遗传算法GA

来源:互联网 发布:联想扬天x110知乎 编辑:程序博客网 时间:2024/05/19 13:07

摘要

写华为CodeCraft的时候,尝试使用了遗传算法进行搜索,以下是模仿网上教程写的代码,我把它进行了简单的封装,常用参数都可以直接改了,可以作为一个小的Demo来使用。

使用的Qt环境,所以注意把Qt相关的内容删掉。

目标函数默认为求当前基因节点的最大和,比如当前的y_totalNodeNumber 为800,则理论上最优值为800,我用随机数初始化了一个随机值,用来测试收敛的速度,这个函数可以根据使用需要进行更改,遗传策略之类的东西也是可以自定义的。除了淘汰概率!!!!

同时,我设置了两种迭代控制,分别是规定迭代次数和迭代的时间,分别通过y_startIteration(1000000)y_startIterationByTime(5000) 进行控制,前者单位为次数,后者为毫秒。

这里放一张运行图片,初始值为402,跑了5秒钟,输出了762,感觉还阔以噻 :)

这里写图片描述


代码

#include <QCoreApplication>#include <iostream>#include <time.h>#include <stdlib.h>using namespace std;void y_initiateGroups();void y_travelsal();double y_fitness(int n);void y_pickChroms();void y_crossover();void y_mutation();void swapChrom(int i, int j);const int y_totalNodeNumber = 800; //每个个体中的基因节点个数,也就是节点数目const int y_totalGroupNumber = 4; //种群个体个数,如为n,表示当前种群中有n个个体参与繁衍和变异const float y_failRate = 0.5; //每一代的淘汰比率const float y_mutateRate = 0.2; //变异概率typedef struct Chrom                           // 结构体类型,为单个染色体的结构;{    short int bit[y_totalNodeNumber];//一共6bit来对染色体进行编码,其中1位为符号位。取值范围-64~+64    int fit ;//适应值    double rfit;//相对的fit值,即所占的百分比    double cfit;//积累概率}chrom;chrom y_groupCurrent [y_totalGroupNumber];          // 初始种群规模chrom y_groupNext    [y_totalGroupNumber];          // 更新后种群规模//初始化种群void y_initiateGroups(){    double sum = 0.0;    srand(clock() + (unsigned)time(NULL));    for(int i=0; i<y_totalGroupNumber; ++i){        for(int j=0; j<y_totalNodeNumber; j++){            y_groupCurrent[i].bit[j] = (short)(rand() % 2);        }    }    for(int i=0; i<y_totalGroupNumber; ++i){        y_groupNext[i] = y_groupCurrent[i];        y_groupCurrent[i].fit = y_fitness(i);        sum = sum + y_groupCurrent[i].fit;    }    //计算适应值得百分比,该参数是在用轮盘赌选择法时需要用到的    for (int i=0; i<y_totalGroupNumber; ++i)    {        y_groupCurrent[i].rfit = y_groupCurrent[i].fit/sum;        y_groupCurrent[i].cfit = 0;//将其初始化为0    }}int Partition(Chrom a[], int left, int right)///7行代码{    int i = left - 1;///初始化一定要赋值好。    for (int j = left;j <= right - 1;j++) {        if (a[j].fit > a[right].fit) {///把right这个作为轴了。            i++;///这个i坐标左边的值就是比a[right]小的。            swapChrom(i,j);///必须交换一下。        }    }    swapChrom(i+1,right);///最后把i+1和right交换,这样轴就是i+1了必须是保证i+1上当初就是作为标杆的a[right]啊。    return i + 1;}void Qsort(Chrom a[], int left, int right){    if (left < right) {        int q = Partition(a, left, right);        Qsort(a, left, q - 1);        Qsort(a, q + 1, right);    }}void swapChrom(int i, int j){    chrom temp ;    temp             = y_groupNext[j];    y_groupNext[j]   = y_groupNext[i];    y_groupNext[i]   = temp;}//从种群中选出若干个体进行交叉、变异,这里采用排序法来选择,即每次选择都选出适应度最高的两个个体void y_pickChroms(){//    Qsort(y_groupNext, 0, y_totalGroupNumber);    //以下为冒泡法    int i ,j;    chrom temp ;                                // 中间变量    int top = y_totalGroupNumber-1;    for(i=0; i<top; i++)                          // 根据个体适应度来排序;(冒泡法)    {        for(j=0; j<top-i; j++)        {            if(y_groupNext[j+1].fit > y_groupNext[j].fit)            {                temp             = y_groupNext[j+1];                y_groupNext[j+1] = y_groupNext[j];                y_groupNext[j]   = temp;            }        }    }}void y_crossover(){    srand(clock() + (unsigned)time(NULL));    int random = rand() % y_totalNodeNumber;          // 随机产生交叉点,交叉点控制在0到y_totalGroupNumber之间;    int lastParentIndex = (int)((1-y_failRate)*y_totalGroupNumber);    int i,k ;    for(i=0; i<random; ++i)    {        //采取第一名和剩下的所有母节点进行繁殖的策略        k=1;        for(int j=0; j<lastParentIndex; j+=2){            y_groupNext[j+lastParentIndex].bit[i] = y_groupNext[0].bit[i];            y_groupNext[j+lastParentIndex+1].bit[i] = y_groupNext[k].bit[i];            ++k;        }    }    for(i=random; i<y_totalNodeNumber; ++i)         // crossing the bits beyond the cross point index    {        //采取第一名和剩下的所有母节点进行繁殖的策略        k=1;        for(int j=0; j<lastParentIndex; j+=2){            y_groupNext[j+lastParentIndex].bit[i] = y_groupNext[k].bit[i];            y_groupNext[j+lastParentIndex+1].bit[i] = y_groupNext[0].bit[i];            ++k;        }    }    for(i=lastParentIndex; i<y_totalGroupNumber; ++i)    {        y_groupNext[i].fit= y_fitness(i);        // 为新个体计算适应度值;    }}void y_mutation(){    int row ,col;    srand(clock() + (unsigned)time(NULL));    int random = rand()%1000;  // 随机产生到之间的数;    int mutate = 1000*y_mutateRate;    //变异操作也要遵从一定的概率来进行,一般设置为0到0.5之间    if(random < mutate)                              //变异率为y_mutate,所以是以小概率进行变异!!    {        col=rand()%y_totalNodeNumber;          // 随机产生要变异的基因位号;        row=rand()%y_totalGroupNumber;         // 随机产生要变异的染色体号;        if(y_groupNext[row].bit[col]==0)             // 1变为0;        {            y_groupNext[row].bit[col]=1 ;        }        else if (y_groupNext[row].bit[col]==1)        // 0变为1;        {            y_groupNext[row].bit[col]=0;        }        y_groupNext[row].fit= y_fitness(row);     // 计算变异后的适应度值;    }}//输出当前的种群void y_travelsal(){    for(int i=0; i<y_totalGroupNumber; i++)    {        for(int j=0; j<y_totalNodeNumber; j++)        {            cout<<y_groupCurrent[i].bit[j]<<" ";        }        cout<<y_groupCurrent[i].fit<<endl;    }}//输出下一代种群void y_travelsal_next(){    for(int i=0; i<y_totalGroupNumber; i++)    {        for(int j=0; j<y_totalNodeNumber; j++)        {            cout<<y_groupNext[i].bit[j]<<" ";        }        cout<<y_groupNext[i].fit<<endl;    }}//传入行号,对y_groupCurrent的第n行进行适应度计算,返回适应度数值double y_fitness(int n){    int sum = 0;    for(int i=0; i<y_totalNodeNumber; ++i)    {        sum += y_groupNext[n].bit[i];    }    return (double)sum;}//开始迭代void y_startIteration(int num) //num为迭代次数{    for(int i=0; i<num; i++)                          // 开始迭代;    {        y_pickChroms();                    // 挑选优秀个体;        y_crossover();                     // 交叉得到新个体;        y_mutation();                      // 变异得到新个体;    }  // 等待迭代终止;}void y_startIterationByTime(int timeLimit){    int starttime = clock();    int curtime = clock();    int itr = 0;    while(1)    {        if(curtime - starttime >= timeLimit)            break;        y_pickChroms();                    // 挑选优秀个体;        y_crossover();                     // 交叉得到新个体;        y_mutation();                      // 变异得到新个体;        itr++;        curtime = clock();    }    cout<<"iter: "<<itr<<endl;}int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    int starttime = clock();    y_initiateGroups();    y_pickChroms();    cout<<y_groupCurrent[0].fit<<endl;    //y_startIteration(1000000);    y_startIterationByTime(5000);    y_pickChroms();    cout<<y_groupNext[0].fit<<" Time: "<<clock()-starttime<<endl;    return a.exec();}
1 0
原创粉丝点击