首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 實作遺傳演算法:完整架構與核心類別設計 (Population、Individual、IGeneticStrategy、IFitness)

     編輯:關於C#

前言

遺傳演算法 是一種啟發式最佳化演算法,模擬達爾文自然選擇與孟德爾遺傳定律,透過**選擇**、**交叉**、**突變** 迭代演化,在龐大搜尋空間中尋找近似最優解。適用於:函數最佳化、排程問題、路徑規劃、參數調參、神經網路架構搜尋等傳統演算法難以處理的 NP-Hard 問題。本文提供一個 **C# 完整物件導向實作架構**,包含:

  • Individual:個體 (染色體、基因、適應度、編碼/解碼、交叉、突變運算子多載)
  • Population:族群 (初始化、適應度統計、選擇/交叉/突變委派策略、ICloneable/IDisposable)
  • IGeneticStrategy:演化策略介面 (選擇、交叉、突變)
  • IFitness:適應度計算介面 (可換裝不同問題域)
  • Coder:編碼/解碼工具 (二進位字串 ↔ 實數)

核心介面定義

using System;
using System.Collections.Generic;

namespace GeneticAlgorithm.Core
{
    /// 
    /// 適應度計算策略介面:針對特定問題域實作
    /// 
    public interface IFitness
    {
        /// 
        /// 計算適應度
        /// 
        /// 表現型數值 (解碼後的實數)
        /// 適應度值 (越大越好)
        double Calculate(double phenotype);
    }

    /// 
    /// 演化策略介面:封裝選擇、交叉、突變演算法
    /// 
    public interface IGeneticStrategy
    {
        /// 
        /// 選擇操作:根據適應度挑選下一代族群
        /// 
        Population Select(Population population);

        /// 
        /// 交叉操作:配對個體交換基因片段
        /// 
        void Crossover(Population population);

        /// 
        /// 突變操作:隨機翻轉基因位
        /// 
        void Mutation(Population population);
    }
}

編碼/解碼工具類:Coder

namespace GeneticAlgorithm.Core
{
    /// 
    /// 二進位字串與實數雙向轉換 (固定長度、定義域映射)
    /// 
    public static class Coder
    {
        /// 
        /// 實數 → 二進位字串 (固定長度)
        /// 
        public static string ToBinary(double value, double min, double max, int geneLength)
        {
            double normalized = (value - min) / (max - min); // 0.0 ~ 1.0
            normalized = Math.Max(0, Math.Min(1, normalized)); // 夾擠
            int intVal = (int)(normalized * ((1 << geneLength) - 1));
            return Convert.ToString(intVal, 2).PadLeft(geneLength, '0');
        }

        /// 
        /// 二進位字串 → 實數 (映射回定義域)
        /// 
        public static double ToReal(string binary, double min, double max)
        {
            int intVal = Convert.ToInt32(binary, 2);
            int maxInt = (1 << binary.Length) - 1;
            double normalized = (double)intVal / maxInt;
            return min + normalized * (max - min);
        }
    }
}

個體類別:Individual

using System;
using System.Text;

namespace GeneticAlgorithm.Core
{
    /// 
    /// 個體:基因型 (二進位字串)、表現型 (實數)、適應度
    /// 
    public class Individual : ICloneable
    {
        private string _gene;           // 基因型:二進位字串 (如 "101011...")
        private double _fitness;        // 適應度快取
        private static IFitness _fitnessCalculator = new DefaultFitness(); // 預設適應度計算器

        /// 
        /// 靜態屬性:設定全域適應度計算策略
        /// 
        public static IFitness FitnessCalculator
        {
            get => _fitnessCalculator;
            set => _fitnessCalculator = value ?? new DefaultFitness();
        }

        /// 
        /// 基因型 (唯讀)
        /// 
        public string Gene => _gene;

        /// 
        /// 適應度 (唯讀,懶惰計算)
        /// 
        public double Fitness
        {
            get
            {
                if (double.IsNaN(_fitness))
                    _fitness = _fitnessCalculator.Calculate(Variable);
                return _fitness;
            }
        }

        /// 
        /// 表現型:解碼後的實數值 (對應問題域變數)
        /// 
        public double Variable => Coder.ToReal(_gene, -1.0, 2.0); // 定義域 [-1, 2]

