交叉算子用的pbx算子,自己写的交叉方法。
这个类名是GenAlgTSP,求解y=3*a^2+24*b+5*c^2+d^3+e+2f+2*g^3的最大值,a,b,c,d,e,f,g取值为0到6。也就是0到6做一个最优排序,使得y值最大。适应度函数你可以自己改,我这里设定的不太好,就是y本身。
先是GenAlgTSP.h文件,代码如下
#include"stdafx.h"
#include
#include
#include
#include
#include
#define len 7 //数字范围,即染色体长度
typedef struct Chrom // 结构体类型,为单个染色体的结构;
{
int bit[len];//一共len长度bit来对染色体进行编码。取值为10进制。
int fit;//适应值
double rfit;//相对的fit值,即所占的百分比
double cfit;//积累概率
}chrom;
class GenAlgTSP{
private:
public:
void evpop(chrom popcurrent[100]);//进行种群的初始化
bool check(chrom *p, int pop, int num, int k);//检查初始化时是否已存在节点
int y(chrom popcurrent); //函数:求个体的适应度,适应度函数为y=3*a^2+24*b+5*c^2+d^3+e+2f+2*g^3
void pickchroms(chrom popcurrent[100]);//选择操作
void pickchroms_new(chrom popcurrent[100]); // 基于概率分布
void crossover(chrom popnext[100]);//交叉操作
int findLocInPar(int data,int i);//寻找第一个父亲选定节点在第二个父亲的位置
void mutation(chrom popnext[100]);//突变
double r8_uniform_ab(double a, double b, int &seed);//生成a~b之间均匀分布的数字
chrom popcurrent[100]; // 初始种群规模为;
chrom popnext[100]; // 更新后种群规模仍为;
};
然后是GenalgTSP.cpp文件,代码如下
#include "stdafx.h"
#include "GenAlgTSP.h"
//#include "stdafx.h"
void GenAlgTSP::evpop(chrom popcurrent[100])// 函数:随机生成初始种群;
{
int r;
int sum = 0;
for (int i = 0; i<100; i++)
{
for (int j = 0; j
r = rand() % len;//产生0~len之间的随机数
while (check(popcurrent, i, j, r))//随机产生城市序号,即为city.colony[i][j]赋值
{
r = rand() % len;
}
popcurrent[i].bit[j] = r;
}
popcurrent[i].fit = y(popcurrent[i]); // 计算染色体的适应度值
sum = sum + popcurrent[i].fit;
}
for (int i = 0; i < 100; i++)
{
popcurrent[i].rfit = popcurrent[i].fit / sum;
popcurrent[i].cfit = 0;//将其初始化为0
}
}
bool GenAlgTSP::check(chrom *p, int pop, int num, int k)/*用来检查新生成的节点是否在当前群体中*/
{
int i;
for (i = 0; i < num; i++){
if (k ==(*(p+pop)).bit[i])
return true;//新生成节点存在于已经生成的路径中
}
return false;//新生成节点没有存在于已经生成的路径中
}
int GenAlgTSP::y(chrom popcurrent){
int sum=0,j;
for (j = 0; j < len; j++){
if (j == 0)
sum = sum + 3 * popcurrent.bit[j] * popcurrent.bit[j];
else if (j == 1)
sum = sum + 24 * popcurrent.bit[j];
else if (j == 2)
sum = sum + 5 * popcurrent.bit[j] * popcurrent.bit[j];
else if (j == 3)
sum = sum + popcurrent.bit[j] * popcurrent.bit[j] * popcurrent.bit[j];
else if (j == 4)
sum = sum + popcurrent.bit[j];
else if (j == 5)
sum = sum + 2 * popcurrent.bit[j];
else if (j == 6)
sum = sum + popcurrent.bit[j] * popcurrent.bit[j] * popcurrent.bit[j];
}
return sum;
}
void GenAlgTSP::pickchroms(chrom popcurrent[100])//选择操作
{
int i, j;
chrom temp; // 中间变量
//因此此处设计的是个个体,所以参数是
for (i = 0; i<99; i++) // 根据个体适应度来排序;(冒泡法)
{
for (j = 0; j<99 - i; j++)
{
if (popcurrent[j + 1].fit>popcurrent[j].fit)
{
temp = popcurrent[j + 1];
popcurrent[j + 1] = popcurrent[j];
popcurrent[j] = temp;
}
}
}
_flushall();/* 清除所有缓冲区 */
}
void GenAlgTSP::pickchroms_new(chrom popcurrent[100]) // 基于概率分布
{
int men;
int i; int j;
double p;
double sum = 0.0;
//find the total fitness of the population
for (men = 0; men < 100; men++)
{
sum = sum + popnext[men].fit;
}
//calculate the relative fitness of each member
for (men = 0; men < 100; men++)
{
popnext[men].rfit = popnext[men].fit / sum;
}
//calculate the cumulative fitness,即计算积累概率
popcurrent[0].cfit = popcurrent[0].rfit;
for (men = 1; men < 100; men++)
{
popnext[men].cfit = popnext[men - 1].cfit + popnext[men].rfit;
}
for (i = 0; i < 100; i++)
{//产生0~1之间的随机数
//p = r8_uniform_ab ( 0, 1, seed );//通过函数生成0~1之间均匀分布的数字
p = rand() % 10;//
p = p / 10;
if (p < popnext[0].cfit)
{
popcurrent[i] = popnext[0];
}
else
{
for (j = 0; j < 100; j++)
{
if (popnext[j].cfit <= p && p < popnext[j + 1].cfit)
{
popcurrent[i] = popcurrent[j + 1];
}
}
}
}
// Overwrite the old population with the new one.
//
for (i = 0; i < 100; i++)
{
popnext[i] = popcurrent[i];
}
}
double GenAlgTSP::r8_uniform_ab(double a, double b, int &seed)
{
{
int i4_huge = 2147483647;
int k;
double value;
if (seed == 0)
{
std::cerr << "\n";
std::cerr << "R8_UNIFORM_AB - Fatal error!\n";
std::cerr << " Input value of SEED = 0.\n";
exit(1);
}
k = seed / 127773;
seed = 16807 * (seed - k * 127773) - k * 2836;
if (seed < 0)
{
seed = seed + i4_huge;
}
value = (double)(seed)* 4.656612875E-10;
value = a + (b - a) * value;
return value;
}
}
void GenAlgTSP::crossover(chrom popnext[100])//交叉操作,计算新适应度,调适应度函数
//适应度前4的个体不参与交叉,4到51号的个体配对交叉,产生48个后代赋值给第52到99号个体。
//交叉算子采用PBX算子交叉
{
int i,random1=0, random2=0,L1,L2,L3,L4;
while (random1 == random2){
random1 = rand()%len;
random2 = rand() % len;
}
for (i = 4; i <= 50; i = i + 2){
L1 = findLocInPar(popnext[i].bit[random1],i);//L1表示偶数父亲的选定节点在另一父亲对应节点的位置
L2 = findLocInPar(popnext[i].bit[random2],i);//L2同L1
L3 = findLocInPar(popnext[i + 1].bit[random1], (i+1));//L3表示奇数父亲选定节点在另一父亲对应节点的位置
L4 = findLocInPar(popnext[i + 1].bit[random2], (i + 1));//L3同L4
for (int k = 0,x=0; x
if ((k != random1)&&(k != random2)){
if ((x != L1)&&(x != L2)){
popnext[i + 48].bit[k] = popnext[i + 1].bit[x];
x++;
k++;
}
else
x++;
}
else if (k == random1){
popnext[i + 48].bit[k] = popnext[i].bit[random1];
k++;
}
else
{
popnext[i + 48].bit[k] = popnext[i].bit[random2];
k++;
}
}//偶数父代得到子代
for (int k = 0, x = 0; x < len||k < len;)
{
if ((k != random1) && (k != random2)){
if ((x != L3) && (x != L4)){
popnext[i + 48+1].bit[k] = popnext[i].bit[x];
x++;
k++;
}
else
x++;
}
else if (k == random1){
popnext[i + 48+1].bit[k] = popnext[i+1].bit[random1];
k++;
}
else
{
popnext[i + 48+1].bit[k] = popnext[i+1].bit[random2];
k++;
}
}
}//交叉结束
for (int i=0; i < 100; i++)//为新一代计算适应度值
{
popnext[i].fit = y(popnext[i]); // 为新个体计算适应度值;
}
}
int GenAlgTSP::findLocInPar(int data,int i)
{
if (i % 2 == 0){
int j;
for (j = 0; j < len;j++)
if (popnext[i+1].bit[j] == data)
return j;
}
else{
int j;
for (j = 0; j < len;j++)
if (popnext[i-1].bit[j] == data)
return j;
}
}
void GenAlgTSP::mutation(chrom popnext[100])//突变
{
int random;
int row, col,col2,t;
//srand(time(0));
random = rand() % 50; // 随机产生到之间的数;
//变异操作也要遵从一定的概率来进行,一般设置为0到0.5之间
//
if (random == 25) // random==25的概率只有2%,即变异率为,所以是以小概率进行变异!!
{
col = rand() % len; // 随机产生要变异的基因位号;
row = rand() % 100; // 随机产生要变异的染色体号;
col2 = rand() % len; // 随机产生要变异的基因位号;
t = popnext[row].bit[col];
popnext[row].bit[col] = popnext[row].bit[col2];
popnext[row].bit[col2] = t;
/***************************************************************************************************************************/
popnext[row].fit = y(popnext[row]); // 计算变异后的适应度值;
}
}
注意,概率分布函数没什么用,这个算法没有用到,可以酌情删去。
最后是main函数
#include "stdafx.h"
#include "GenAlgTSP.h"
void main() // 主函数;
{
int num; // 迭代次数;
int i, j, l, Max, k;
Max = 0; // 函数最大值
printf("\nWelcome to the Genetic Algorithm!\n"); //
printf("The Algorithm is based on the function 函数为y=3*a^2+24*b+5*c^2+d^3+e+2f+2*g^3 to find the maximum value of the function.\n");
enter:printf("\nPlease enter the no. of iterations\n请输入您要设定的迭代数 : ");
scanf_s("%d", &num); // 输入迭代次数,传送给参数 num;
if (num <1)
goto enter; // 判断输入的迭代次数是否为负或零,是的话重新输入;
//不同的随机数可能结果不同??那是当所设置的迭代次数过少时,染色体的基因型过早地陷入局部最优
srand(time(0));
GenAlgTSP genalg;
genalg.evpop(genalg.popcurrent); // 随机产生初始种群;
//是否需要指定x的取值范围呢?6bit来表示数字,第一位为符号位,5bit表示数字大小。所以,取值范围为-32~+31
Max = genalg.popcurrent[0].fit;//对Max值进行初始化
for (i = 0; i< num; i++) // 开始迭代;
{
printf("\ni = %d\n", i); // 输出当前迭代次数;
for (j = 0; j<100; j++)
{
genalg.popnext[j] = genalg.popcurrent[j]; // 更新种群;
}
genalg.pickchroms(genalg.popnext); // 挑选优秀个体;
genalg.crossover(genalg.popnext); // 交叉得到新个体;
genalg.mutation(genalg.popnext); // 变异得到新个体;
for (j = 0; j<100; j++)
{
genalg.popcurrent[j] = genalg.popnext[j]; // 种群更替;
}
} // 等待迭代终止;
//对于真正随机数是需要注意取较大的迭代次数
int A[len];
for (l = 0; l<100; l++)
{
if (genalg.popcurrent[l].fit > Max)
{
Max = genalg.popcurrent[l].fit;
//k = genalg.y(genalg.popcurrent[l]);//此时的value即为所求的x值
for (int i = 0; i < len; i++)
A[i] = genalg.popcurrent[l].bit[i];
}
}
printf("\n 当排序等于");
for(int i = 0; i < len;i++)
printf("%d ", A[i]);
printf("\n函数得到最大值为: %d ", Max);
printf("\nPress any key to end ! ");
_flushall(); // 清除所有缓冲区;
_getche(); // 从控制台取字符,不以回车为结束;
}