遗传算法GA

摘要

写华为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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值