        /// 
        /// 建構函式:指定基因字串
        /// 
        public Individual(string gene)
        {
            _gene = gene ?? throw new ArgumentNullException(nameof(gene));
            _fitness = double.NaN; // 標記未計算
        }

        /// 
        /// 建構函式:指定基因與自訂適應度計算器
        /// 
        public Individual(string gene, IFitness fitnessCalculator)
        {
            _gene = gene ?? throw new ArgumentNullException(nameof(gene));
            _fitnessCalculator = fitnessCalculator ?? new DefaultFitness();
            _fitness = double.NaN;
        }

        /// 
        /// 隨機產生個體 (指定基因長度)
        /// 
        public static Individual CreateRandom(int geneLength = 22)
        {
            var rd = new Random();
            var sb = new StringBuilder(geneLength);
            for (int i = 0; i < geneLength; i++)
                sb.Append(rd.Next(0, 2));
            return new Individual(sb.ToString());
        }

        #region 交叉運算子多載 (*)

        /// 
        /// 單點/兩點交叉:隨機選取交叉區間,交換基因片段
        /// 
        public static int operator *(Individual ind1, Individual ind2)
        {
            if (ind1._gene.Length != ind2._gene.Length)
                throw new ArgumentException("基因長度必須相同");

            var rd = new Random();
            int len = ind1._gene.Length;

            // 隨機選取起始與結束位置 (確保區間非空)
            int start = rd.Next(0, len - 1);
            int end = rd.Next(start + 1, len);

            // 若該區段基因相同,重新選取 (避免無效交叉)
            while (ind1._gene.Substring(start, end - start) == ind2._gene.Substring(start, end - start))
            {
                start = rd.Next(0, len - 1);
                end = rd.Next(start + 1, len);
            }

            // 建構新基因
            var sb1 = new StringBuilder(ind1._gene);
            var sb2 = new StringBuilder(ind2._gene);

            for (int i = start; i < end; i++)
            {
                char temp = sb1[i];
                sb1[i] = sb2[i];
                sb2[i] = temp;
            }

            ind1._gene = sb1.ToString();
            ind2._gene = sb2.ToString();
            ind1._fitness = double.NaN; // 使適應度失效,下次重新計算
            ind2._fitness = double.NaN;

            return end - start; // 回傳交叉片段長度
        }

        /// 
        /// 實例方法版交叉
        /// 
        public int Crossover(Individual other) => this * other;

        #endregion

        #region 突變

        /// 
        /// 單點突變:隨機翻轉一個基因位 (0↔1)
        /// 
        public int Mutation()
        {
            var rd = new Random();
            int pos = rd.Next(0, _gene.Length);
            var sb = new StringBuilder(_gene);
            sb[pos] = sb[pos] == '0' ? '1' : '0';
            _gene = sb.ToString();
            _fitness = double.NaN;
            return pos;
        }

        #endregion

        #region 輔助方法

        /// 
        /// 基因字串轉十進位整數 (除錯用)
        /// 
        public int ToMetrication() => Convert.ToInt32(_gene, 2);

        public override string ToString() => _gene;

        public override bool Equals(object obj) => obj is Individual other && _gene == other._gene;

        public override int GetHashCode() => _gene.GetHashCode();

        public object Clone() => new Individual(_gene);

        #endregion
    }

    /// 
    /// 預設適應度函數:f(x) = x * sin(10πx) + 2.0 (單峰/多峰測試函數)
    /// 
    public class DefaultFitness : IFitness
    {
        public double Calculate(double x)
        {
            return x * Math.Sin(10 * Math.PI * x) + 2.0;
        }
    }
}

