遗传算法是解决复杂问题的一种搜索策略,是一种智能计算。他模拟自然界中的种群进化。从这点看,它和神经网络这些算法的起源很像,都是使用计算机去模拟一些自然法则和运作规律。同样,和神经网络一样,遗传算法也是一种基于概率的算法。当然,在现代启发式算法中,很多算法都都是基于概率的,比如神经网络,粒子群算法,模拟退火等。这类方法的要解决的一个问题就是NP问题,要求得结果是满意解,而非最优解。理解这点,我觉得很重要。
本文中的GA实现的例子来自于http://www.theprojectspot.com/tutorial-post/creating-a-genetic-algorithm-for-beginners/3 一文。有兴趣的读者,也可以参考原文的实现。
遗传算法工作的时候,可以分为以下几个步骤:
1.初始化:首先需要初始化一个种群,大小可以根据需要随意,几个个体或者几千个个体都可以。种群的中个体的产生是随机的。
2.评估:每一个种群成员需要计算他们的适应度,就和自然界里的生物对自然环境的适应度一样。这里的适应度计算是一个关键,一个基本原则是,把对解决当前问题有意义的个体的适应度应该设置得比较高,否则应该给一个低的适应度。适应度计算函数很影响遗传算法性能。因为每一次进化,每一次迭代,每一个个体都要不停得被评估,如果这个方法很慢,搜索性能就会比较差。
3.选择:选择适应度比较高的个体进入下一个进化阶段。适应度低的可以抛弃。
4.交叉:将选中的个体进行基因交叉,产生下一代种群。这个过程就和自然界中生物体有性生殖一样,做DNA的交叉。
5.变异:和自然界一样,DNA是会变异的,变异操作可以帮助我们跳出局部最优。
6.重复:不停重复以上评估、选择、交叉、变异,直到找到一个满意的个体作为算法的最终解。
下面来看一个实现,首先看一下个体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | package simpleGa ; public class Individual { static int defaultGeneLength = 64 ; // 随机的个体 // Use this if you want to create individuals with different gene lengths public void setGene ( int index, byte value ) { public int size ( ) { public int getFitness ( ) { @Override |
每一个个体需要计算它的适应度:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package simpleGa ; public class FitnessCalc { static byte [ ] solution = new byte [ 64 ] ; // 设置一个候选解 // 设置一个候选解 就是参数类型不一样,这里做个转换 // 计算某一个个体的适应度 |
基于个体而产生的种群:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package simpleGa ; public class Population { Individual [ ] individuals ; public Individual getIndividual ( int index ) { public Individual getFittest ( ) { // Get population size // Save individual |
基于以上的个体和种群,就可以进行遗传算法的主要工作,交叉,变异等等。来看一下核心的算法实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | package simpleGa ; public class Algorithm { private static final double uniformRate = 0.5 ; // 保留最优秀的个体 // 变异 return newPopulation ; // 交叉 // 变异 // 选择用于交叉的个体,确保最差的个体不会进来 |
以上就是全部的实现,最后,测试这些代码