遗传算法C语言源码

遗传算法是上学时曾经研究过的算法,它是一种基于基因遗传思想的快速搜索遍历算法。简单理解,它就是比一般的盲搜索和其他的一些搜索快的算法。其主要目的就是为了能快速准确搜索所求的值,用于求解一些复杂的数值应用,以及一些实时性要求高的算法应用中。以下是以前练习过的代码,欢迎有需要的同学学习交流。

include <stdio.h>
include <string.h>
include <stdlib.h>
include <ctime>
include <math.h>

define N 30000000000
define PI 3.14159265
define MIN_(a,b) ((a)>(b)?(b):(a))//定义求最小值函数MIN_(a,b) 

define SIZE  50
define MAXGEN  50
define P_CORSS 0.75
define P_MUTATION 0.05

define LEN 22

typedef struct node//定义结构体,表示染色体,x是染色体二进制编码,fitness是该染色体的适应值,fitsum是当前所有染色体的适应值的总和
{
  char x[LEN];
  double fitness,fitsum;
}node;

node cur[SIZE],next[SIZE],max,min;//定义结构体数组,有当前染色体种群,下一代染色体种群,以及最优和最差染色体。

double randd()
{
  return (double)rand()/RAND_MAX;//产生0-1之间随机数, RAND_MAX其值至少为32767,rand()在0-MAX之间
}
int randi(int k)
{
  return (int)(randd()*k+0.5);//返回接近k大小的随机值
}

//计算当前种群中各个个体的适应度 
void cal_fitness()
{
  int i,j,k;
  double d;
  for(i=0;i<SIZE;i++)
  {
    k=0;
    for(j=LEN-1;j>=0;j--) k=(k<<1)+cur[i].x[j];;//该循环用于将染色体二进制数转成十进制,<<是左移运算,x[j]是染色体i的第j位
    d=(double)k/N*100-50;//用上面的k产生一个浮点数d,作为函数自变量x的值
    cur[i].fitness=d+10*sin(5*d)+7*cos(4*d);            //计算每个染色体的适应值 //////// //函数y= x+10*sin(5*x)+7*cos(4*x)////////////// 
    cur[i].fitsum=i>0?(cur[i].fitness+cur[i-1].fitsum):(cur[0].fitness);//计算所有适应值的总和,里面有迭代过程,就是若i=3,则cur[3].fitsum=cur[3].fitsum+cur[2].fitsum+cur[1].fitsum+cur[0].fitsum.
  }
}

void init()//初始化染色体种群,共SIZE个,每个都是二进制LEN长度的串
{
  int tmp;
  for(int i=0;i<SIZE;i++)
  {
    tmp=randi(N);//用randi函数产生一个大概N那么大的随机数
    for(int j=0;j<LEN;j++)
    {
      cur[i].x[j]=tmp%2;//用temp对2取余,初始化每个染色体的每个位,共LEN位;一个数不是奇数就是偶数,对2取余得0或1,从而产生像001001010...11010001这样的串
      tmp=tmp>>1;//右移tmp,就是将temp缩小,使tmp值变化
    }
  }
  cal_fitness();//计算当前种群各个个体的适应度 
}

int sel()//选择种群中某个染色体
{
  double p=randd();
  double sum=cur[SIZE-1].fitsum;//全部染色体的适应值总和
  for(int i=0;i<SIZE;i++)
  {
    if(cur[i].fitsum/sum>p) return i;//如果当前适应总值/全部总值大于随机数p,也就是当前适应总值不为0,不太差时,返回这个i值,循环停止
  }
}

//换代 
void tran()
{
  int i,j,pos;
  //找当前种群最优个体 
  max=cur[0];
  for(i=1;i<SIZE-1;i++)
  {
    if(cur[i].fitness>max.fitness)  max=cur[i];//记录种群中的最优染色体为max
  }
  for(int k=0;k<SIZE;k+=2)
  {
    //选择交叉个体 
    i=sel();//用sel函数挑选一个个体,染色体号为i
    j=sel();//同上,再选择个个体,号为j

    //选择交叉位置 
    pos=randi(LEN-1);//随机产生个LEN-1左右的数pos,如18,19,21等

    //交叉
    if(randd()<P_CORSS)//如果randd()产生的随机数(在0-1之间)小于设定的交叉率P_CORSS
    {
      memcpy(next[k].x,cur[i].x,pos);//提取染色体i的前pos位赋给下一代种群next的第k个染色体.——函数memcpy(&a,&b,n)用于从&b的位置开始数n个长度的数据拷贝赋给&a; 
      memcpy(next[k].x+pos,cur[j].x+pos,LEN-pos);//提取染色体j的 后面LEN-pos位赋给next的第k个染色体,结合上面,从而拼成一个新的染色体

      memcpy(next[k+1].x,cur[j].x,pos);//同样的方式给next的第k+1染色体赋值,这回换过来生成这个值,即提取j的前pos位数据 + i的后LEN-pos位数据
      memcpy(next[k+1].x+pos,cur[i].x+pos,LEN-pos);
    }
    else//否则不交叉,
    {
      memcpy(next[k].x,cur[i].x,LEN);
      memcpy(next[k+1].x,cur[j].x,LEN);
    }
    //变异
    if(randd()<P_MUTATION)//如果一随机数小于设定的变异率P_MUTATION,则执行变异操作
    {
      pos=randi(LEN-1);//仍然是从中间找个位置,执行变异
      next[k].x[pos]^=next[k].x[pos];// ^=按位异或后赋值函数,相同为0不同为1,此处是将第pos位上的值(不论是0或1)定为0

      pos=randi(LEN-1);
      next[k+1].x[pos]^=next[k+1].x[pos];//同样将下一代next的第k+1个染色体的第pos位也变为0;??最好应该是0变1,1变0...,但这样也行,进化稍慢点
    }
  }
  //找下一代的最差个体 
  min=next[0],j=0;
  for(i=1;i<SIZE-1;i++)
  {
    if(next[i].fitness<min.fitness)  min=next[i],j=i;//用j记录最差染色体号
  }
  //用上一代的最优个体替换下一代的最差个体
  next[j]=max;

  memcpy(cur,next,sizeof(cur));//把整个改良过的(经过交叉,变异,替换等操作的)next代的值赋给当前种群cur,供下一次循环优化


  cal_fitness();
}

//打印个体适应度和二进制编码 
void print(node tmp)
{
  printf("%.6lf",tmp.fitness);
  for(int i=0;i<LEN;i++)  printf(" %d",tmp.x[i]);
  printf("\n");
}

//打印种群
void printcur()
{
  for(int i=0;i<SIZE;i++) print(cur[i]);
} 


void GA()
{
  int cnt=0;
  double ans;
  while(cnt++<MAXGEN)//当计数值cnt小于设定的最大进化次数MAXGEN,执行换代操作
  {
    tran();
  }
  ans=cur[0].fitness;
  for(int i=1;i<SIZE;i++) ans=MIN_(ans,cur[i].fitness);//找出函数最小值,打印输出(应设定的是求函数最小值)
  printf("%.6lf\n",ans);
}

int main()
{
  srand((unsigned)time(NULL));//初始化随机数种子产生器,为使程序中每次的rand()函数产生的随机数不一样

  init();//初始化种群
  GA();//遗传换代操作

  system("pause"); //输出结果在屏幕,而不是一闪而过
  return 0;
}
    原文作者:遗传算法
    原文地址: https://blog.csdn.net/tortoisess/article/details/71271378
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