族群類別:Population

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace GeneticAlgorithm.Core
{
    /// 
    /// 族群:個體集合、適應度統計、演化操作委派
    /// 
    public class Population : CollectionBase, ICloneable, IDisposable
    {
        private IGeneticStrategy _strategy;

        public Population() { }

        public Population(IGeneticStrategy strategy)
        {
            _strategy = strategy ?? throw new ArgumentNullException(nameof(strategy));
        }

        /// 
        /// 演化策略 (可執行期熱插拔)
        /// 
        public IGeneticStrategy Strategy
        {
            get => _strategy;
            set => _strategy = value ?? throw new ArgumentNullException(nameof(value));
        }

        /// 
        /// 索引子存取個體
        /// 
        public Individual this[int index]
        {
            get => (Individual)List[index];
            set => List[index] = value ?? throw new ArgumentNullException(nameof(value));
        }

        /// 
        /// 新增個體
        /// 
        public void Add(Individual ind) => List.Add(ind ?? throw new ArgumentNullException(nameof(ind)));

        /// 
        /// 初始化族群:隨機產生指定數量個體
        /// 
        public void Initialize(int populationSize, int geneLength = 22)
        {
            for (int i = 0; i < populationSize; i++)
                Add(Individual.CreateRandom(geneLength));
        }

        #region 適應度統計屬性

        /// 
        /// 最大適應度
        /// 
        public double MaxFitness
        {
            get
            {
                double max = double.MinValue;
                foreach (Individual ind in List)
                    if (ind.Fitness > max) max = ind.Fitness;
                return max;
            }
        }

        /// 
        /// 平均適應度
        /// 
        public double AverageFitness => SumFitness / Count;

        /// 
        /// 適應度總和
        /// 
        public double SumFitness
        {
            get
            {
                double sum = 0;
                foreach (Individual ind in List)
                    sum += ind.Fitness;
                return sum;
            }
        }

        #endregion

        #region 演化操作 (委派給 Strategy)

        public Population Select() => _strategy?.Select(this);
        public void Crossover() => _strategy?.Crossover(this);
        public void Mutation() => _strategy?.Mutation(this);

        #endregion

        /// 
        /// 列印族群資訊 (除錯用)
        /// 
        public void Print()
        {
            for (int i = 0; i < Count; i++)
            {
                var ind = (Individual)List[i];
                Console.WriteLine($"個體[{i:D3}] 基因={ind.Gene} 表現型={ind.Variable:F6} 適應度={ind.Fitness:F6}");
            }
        }

        #region ICloneable / IDisposable

        public object Clone()
        {
            var clone = new Population(_strategy);
            foreach (Individual ind in List)
                clone.List.Add(ind.Clone());
            return clone;
        }

        public void Dispose()
        {
            _strategy = null;
            List.Clear();
        }

        #endregion
    }
}

具體演化策略實作範例:SimpleGeneticStrategy

using System;
using System.Collections.Generic;
using System.Linq;

namespace GeneticAlgorithm.Core
{
    /// 
    /// 簡單演化策略:輪盤選擇 + 單點交叉 + 單點突變
    /// 
    public class SimpleGeneticStrategy : IGeneticStrategy
    {
        private readonly Random _rd = new Random();
        private readonly double _crossoverRate = 0.8;
        private readonly double _mutationRate = 0.05;

        public SimpleGeneticStrategy(double crossoverRate = 0.8, double mutationRate = 0.05)
        {
            _crossoverRate = crossoverRate;
            _mutationRate = mutationRate;
        }

        /// 
        /// 輪盤選擇:適應度比例選擇
        /// 
        public Population Select(Population population)
        {
            var newPop = new Population(this);
            double totalFitness = population.SumFitness;
            if (totalFitness <= 0) return population.Clone() as Population; // 避免除零

            for (int i = 0; i < population.Count; i++)
            {
                double pick = _rd.NextDouble() * totalFitness;
                double accumulated = 0;
                foreach (Individual ind in population.List)
                {
                    accumulated += ind.Fitness;
                    if (accumulated >= pick)
                    {
                        newPop.Add((Individual)ind.Clone());
                        break;
                    }
                }
            }
            return newPop;
        }

        /// 
        /// 隨機配對交叉
        /// 
        public void Crossover(Population population)
        {
            var individuals = new List();
            foreach (Individual ind in population.List)
                individuals.Add(ind);

            // 隨機打亂配對順序
            for (int i = individuals.Count - 1; i > 0; i--)
            {
                int j = _rd.Next(i + 1);
                var temp = individuals[i];
                individuals[i] = individuals[j];
                individuals[j] = temp;
            }

            // 成對交叉
            for (int i = 0; i < individuals.Count - 1; i += 2)
            {
                if (_rd.NextDouble() < _crossoverRate)
                    individuals[i] * individuals[i + 1]; // 使用運算子多載
            }

            // 更新族群
            population.List.Clear();
            foreach (var ind in individuals)
                population.List.Add(ind);
        }

