遗传算法入门简单实例

参考:

http://www.360doc.com/content/15/0309/15/13726687_453806200.shtml

http://www.cnblogs.com/liyuwang/p/5988358.html

        最近在自学《演化计算》(潘正君著),了解了演化算法的基本基本步骤。在丽丽的帮助下找到了一个SGA的入门小程序,结合程序,理解演化算法中简单遗传算法的基本步骤。

一、问题描述

        f(x1, x2) = x1 * x1 + x2 * x2,求解 f 的最大值(x1、x2为 0 ~ 7之间的正整数)。

二、算法实现

        1、基本模块(具体遗传算法的基本步骤可以查书)

                a、初始化种群(二进制编码)

                b、评价种群(计算目标值、适应值、更新当前最坏个体)

                c、产生下一代种群(选择——轮盘式选择、交叉——单点交叉、变异)

                d、输出结果

        2、具体思想

                a、初始化种群(二进制编码)

                        x1、x2分别用3位二进制数来表示,将它们连在一起组成一个6位二进制数。用字符串来保存。

                        例:基因型 X = 101110,表现型 x1 = 5,x2 = 6。

                        种群使用一个结构体来表示,包括

                b、评价种群(计算目标值、适应值)

                        本例中,目标值和适应值相同就采用一个整型变量来存储,fitness。

                c、评价种群(更新当前最坏个体)

                        例中,额外定义一个历史最好个体和当前最坏个体。每次调用评价种群函数更新历史最好个体,并找到当前最坏个体,用历史最好个体更新当前最坏个体。

                e、产生下一代种群(选择——轮盘式选择)

                        计算种群中所有个体的适应值之和sfitness。

                        计算每个个体相对适应值的大小 cfitness[i] += fitness / sfitness – cfitness[i – 1]。

                        随机生成 0 ~ 1 之间的数,来确定每个个体被选中的次数。

                 f、产生下一代种群(交叉——单点交叉)

                        打乱种群中个体的下标,重新排列种群中的个体。

                        循环,每次两个个体。

                        判断随机概率是否低于交叉概率。

                        是,则随机生成一个单点的下标。

                        将两个个体从单点下标开始到个体末端的基因位进行交换。

                g、产生下一代种群(变异)

                        对每个个体的每一位随机生成概率。

                        若概率低于变异概率,则将这一位取反。

        3、注意问题

                a、随机数生成

                        由于rand()直接产生的是伪随机,所以在前面添上:

                               inclue <time.h>
                               rand((int)time(0));

                b、种群中个体的个数、交叉概率和变异概率都会对算法产生影响,慎重选取

                        这里个体个数为:10

                               交叉概率为:0.6

                               变异概率为:0.001

#include <iostream>
#include <time.h>
#include <stdio.h>
using namespace std;

#define Popsize 10 //population size
#define ChromLength 6 //length of chromosome

typedef struct
{
	char chrom[ChromLength + 1];//a chromosome of individual
	int fitness; //取fitness(适应值) = value(目标值)
}Individual;

int gen; //current generation no.
int maxgen = 100; //maximum generation
int bestidx; //最好个体下标
int sfitness; //适应值总和

double pc = 0.6; //交叉概率
double pm = 0.001; //变异概率

Individual pop[Popsize + 1]; //old population
Individual hisbestind; //历史最佳个体
Individual curworsind; //当前最差个体

void initpop(void); //初始化种群
void evaluatepop(void); //评估种群并优化
void calfitness(void); //计算目标值(适应值)
int decchrom(char *chrom, int l, int r); //二进制转十进制
void findbestandworsind(void); ////更新历史最好和当前最坏个体,并用历史最好替换当前最坏
void gennexpop(void); //产生下一代种群
void selectpop(void); //选择算子,轮盘式选择
void crosspop(void); //交叉算子,单点交叉
void mutatepop(void); //变异算子,对每个个体每一位进行概率变异
void output(void); //输出

//初始化种群
void initpop(void)
{
	int i, j;
	srand((int)time(0));
	for(i = 0; i < Popsize; i++)
	{
		for(j = 0; j < ChromLength; j++)
		{
			if(rand() % 2 == 0)
				pop[i].chrom[j] = '0';
			else
				pop[i].chrom[j] = '1';
		}
		pop[i].chrom[j] = '\0';
	}
	bestidx = 0;
}

