遗传算法,顾名思义,是在计算机中模拟自然界中的进化过程,优胜劣汰,从而得到出最优个体的算法。因此我们可以从自然界的进化过程着手,来理解什么是遗传算法。
在自然界中,物种的进化往往是以外界环境的变化为开端的,比如水中生物用于水下呼吸的鳃,南极生物皮下厚厚的脂肪,都是适应外界环境的结果。而在遗传算法中,算法想要达到的目的就是这里的“外界环境”,于是我们设置了一个数值来评估每个个体与外界环境的契合程度,称为“适应度(Fitness)”。比如你想要求一个函数的最大值,那么函数值的大小就是其适应度;你想求两地之间的最短路线,那么距离就是其适应度。
了解过进化过程的人都知道,进化本质上是一个“筛选”的过程,基因随机产生变异,然后携带劣质基因的个体由于不能适应环境而被淘汰,如此循环很多代之后,留存下来的都会是适应度很高的个体。这个优胜劣汰的过程,在遗传算法中称为“选择(Select)”。
自然界的种群,是靠繁殖来补充在选择过程中的淘汰的个体,在繁殖的过程中,父母的染色体重新组合,使得子女会带有父母的部分基因,更有一定可能会集成父母二者的优势。遗传算法中,随机选取两个个体,让二者的染色体随机重组生成一条或多条新染色体的过程,称为“交叉(Cross)”。
除了交叉之外,还有一个提升基因多样性的重要手段,就是“变异(Mutation)”,在算法中表现为将某一位进行反转,来模拟自然界中的基因突变。
遗传算通过选择,交叉,变异操作对种群进行不断迭代,就会使得整个群体的适应度越来越高,使其中的最优个体不断的逼近最优解。但是想要完成一个完整的遗传算法,还需要一些其它的组成部分,接下来结合代码进行说明。
注:个体&染色体:本文假定每个个体只含有一个染色体,因此“染色体”和“个体”均表示基因的载体,在阅读中二者可以认为是同一种东西。
遗传算法解决函数优化问题实例:
适应度:要求函数的最小值,那么就要使得到结果越小的个体,适应度越高。
精度:想要精确到小数点后6位,那么定义域的区间至少需要划分成6*10^6等份,再求出表示这个量级所需要的二进制位数,作为基因的位数
终止条件:通常是达到指定迭代次数和达到指定精度便停止迭代,输出结果。本文代码为了便于观察只设置了迭代次数作为终止条件。
为了便于以后修改,我将每一个步骤都写成了单独的类。
1.编码和解码
编码:初始化,将染色体的每一位都随机置为0或1
//初始化群体(编码)
public class ClsInit {
//初始化一条染色体
public String initSingle(int GENE){
String res = "";
for(int i = 0; i < GENE; i++){
if(Math.random() < 0.5){
res += 0;
}else