c++ 简单的遗传算法实现

简单介绍

由于《自然计算》课程布置了一道关于遗传算法的编程题,所以大概花了四天时间来学习遗传算法的基本概念、程序设计流程、c++编程实现。在学习过程中,也遇到了不少问题,通过自己不断的分析思考,查阅书籍(《c++ primer》解决一些成员函数使用的问题)和结合网上的一些已有程序(a href=”http://blog.csdn.net/ilikeprograming/article/details/25702861”),使得问题一一解决。

算法流程如下:
《c++ 简单的遗传算法实现》

代码块

实现代码如下:
main.cpp

/********************************************************* 
Copyright: zhangchao 
Author: superman
Date: 2016-10-28 
Description: 遗传算法求解最优值
Function: f(x1,x2)=21.5+x1*sin(4*Pi*x1)+x2*sin(20*Pi*x2)
Range: x1[-3,12.1],x2[4.1,5.8]
**********************************************************/ 
#include "geneticAlgorithm.h"

//#define MaxGen 5

int main(int argc,char *argv[])
{       
    multimap<double,double> m_mapData;
    m_mapData.insert(make_pair(-2.687969,5.361653));
    m_mapData.insert(make_pair(0.474101,4.170144));
    m_mapData.insert(make_pair(10.419457,4.661461));
    m_mapData.insert(make_pair(6.159951,4.109598));
    m_mapData.insert(make_pair(-2.301286,4.477282));
    m_mapData.insert(make_pair(11.788084,4.174346));
    m_mapData.insert(make_pair(9.342067,5.121702));
    m_mapData.insert(make_pair(-0.330256,4.694977));
    m_mapData.insert(make_pair(11.671267,4.873501));
    m_mapData.insert(make_pair(11.446273,4.171908));
    srand( unsigned( time(0) ) );//srand(time(NULL)); 产生随机数

    cout<<"----------------------------------------------------------------------------------------------------"<<endl;
    cout<<"\tDescription: The  Genetic Algorithm is used to find the maximum value of the function "<<endl;
    cout<<"\tFunction: f(x1,x2)=21.5+x1*sin(4*Pi*x1)+x2*sin(20*Pi*x2) "<<endl;
    cout<<"\tRange:    x1[-3,12.1],x2[4.1,5.8] "<<endl;
    cout<<"---------------------------------------------------------------------------------------------------- "<<endl;

    vector<double> fitnGloMax;  //存储全局最优eval-fitness
    vector<double> get_x1fitn;
    vector<double> get_x2fitn;

    int MaxGen;
    cout<<"Please input the  number of generations : ";
    cin>>MaxGen;
    int gen=1;
    vector<string> binMutVec;   //定义经变异后生成的二进制序列

    vector<string> binVec;  
    binVec=encoding(m_mapData); //编码,保存为二进制序列,将生成的chromosome(bin) 保存到vector中
    cout<<endl;
    do{
//      cout<<"******************************The "<<gen<<" generation*******************************"<<endl;
        double fitnMax=0.0;
        double x1max=0.0;
        double x2max=0.0;
        vector<double> evalFitness;
        if(gen==1){
            evalFitness=evalFit(decoding(binVec),fitnMax,x1max,x2max);  //计算适应度,通过解码
        }else{
            evalFitness=evalFit(decoding(binMutVec),fitnMax,x1max,x2max);   
        }
        fitnGloMax.push_back(fitnMax);
        get_x1fitn.push_back(x1max);
        get_x2fitn.push_back(x2max);

        vector<string> binSelVec;
        binSelVec=selection(binVec,evalFitness,m_mapData.size());   //选择

        vector<string> binCroVec;
        binCroVec=crossover(binSelVec);

        binMutVec=mutation(binCroVec);

        ++gen;
    }while(gen<=MaxGen);
    auto biggest=max_element(fitnGloMax.begin(),fitnGloMax.end());  //搜索fitnGloMax中的最大值(最优值)的迭代器
    auto sub=biggest-fitnGloMax.begin();    //sub:相对位置
    auto xx1=get_x1fitn.begin()+sub;        //xx1,xx2:对应的x值的迭代器
    auto xx2=get_x2fitn.begin()+sub;
    cout<<"The fitness of best chromosome : "<<*biggest
        <<"\t [x1,x2]="<< " ["<<*xx1<<","<<*xx2<<"]"<<endl;
    int i=0;
    int maxi=0;
    for(auto it=fitnGloMax.begin();it!=fitnGloMax.end();++it){
        if(*biggest==*it){
            maxi=i;
        }
        ++i;
    }
    cout<<"The maximum value of the function : "<< maxi+1<<"th generation"<<endl;
    cout<<endl;

    cout<<"The fitness of all chromosomes(format:generation--fitness) : "<<endl;
    int j=0;
    for(auto it=fitnGloMax.begin();it!=fitnGloMax.end();++it){
        cout<<j+1<<"--"<<*it<<"\t\t";
        ++j;
//      if(i%10==0) cout<<endl;
    }
    cout<<endl;
/***********************************************************************/
/*
//绘图:将fitness的值显示在坐标系中,x轴为代数,y轴为所对应的该代中的最优值
//输出窗口x对应的值的范围有限,大于一定的值就会换行显示,整个格式就乱码了
    gotoxy(1,int(16.5*2+100));
    cout<<"↓";
    gotoxy(2,(17*2+100));
    cout<<"y";
    gotoxy(2,(16*2+100));
    cout<<"o";
    gotoxy(4,(16*2+100));
    cout<<"→";
    gotoxy(7,(16*2+100));
    cout<<"x";
    for(double k=18.0;k<=40.0;){//24.5
        int posY=int(k*2+100);
        if(k==18.0||k==20.0||k==24.5||k==35.5||k==40.0){
            gotoxy(1,posY);
            cout<<setprecision(1)<<std::fixed <<k;
        }
        else{
            gotoxy(1,posY);
            cout<<" |";
        }
        k+=0.5;
    }
    for(double k=25.0;k<=35.0;){
        int posY=int(k*2+100);
        gotoxy(1,posY);
        cout<<setprecision(1)<<std::fixed <<k;
        k+=0.5;
    }
    int xVal=6,yVal=0;
    for(auto it=fitnGloMax.begin();it!=fitnGloMax.end();++it){
        yVal=int(((*it)*2+100));        //y*2=1精度0.5
        gotoxy(xVal++, yVal);       
        if(*biggest==*it){
            cout<<"*";
            gotoxy(xVal-1, yVal+1);     //y*2=1精度0.5
            cout<<setprecision(4)<<std::fixed<<*it;
        }
        else
            cout<<"*";
    }
    getch();*/
    return 0;
}

geneticAlgorithm.h

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <string>
#include <map>
#include <cmath>
#include <iterator>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

#define PI 3.1415926
#define Pc 0.25
#define Pm 0.01

#define X1min -3
#define X1max 12.1 
#define X1sub 15.1

#define X2min 4.1
#define X2max 5.8 
#define X2sub 1.7

void displayInitGen(vector<string> bin);    //displayInitGen 显示每一代的初始群体
double random(double start,double end); //random 产生一个随机数,将返回值范围限定至begin--end之间
vector<string> encoding(multimap<double,double> binMap);    //encoding
string decToBin(long long n,int bits);  //十进制转换为二进制
multimap<double,double> decoding(vector<string> binVec);    //decoding
vector<double> evalFit(multimap<double,double> evalMap,double &fitnMax,double &x1max,double& x2max);    //evalutation
vector<string> selection(vector<string> binVec,vector<double> eval,const int randNum);  //selection
int rouletteWheel(vector<double> qq);  //轮盘赌算法
vector<string> crossover(vector<string> &binSecVec);    //crossover
vector<string> mutation(vector<string> &binCroVec);     //mutation
void mutation(string &bin, int j);  //1(0)取反

以上是所有实现过程调用到的函数,具体的函数后面有时间再分享给大家。
以下对编程过程遇到的问题总结如下:
1、在编码过程中,要把x的范围从十进制转换到二进制,并一一对应。一般流程:2^n-1 < (xMax-xMin )* 10^4 < 2^n;n是对应所需二进制的位数。decimal=(m-aj)/(bj-aj)* (2^18-1) +0.5,让小数点四舍五入。注意不要直接把十进制数 *10^n,转化为二进制。
2、termination condition是什么?本例根据循环次数来判定。还可以根据最大适应度和种群间相同个体数与总个体数的比值来判定。
3、本例中,刚开始是采用map < double,double > 类型来存储x1,x2的值,但是在经过一轮迭代之后,种群中的优秀的染色体(二进制码)是有相同的,所以经过解码后得到的x1、x2的值会出现相同的情况。所以map显然不满足要求,mutilmap类型刚好符合这种情况。
4、轮盘赌算法。在筛选过程中很重要的选择方法。每个个体的适应度占总适应度的比值,然后按照后一个比值叠加到前一个比值上得到一个轮盘值,照此下去,直到最后轮盘值为1。就这样构成了一个完整的轮盘。

以下是我画的大概的过程:
《c++ 简单的遗传算法实现》

    原文作者:遗传算法
    原文地址: https://blog.csdn.net/zc20122690/article/details/52959826
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