        /// 
        /// 隨機突變
        /// 
        public void Mutation(Population population)
        {
            foreach (Individual ind in population.List)
            {
                if (_rd.NextDouble() < _mutationRate)
                    ind.Mutation();
            }
        }
    }
}

主程式:執行遺傳演算法尋找函數最大值

using System;
using GeneticAlgorithm.Core;

namespace GeneticAlgorithm.Demo
{
    class Program
    {
        static void Main()
        {
            Console.WriteLine("=== C# 遺傳演算法示範:尋找 f(x)=x*sin(10πx)+2 在 [-1,2] 最大值 ===");

            // 1. 建立族群與策略
            var strategy = new SimpleGeneticStrategy(crossoverRate: 0.8, mutationRate: 0.05);
            var population = new Population(strategy);
            population.Initialize(populationSize: 100, geneLength: 22);

            // 2. 迭代演化
            const int MAX_GENERATIONS = 200;
            for (int gen = 0; gen < MAX_GENERATIONS; gen++)
            {
                // 選擇 → 交叉 → 突變
                var selected = population.Select();
                selected.Crossover();
                selected.Mutation();

                // 精英保留:保留前代最佳個體
                var bestPrev = population[0];
                for (int i = 1; i < population.Count; i++)
                    if (population[i].Fitness > bestPrev.Fitness) bestPrev = population[i];

                selected[0] = (Individual)bestPrev.Clone(); // 取代第一個

                population = selected; // 世代更替

                // 監控輸出
                if (gen % 20 == 0 || gen == MAX_GENERATIONS - 1)
                {
                    var best = population[0];
                    for (int i = 1; i < population.Count; i++)
                        if (population[i].Fitness > best.Fitness) best = population[i];

                    Console.WriteLine($"第 {gen:D3} 代 | 最大適應度={best.Fitness:F6} | 平均={population.AverageFitness:F6} | 最佳x={best.Variable:F6}");
                }
            }

            // 3. 輸出最終結果
            var finalBest = population[0];
            for (int i = 1; i < population.Count; i++)
                if (population[i].Fitness > finalBest.Fitness) finalBest = population[i];

            Console.WriteLine("\n=== 最終結果 ===");
            Console.WriteLine($"最佳解 x = {finalBest.Variable:F6}");
            Console.WriteLine($"最大值 f(x) = {finalBest.Fitness:F6}");
            Console.WriteLine($"基因型 = {finalBest.Gene}");

            Console.ReadKey();
        }
    }
}

架構設計亮點總結

擴充方向建議

  • 多目標最佳化:引入 Pareto 前沿、NSGA-II 策略實作 IGeneticStrategy。
  • 實數編碼 GA:Individual 改用 double[] 基因,Coder 移除,交叉用 SBX (Simulated Binary Crossover)、突變用多項式突變。
  • 平行化:適應度計算、交叉、突變均可 Parallel.ForEach 加速。
  • 自適應參數:根據族群多樣性動態調整 crossoverRate、mutationRate。
  • 基因演算法框架整合:封裝為 NuGet 套件,提供 Fluent API 設定流程。

總結

本文提供了一個**結構清晰、可擴充、符合 SOLID 原則**的 C# 遺傳演算法實作架構。核心在於:Individual 封裝基因型/表現型/適應度與交叉突變運算子、Population 管理族群生命週期與統計、IGeneticStrategy/IFitness 介面隔離演化邏輯與問題域、Coder 解耦編碼轉換。此架構不僅適合教學示範,更可作為實務專案中超參數調參、排程最佳化、函數搜尋等任務的起始框架。掌握「策略模式隔離演算法、運算子多載表達領域邏輯、懶惰計算提升效能」三大設計精髓,即可輕鬆擴充至更複雜的演化計算場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
設計模式應用位置效益
StrategyIGeneticStrategy / IFitness演化演算法與適應度函數可熱插拔,支援不同問題域
Operator OverloadingIndividual.operator *交叉操作語法直觀 (ind1 * ind2),符合領域語言
Lazy EvaluationIndividual.Fitness 屬性適應度僅在首次存取時計算,避免重複運算
Prototype (ICloneable)Individual / Population精英保留、族群複製無需序列化,高效能
Static FactoryIndividual.CreateRandom封裝隨機初始化邏輯,統一基因長度
Separation of ConcernsCoder 類別編碼/解碼邏輯與個體/族群解耦,易於擴充 Gray Code、Real-valued GA