zoukankan      html  css  js  c++  java
  • C# 遗传算法入门学习

      此文仅用于记录自己的遗传算法的学习过程,对代码做了微微的改动,加了点注释,可能存在错误。
    参考:https://blog.csdn.net/kyq0417/article/details/84345094

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace GA
    {
        class Program
        {
    
            #region 全局变量
            /// <summary>
            /// 染色体信息
            /// </summary>
            private class Chromosome
            {
                /// <summary>
                /// 用6bit对染色体进行编码,第1个元素表示正负,2-5以此存储二进制的的信息,最大表示31
                /// </summary>
                public int[] bits = new int[6];
    
                /// <summary>
                /// 适应值
                /// </summary>
                public int fitValue;
    
                /// <summary>
                /// 选择概率
                /// </summary>
                public double fitValuePercent;
    
                /// <summary>
                /// 累积概率
                /// </summary>
                public double totalProbability;
    
                public Chromosome Clone()//染色体赋值,复制
                {
                    Chromosome c = new Chromosome();
                    for (int i = 0; i < bits.Length; i++)//逐个染色体赋值
                    {
                        c.bits[i] = bits[i];
                    }
                    c.fitValue = fitValue;
                    c.fitValuePercent = fitValuePercent;
                    c.totalProbability = totalProbability;
                    return c;
                }
            }
    
            /// <summary>
            /// 变异几率
            /// </summary>
            public  static  double varProbability = 0.02;
    
            /// <summary>
            /// 染色体组;
            /// </summary>
            private static List<Chromosome> chromosomes = new List<Chromosome>();           //父代
    
            private static List<Chromosome> chromosomesChild = new List<Chromosome>();      //子代
    
            private static Random random = new Random();
    
            /// <summary>
            /// 选择类型
            /// </summary>
            private enum ChooseType
            {
                Bubble,//冒泡;
                Roulette,//轮盘赌;
            }
    
            private static ChooseType chooseType = ChooseType.Roulette;     //选择赌轮盘的方法
            #endregion
    
            /// <summary>
            /// Main入口函数;
            /// </summary>
            /// <param name="args"></param>
            private static void Main(string[] args)
            {
                Console.WriteLine("遗传算法");
                Console.WriteLine("求函数最大值函数为y = x*x-31x的最大值,-31<=x<=31");
    
                int totalTime = 30;                    // 迭代次数,根据结果调整
                Console.WriteLine("迭代次数为: " + totalTime);
                Console.WriteLine("初始化: ");          //初始化;
    
                Init();          // 输出初始化数据;          
                Print();
    
                for (int i = 0; i < totalTime; i++)
                {
                    Console.WriteLine("当前迭代次数: " + i);
    
                    //重新计算fit值;;
                    UpdateFitValue();
    
                    // 挑选染色体;
                    Console.WriteLine("挑选:");
    
                    switch (chooseType)
                    {
                        case ChooseType.Bubble:
                            // 排序;
                            Console.WriteLine("排序:");
                            ChooseChromosome();
                            break;
                        default:
                            //轮盘赌;
                            Console.WriteLine("轮盘赌:");
                            UpdateNext();
                            break;
                    }
                    Print(true);
    
                    //交叉得到新个体
                    Console.WriteLine("交叉:");
                    CrossOperate();
                    Print();
    
                    //变异
                    Console.WriteLine("变异:");
                    VariationOperate();
                    Print();
                }
    
                //挑选出最大适应值
                int maxFit = chromosomes[0].fitValue;
                for (int i = 1; i < chromosomes.Count; i++)
                {
                    if (chromosomes[i].fitValue > maxFit)
                    {
                        maxFit = chromosomes[i].fitValue;
                    }
                }
                Console.WriteLine("最大值为: " + maxFit);
                Console.ReadKey();
            }
    
            #region 打印输出
            /// <summary>
            /// 打印;
            /// </summary>
            private static void Print(bool bLoadPercent = false)
            {
                Console.WriteLine("=========================");
                for (int i = 0; i < chromosomes.Count; i++)
                {
                    Console.Write("" + i + "" + " 基因: ");
                    for (int j = 0; j < chromosomes[i].bits.Length; j++)
                    {
                        Console.Write(" " + chromosomes[i].bits[j]);
                    }
                    int x = DeCode(chromosomes[i].bits);
                    Console.Write(" x: " + x);
                    Console.Write(" y: " + chromosomes[i].fitValue);
                    if (bLoadPercent)
                    {
                        Console.Write(" 选择概率: " + chromosomes[i].fitValuePercent);
                    }
                    Console.WriteLine();
                }
                Console.WriteLine("=========================");
            }
            #endregion
    
            #region 初始化
            /// <summary>
            /// 初始化
            /// </summary>
            private static void Init()
            {
                chromosomes.Clear();
                int length = 30;        // 染色体数量
                int totalFit = 0;
    
                for (int i = 0; i < length; i++)
                {
                    Chromosome chromosome = new Chromosome();
                    for (int j = 0; j < chromosome.bits.Length; j++)
                    {
                        // 随机出0或者1;
                        int bitValue = random.Next(0, 2);
                        chromosome.bits[j] = bitValue;
                    }
                    //获得十进制的值;
                    int x = DeCode(chromosome.bits);
                    int y = GetFitValue(x);
                    chromosome.fitValue = y;
                    chromosomes.Add(chromosome);
                    //算出total fit;
                    if (chromosome.fitValue <= 0)
                    {
                        totalFit += 0;
                    }
                    else
                    {
                        totalFit += chromosome.fitValue;
                    }
                }
            }
            #endregion
    
            #region 解码,二进制装换
            /// <summary>
            /// 解码,二进制装换;
            /// </summary>
            /// <param name="bits"></param>
            /// <returns></returns>
            private static int DeCode(int[] bits)
            {
                int result = bits[1] * 16 + bits[2] * 8 + bits[3] * 4 + bits[4] * 2 + bits[5] * 1;//第一个元素判断正负,后5个元素二进制转换十进制,所能表达的最大十进制数值为31
                //通过第一个元素判断正负;
                if (bits[0] == 0)
                {
                    return result;
                }
                else
                {
                    return -result;
                }
            }
            #endregion
    
            #region 获取fitValue(适应度)
            /// <summary>
            /// 获取fitValue,返回值越大说明适应度越高
            /// </summary>
            /// <param name="x"></param>
            /// <returns></returns>
            private static int GetFitValue(int x)
            {
                return x * x - 31 * x;//目标函数 y= x*x -31*x
            }
            #endregion
    
            #region 选择
            /// <summary>
            /// 更新下一代;
            /// 基于轮盘赌选择方法,进行基因型的选择;
            /// </summary>
            private static void UpdateNext()
            {
                // 获取总的fit;
                double totalFitValue = 0;
                for (int i = 0; i < chromosomes.Count; i++)
                {
                    //适应度为负数的取0(前提知道函数的最大值一定大于0)
                    if (chromosomes[i].fitValue <= 0)
                    {
                        totalFitValue += 0;
                    }
                    else
                    {
                        totalFitValue += chromosomes[i].fitValue;
                    }
                }
                Console.WriteLine("累计适应度(totalFitValue) :" + totalFitValue);
    
                //算出每个的fit percent;
                for (int i = 0; i < chromosomes.Count; i++)
                {
                    if (chromosomes[i].fitValue <= 0)   //杀掉适应度为负的基因
                    {
                        chromosomes[i].fitValuePercent = 0;
                    }
                    else
                    {
                        chromosomes[i].fitValuePercent = chromosomes[i].fitValue / totalFitValue;//计算第i个基因的适应值(第i个基于的适应值/累计适应值)
                    }
                    Console.WriteLine("" + i + " 个体选择概率(fitValuePercent):" + chromosomes[i].fitValuePercent);
                }
    
                ////计算累积概率
                //// 第一个的累计概率就是自己的概率,循环完后,便可得到累计概率的值,便于后续的赌轮盘算法
                chromosomes[0].totalProbability = chromosomes[0].fitValuePercent;
                double probability = chromosomes[0].totalProbability;
                for (int i = 1; i < chromosomes.Count; i++)
                {
                    if (chromosomes[i].fitValuePercent != 0)        //只对出现概率概率不为0的染色体进行操作
                    {
                        chromosomes[i].totalProbability = chromosomes[i].fitValuePercent + probability;
                        probability = chromosomes[i].totalProbability;
                    }
                }
    
                chromosomesChild.Clear();
                //轮盘赌选择方法,用于选出前两个;
                for (int i = 0; i < chromosomes.Count; i++)
                {
                    double chooseNum = random.NextDouble();     //生成0.0-1.0之间的随机数,用于选择
                    Console.WriteLine("挑选的数值:" + chooseNum);
                    //判断挑选的数值落在区间位置,从而确定选择的染色体
                    if (chooseNum < chromosomes[0].totalProbability)
                    {
                        chromosomesChild.Add(chromosomes[0].Clone());
                    }
                    else
                    {
                        for (int j = 0; j < chromosomes.Count - 1; j++) //-1是因为去除了第1个染色体
                        {
                            if (chromosomes[j].totalProbability <= chooseNum && chooseNum <= chromosomes[j + 1].totalProbability)   //判断区间
                            {
                                chromosomesChild.Add(chromosomes[j + 1].Clone());   //j是从0开始的,
                            }
                        }
                    }
                }
                for (int i = 0; i < chromosomes.Count; i++)
                {
                    chromosomes[i] = chromosomesChild[i];   //子代变父代,便于进入下一次循环
                }
            }
    
            /// <summary>
            /// 选择染色体;
            /// </summary>
            private static void ChooseChromosome()
            {
                // 从大到小排序;
                chromosomes.Sort((a, b) => { return b.fitValue.CompareTo(a.fitValue); });
            }
            #endregion
    
            #region 交叉
            /// <summary>
            /// 交叉操作
            /// </summary>
            private static void CrossOperate()
            {
                //选择交叉位置
                int bitNum = chromosomes[0].bits.Length;    //获取染色体位数
                int a = random.Next(0, bitNum );            //生成0-染色体位数-1之间的随机数,
                int b = random.Next(0, bitNum );
                if (a > b)      //交换,排序
                {
                    int temp = a;
                    a = b;
                    b = temp;
                }
                Console.WriteLine("交叉范围:" + a + "" + b);
    
                //交叉位置处进行交叉操作(第1条和第2条进行交叉,两两一对,以此类推,染色体个数优先选择偶数个)
                for (int j = 0; j < chromosomes.Count; j = j + 2)
                {
                    for (int i = a; i <= b; i++)        //从第一个随机数开始交叉 到第二个随机数结束
                    {
                        int temp = chromosomes[j].bits[i];
                        chromosomes[j].bits[i] = chromosomes[j + 1].bits[i];
                        chromosomes[j + 1].bits[i] = temp;
                    }
    
                    //对交叉后生成的两条新染色体(二进制转码十进制)重新计算适应值
                    chromosomes[j].fitValue = GetFitValue(DeCode(chromosomes[j].bits)); 
                    chromosomes[j + 1].fitValue = GetFitValue(DeCode(chromosomes[j + 1].bits));
                }
            }
            #endregion
    
            #region 变异
            /// <summary>
            /// 变异操作
            /// </summary>
            private static void VariationOperate()
            {
                int chromoNum = chromosomes.Count;                      //染色体数量
                int geneNum = chromosomes[0].bits.Length - 1;           //单个染色体基因数-1,去除用于判断正负的一个基因
                int varSite = random.Next(1, chromoNum * geneNum + 1);  //在所有的基因数范围中选择一个随机数
                if (varSite <= chromoNum *geneNum *varProbability)       //通过判断随机数是否小于等于 基因总数*变异概率 ,判断是否发生突变     //每条染色体有5个决定基因(排除第一个决定正负的基因)
                {
                    Console.WriteLine("开始变异");
    
                    int row = random.Next(0, chromoNum );         //确定要突变的染色体编号
                    int col = random.Next(0, geneNum );           //确定要突变的基因
                    Console.WriteLine("变异的位置 :第" + row + "条染色体的第" + col + "个基因");
                    //0变1,1变0
                    if (chromosomes[row].bits[col] == 0)
                    {
                        chromosomes[row].bits[col] = 1;
                    }
                    else
                    {
                        chromosomes[row].bits[col] = 0;
                    }
                    chromosomes[row].fitValue = GetFitValue(DeCode(chromosomes[row].bits));
                }
            }
            #endregion
    
            #region 重新计算fit值
            /// <summary>
            /// 重新计算fit值;
            /// </summary>
            private static void UpdateFitValue()
            {
                for (int i = 0; i < chromosomes.Count; i++)
                {
                    chromosomes[i].fitValue = GetFitValue(DeCode(chromosomes[i].bits));
                }
            }
            #endregion
        }
    }
  • 相关阅读:
    两步验证杀手锏:Java 接入 Google 身份验证器实战
    涨姿势:Spring Boot 2.x 启动全过程源码分析
    Spring Cloud 升级最新 Finchley 版本,踩了所有的坑!
    Spring Boot 2.x 启动全过程源码分析(上)入口类剖析
    推荐:7 月份值得一看的 Java 技术干货!
    屌炸天,Oracle 发布了一个全栈虚拟机 GraalVM,支持 Python!
    Spring Boot 核心配置文件 bootstrap & application 详解。
    出场率比较高的一道多线程安全面试题
    凉凉了,Eureka 2.x 停止维护,Spring Cloud 何去何从?
    读写Excel
  • 原文地址:https://www.cnblogs.com/jiang2020/p/12584425.html
Copyright © 2011-2022 走看看