连载之六
染色体的编码
3.4.1 为染色体编码(Ecoding the Chromosome)
每个染色体必须把小人Bob 的每一个行动编入代码中。Bob的行动仅限为4个方向: 向东(East),向南(South),向西(West),向北(North) 故编码后的染色体应该就是代表这4个方向信息的一个字符串。传统的编码方法就是把方 向变换成二进制的代码。四个方向只要2位就够了,例如下表所示的那样:
二进制代码 | 十进制译码 | 代表的方向 |
00 | 0 | 向北 |
01 | 1 | 向南 |
10 | 2 | 向东 |
11 | 3 | 向西 |
二进制代码 | 十进制译码 | 代表的方向 |
11 | 3 | West |
11 | 3 | West |
10 | 2 | East |
01 | 1 | South |
10 | 2 | East |
11 | 3 | West |
10 | 2 | East |
11 | 3 | West |
10 | 2 | East |
01 | 1 | South |
01 | 1 | South |
01 | 1 | South |
struct SGenome
{
vector <int> vecBits;
double dFitness;
SGenome():dFitness(0){}
SGenome(const int num_bits):dFitness(0)
{
//创造随机二进制位串
for (int i=0; i<num_bits; ++i)
{
vecBits.push_back(RandInt(0,1));
}
}
};
正如你能见到的那样,如果你在创建Sgenome对象时把一个整型数作为参数 传递给构造函数,则它就会自动创建一个以此整数为长度的随机2进制位串, 并将其适应性分数初始化为零,这样就把基因组什么都准备好了。 程序注释 std::vector是STL(Standard Templete Library)标准模板库的一部分, 这是一种为处理动态数组而预先建立好的类。如果要把数据加入STL中,可使用 push_back()方法。 下面是一个简单的例子:
#include <vector> for (int i=0; i<10; i++) { MyFirstVector.push_back(i); cout << endl << MyFirstVector[i]; } 要清空一个向量,使用clear()方法:
MyFirstVector.clear();
你可利用size()方法来得到向量中元素的数目: NyFirstVector.size() 就是这样。 不需要你去考虑内存管理问题-std::vector能够为你来做所有这些!当需要 时,我会在整个程序中使用它。 SGenome结构中不具备怎样为染色体(vecBits)进行译码的知识; 这是需要 由遗传算法类自己来完成的一项任务。现在让我们来快速窥视一下这个类的定义。 我已把它称作CgaBob类(有时我对我的原始创见自己也很吃惊,但我确实是这样 做的)。
class CgaBob
{
private:
//基因组群体
vector<SGenome> m_vecGenomes //群体的大小 int m_iPopSize double m_dCrossoverRate; double m_dMutationRate; //每个染色体含有多少bits int m_iChromoLength; //每个基因有多少bits int m_iGeneLength; int m_iFittestGenome; double m_dBestFitnessScore; double m_dTotalFitnessScore; int m_iGeneration; //为 map 类创建一个实例 CBobsMap m_BobsMap; //另一个CbobsMap对象用来保存每一代的最佳路径的一个记录,这是被访问小
//格的一个数组,它仅仅是为了显示目的而使用的。 CBobsMap m_BobsBrain; //让你知道运行是否仍在进行中 bool m_bBusy; void Mutate(vector<int>&vecBits); void Crossover(const vector<int>&mum, const vector<int>&dad, vector<int>&baby1, vector<int>&baby2); SGenome& RouletteWheel Selection(); //用新的适应性分数来更新基因组原有的适应性分数,并 //计算群体的最高适应性分数和适应性分数最高的那个成员。 void UpdateFitnessScores(); //把一个位向量译成为一个方向的(整数)向量 vector<int> Decode(const vector<int> &bits); //把一个位向量变换为十进制数。用于译码 int BinToInt(const vector<int> &v); //创建一个随机的二进制位串的初始群体 void CreateStartPopulation(); public: CgaBob(double cross_rat, double mut_rat, int pop_size, int num_bits, int gene_len):m_dCrossoverRate(cross_rat), m_dMutationRate(mut_rat), m_iPopSize(pop_size), m_iChromoLength(num_bits), m_dTotalFitnessScore(0.0), m_iGeneration(0), m_iGeneLength(gene_len), m_bBusy(false) { CreateStartPopulation(); } void Run(HNND hwnd); void Epoch(); void Render(int cxClient, int cyClient, HDC surface); //访问用的方法 int Generation(){return m_iGeneration;} int GetFittest(){return m_iFittestGenome;} bool Started(){return m_bBusy;} void Stop(){m_bBusy = false;} };
由上你可看出,当这个类的一个实例被创建时,构造函数初始化所有的变量,
并调用CreateStartPopulation()。这一短小函数创建了所需数量的基因组群体。
每个基因组一开始包含的是一个由随机2进制位串组成的染色体,其适应性分数则
被设置为零。
转载于:https://my.oschina.net/dake/blog/196829