//评估种群并优化
void evaluatepop(void)
{
	calfitness();
	findbestandworsind();
}

//计算目标值(适应值)
//目标函数为f(x) = x1 * x1 + x2 * x2;
void calfitness(void)
{
	int i, x1, x2;
	for(i = 0; i < Popsize; i++)
	{
		x1 = decchrom(pop[i].chrom, 0, 2);
		x2 = decchrom(pop[i].chrom, 3, 5);
		pop[i].fitness = x1 * x1 + x2 * x2;
	}
	//求适应值总和
	sfitness = 0;
	for(i = 0; i < Popsize; i++)
		sfitness += pop[i].fitness;
}

//二进制转十进制
int decchrom(char *chrom, int l, int r)
{
	int i, tmp = 1, dec = 0;
	for(i = r; i >= l; i--)
	{
		dec += tmp * (chrom[i] - '0');
		tmp *= 2;
	}
	return dec;
}

//更新历史最好和当前最坏个体,并用历史最好替换当前最坏
void findbestandworsind(void)
{
	int i, j = 0;
	if(gen == 0)
		hisbestind = pop[0];
	curworsind = pop[0];
	for(i = 0; i < Popsize; i++)
	{
		if(hisbestind.fitness < pop[i].fitness)
			hisbestind = pop[i];
		else if(curworsind.fitness > pop[i].fitness)
		{
			curworsind = pop[i];
			j = i;
		}
	}
	pop[j] = hisbestind; 
}

//产生下一代种群
void gennexpop(void)
{
	selectpop();
	crosspop();
	mutatepop();
}

//选择算子,轮盘式选择
void selectpop(void)
{
	int i, j;
	double cfitness[Popsize + 1], p;
	Individual newpop[Popsize + 1];
	//计算轮盘分布
	cfitness[0] = (double)pop[0].fitness / sfitness;
	for(i = 1; i < Popsize; i++)
		cfitness[i] = (double)pop[i].fitness / sfitness + cfitness[i - 1];
	//用轮盘进行随机选取,产生新的种群
	for(i = 0; i < Popsize; i++)
	{
		p = rand() % 1000 / 1000.0;
		j = 0;
		while(p > cfitness[j]) j++;
		newpop[i] = pop[j];
	}
	//更新种群
	for(i = 0; i < Popsize; i++)
		pop[i] = newpop[i];
}

//交叉算子,单点交叉
void crosspop(void)
{
	int i, j, tmp, poi, idx[Popsize + 1];
	double p;
	char c;
	//打乱种群下标,重新排列
	for(i = 0; i < Popsize; i++)
		idx[i] = 1;
	for(i = 0; i < Popsize; i++)
	{
		poi = rand() % (Popsize - i);
		tmp = idx[poi];
		idx[poi] = idx[i];
		idx[i] = tmp;
	}
	//随机选取交叉点,进行交叉
	for(i = 0; i < Popsize; i += 2)
	{
		p = rand() % 1000 /1000.0;
		if(p < pc)
		{
			poi = rand() % ChromLength;
			for(j = poi; j < ChromLength; j++)
			{
				c = pop[i].chrom[j];
				pop[i].chrom[j] = pop[i + 1].chrom[j];
				pop[i + 1].chrom[j] = c;
			}
		}
	}
}

//变异算子,对每个个体每一位进行概率变异
void mutatepop(void)
{
	int i, j;
	double p;
	for(i = 0; i < Popsize; i++)
	{
		for(j = 0; j < ChromLength; j++)
		{
			p = rand() % 1000 / 1000.0;
			if(p < pm)
			{
				if(pop[i].chrom[j] == '0')
					pop[i].chrom[j] = '1';
				else
					pop[i].chrom[j] = '0';
			}
		}
	}
}

//输出
void output(void)
{
	double avg = (double)sfitness / Popsize;
	cout << "gen = " << gen << ", avg = " << avg << ", best = " << hisbestind.fitness << ", chrom = " << hisbestind.chrom << endl;
}

int main()
{
	gen = 0;
	initpop();
	evaluatepop();
	while(gen < maxgen)
	{
		gen++;
		gennexpop();
		evaluatepop();
		output();
	}
	return 0;
}

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