遗传算法的C++实现
2016-04-21 16:41
603 查看
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">遗传算法(Genetic Algorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。遗传算法是从代表问题可能潜在的解集的一个种群(population)开始的,而一个种群则由经过基因(gene)编码的一定数目的个体(individual)组成。每个个体实际上是染色体(chromosome)带有特征的实体。染色体作为遗传物质的主要载体,即多个基因的集合,其内部表现(即基因型)是某种基因组合,它决定了个体的形状的外部表现,如黑头发的特征是由染色体中控制这一特征的某种基因组合决定的。因此,在一开始需要实现从表现型到基因型的映射即编码工作。由于仿照基因编码的工作很复杂,我们往往进行简化,如二进制编码,初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代(generation)演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度(fitness)大小选择(selection)个体,并借助于自然遗传学的遗传算子(genetic operators)进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码(decoding),可以作为问题近似最优解. </span>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">本样例是求取函数:y=21.5+x1*sin(sπ*x1)+x2*sin(20π*x2)的最大值,x1~[-3~12.1],x2~[4.1,5.8] </span>
// Genetic Algorithms.cpp : 定义控制台应用程序的入口点。 #include "stdafx.h" #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <time.h> #include <math.h> #include <iostream> #include <iomanip> using namespace std; #define PI 3.1415926 typedef struct Chrom // 结构体类型,为单个染色体的结构; { short int bit[39]; //39位二进制用来表示x1,x2 //题中X1染色体取值范围-300000~1210000 总共1510000种可能,x1包含21位二进制数 //X2染色体有170000中可能性,X2包含18个二进制位 double x1; double x2; double fit ; //适应度 double rfit; //相对的fit值,即所占的百分比 double cfit; //积累概率 }chrom; //定义将会用到的几个函数; void *evpop (chrom popcurrent[1000]); //初始化种群为1000条染色体 void trans (chrom &pop); //二进制向十进制转换的函数 double y (chrom pop); //求y适应度的检测函数 void *pickchroms (chrom popcurrent[1000]); //排序操作,挑选出最好的结果放在第一位, //最坏的结果放在最后 void *pickchroms_cro (chrom popcurrent[1000]); //基于概率分布时候的选择,计算累计概率 void *crossover (chrom popnext[1000]); //交叉操作 void *mutation (chrom popnext[1000]); //编译操作 chrom popcurrent[1000]; //初始种群规模为1000条 chrom popnext[1000]; //子代规模 chrom best; //保存亲代适应度最好的染色体,为替换做准备 void main () // 主函数; { int num ; // 设置的迭代次数 int i=0; int j, k,n; double Max=0.0; //最大的适应度值 int MaxGene=0; //保存最好的适应度产生时候的代数 cout<<" Welcome to the Genetic Algorithm!\n"<<endl; // cout<<"The Algorithm is based on the function" "y = 21.5+x1*sin(4πx1)+x2*sin(20πx2)\n to find the maximum value of the function."<<endl; enter:cout<<"\nPlease enter the no. of iterations\n请输入您要设定的迭代数 : "; cin>>num; // 输入迭代次数,传送给参数 num; if(num <1) goto enter; // 判断输入的迭代次数是否为负或零,是的话重新输入; //不同的随机数可能结果不同,当所设置的迭代次数过少时, //染色体的基因型过早地陷入局部最优 srand((unsigned)time(NULL)); //srand(time(NULL)),可以为rand函数提供不同的种子值, //进而产生不同的随机数序列 evpop(popcurrent); // 随机产生初始种群; pickchroms(popcurrent); //对初始种群排序 Max = popcurrent[0].fit; //对Max值进行初始化 for(;i<num;i ++) // 开始迭代; { printf("\ni = %d\n" ,i); // 输出当前迭代次数; for(j =0;j<1000; j++) { popnext[j]=popcurrent[j]; // 更新种群; } best=popcurrent[0]; //把最好的值保存起来 pickchroms_cro(popnext); for(j =0;j<1000; j++) { popnext[j]=popcurrent[j]; // 种群更替; } crossover(popnext); // 交叉得到新个体; mutation(popnext); // 变异得到新个体; pickchroms(popnext); //新种群进行排序 popnext[999]=best; //用父代适应度最好的染色体替换子代最差的染色体 pickchroms(popnext); //重新进行排序 if (popnext[0].fit>Max) //如果子代最优值大于父代的值 {Max=popnext[0].fit; MaxGene=i; } //保存最优值出现的代数 for(j =0;j<1000; j++) { popcurrent[j]=popnext[j]; // 种群更替; } } // 等待迭代终止; pickchroms(popcurrent); //最后一次排序 cout<<"选择的结果是:"<<endl; //输出结果 for(n =999;n>=0;n--) {cout<<"popcurrent["<<n<<"]="; for(k=0;k<39;k++) {cout<<popcurrent .bit[k];} cout<<endl; cout<<" x1="<<setprecision(20)<<popcurrent .x1<<" x2="<<popcurrent .x2<<" fitness="<<popcurrent .fit<<endl; } cout<<"\n本算法种群数量为1000条,"<<"迭代次数为 "<<num<<" 次。"; cout<<"\n当x1= "<<setprecision(20)<<popcurrent[0].x1<<" "<<"x2= "<<popcurrent[0].x2<<"时,"; cout<<"\n函数得到最大值为:"<<setprecision(20)<<popcurrent[0].fit; cout<<"\n最大值发生在第 " <<MaxGene<<"代。"; cout<<"\n精确到小数点后面五位:x1= "<<setprecision(7)<<popcurrent[0].x1<<" "; cout<<setprecision(6)<<"x2= "<<popcurrent[0].x2<<""; flushall(); // 清除所有缓冲区; getche(); // 从控制台取字符,不以回车为结束; } void *evpop (chrom popcurrent[1000]) // 函数:随机生成1000条初始种群; { int i,j,k; int random; double sum=0.0; //总的适应度计算 for(i =0;i<1000; i++) // 从种群中的第1个染色体到第1000个染色体 { for(j =0;j<39; j++) // 从染色体的第1个基因位到第39个基因位 { // 产生一个随机值 random=(rand()%2); // 随机产生0或者1 popcurrent[i].bit[j]=random; // 随机产生染色体上每一个基因位的值 } trans(popcurrent[i]); // 将二进制换算为十进制,得到2个整数值; popcurrent[i].fit= y(popcurrent[i]); // 计算染色体的适应度值 sum = sum + popcurrent[i].fit; cout<<"popcurrent["<<i<<"]="; // 输出整条染色体的编码情况, for(k=0;k<39;k++) {cout<<popcurrent[i].bit[k];} cout<<endl; cout<<" x1="<<setprecision(20)<<popcurrent[i].x1<<" x2="<<popcurrent[i].x2<<" fitness="<<popcurrent[i].fit<<endl; } return(0); } void trans (chrom &pop) // 函数:将二进制换算为十进制; { int i; double dec1=0.0,dec2=0.0; for(i=0;i<18;i++) //低18位是x2 { if(pop.bit[i]==1) dec2+=pow(2,i); } for(i=18;i<39;i++) { if(pop.bit[i]==1) dec1+=pow(2,i-18); } pop.x1=-3.0+(dec1*15.1)/(pow(2,21)-1); pop.x2=4.1+(dec2*1.7)/(pow(2,18)-1); } double y (chrom popcurrent) // 函数:求个体的适应度; { double fx ; fx=21.5+popcurrent.x1*sin(4*PI*popcurrent.x1) +popcurrent.x2*sin(20*PI*popcurrent.x2); // 目标函数:y= 21.5+x1*sin(4πx1)+x2*sin(20πx2) return(fx); } //基于轮盘赌选择方法,进行基因型的选择 void *pickchroms_cro(chrom pop[1000])//计算概率 { int men; int i; int j; double p; double sum=0.0; //计算种群总适应度 for (men = 0; men < 1000; men++ ) { sum = sum + pop[men].fit; } //计算适应度概率 for (men = 0; men < 1000; men++ ) { pop[men].rfit = pop[men].fit / sum; } //计算积累概率 pop[0].cfit = pop[0].rfit; for ( men = 1; men < 1000; men++) { pop[men].cfit = pop[men-1].cfit + pop[men].rfit; } //开始根据累计概率产生下一代要交叉的染色体 for ( i = 0; i < 1000; i++ ) { p =rand()%10000; p = p/10000; //产生0~1之间的随机数 if ( p < pop[0].cfit ) { popcurrent[i] = pop[0]; cout<<"i="<<i; } else { for ( j = 0; j < 999; j++ ) { if ( pop[j].cfit <= p && p < pop[j+1].cfit ) { popcurrent[i] = pop[j+1]; } } } } cout<<endl; return(0); } void *pickchroms(chrom pop[1000]) // 函数:选择个体; { int i ,j; chrom temp ; // 中间变量 for(i =0;i<999; i++) // 根据个体适应度来排序;(冒泡法) { for(j =0;j<999-i; j++) { if(pop[j+1]. fit>pop[j]. fit) { temp=pop[j+1]; pop[j +1]=pop[ j]; pop[j ]=temp; } } } flushall();/* 清除所有缓冲区 */ return(0); } void *crossover(chrom pop[1000]) // 函数:交叉操作; { int random; int i,j,k,m,n,p; chrom temp; // 中间变量; random=(rand()%10); if (random!=1) { for(k=0;k<500;k++) //开始交叉 { p=(rand()%38); // 交叉点控制在0到38之间; rest:m=(rand()%1000),n=(rand()%1000); if(m==n) goto rest; for(i=p;i<39;i++) { temp.bit[i] = pop[m].bit[i]; // child 1 cross over pop[m].bit[i] = pop .bit[i]; pop .bit[i] = temp.bit[i]; } } for(j=0;j<1000;j++) { trans(pop[j]); pop[j].fit= y(pop[j]); // 为新个体计算适应度值; } } return(0); } void *mutation (chrom popnext[1000]) // 函数:变异操作; { int random ; int i,j; srand((unsigned)time(0)); random=rand()%50; // 随机产生0到50之间的数; if(random ==25) // random==25的概率只有2%,即变异率为,所以是以小概率进行变异!! { j=rand()%39; // 随机产生要变异的基因位号; i=rand()%1000; // 随机产生要变异的染色体号; if(popnext [i].bit[j]==0) // 1变为; { popnext[i].bit[j]=1 ; } else if (popnext[i].bit[j]==1) // 0变为; { popnext[i].bit[j]=0; } popnext[i].fit= y(popnext[i]); trans(popnext[i]); } return(0); }
相关文章推荐
- c++11 auto
- c++ lambda表达式
- C++ 类的“三法则”
- 如何理解虚表及其计算含虚函数的类的大小
- C++ 基础杂项
- 【c语言】输出杨辉三角
- C++匿名对象
- c语言之关键字
- 理解C语言的数组和指针
- 理解C语言的数组和指针
- C++之输入(cin)详解
- 【积累】C/C++中明明该用函数实现的功能,为啥非要自己写代码!
- C++中赋值函数和拷贝构造函数(举例说明)
- leetcode笔记:Merge Two Sorted Lists
- 100条经典C语言笔试题目(上)
- Codeblocks c++11 std::thread问题
- c语言之数组
- c++ map 记录。为了自己记录理解
- 魔方阵原理及十种解法(C语言)
- C++ 与 JAVA调用问题