遺傳算法 (GA) 是啟發式優化算法,模擬自然選擇與遺傳機制。本文提供一個**教學級完整實現**:5 位二進制編碼、適應度函數 f(x)=x³-60x²+900x+100、輪盤賭選擇、單點交叉 (pc=0.9)、位翻轉變異 (pm=0.05)、20 代演化,搜索定義域 [0,31] 的最大值。
const int L = 5; // 染色體長度 (2^5=32 覆蓋 0~31)
const int POP_SIZE = 8; // 種群大小
const int MAX_GEN = 20; // 最大代數
const double P_CROSS = 0.90;
const double P_MUT = 0.05;
f(x) 值越大越優。pc 概率隨機選擇交叉點 (1~L-1),交換高位片段。pm 概率翻轉 (0↔1),使用 std::bitset<L> 便捷操作。int fitness(int x) { return x*x*x - 60*x*x + 900*x + 100; }
double sum = 0;
for (int v : pop) sum += fitness(v);
double[] cumProb = new double[POP_SIZE];
for (int i = 0; i < POP_SIZE; i++) {
cumProb[i] = (i==0) ? fitness(pop[i])/sum : cumProb[i-1] + fitness(pop[i])/sum;
}
for (int i = 0; i < POP_SIZE; i++) {
double r = rand() / (double)RAND_MAX;
int selected = 0;
while (selected < POP_SIZE && r > cumProb[selected]) selected++;
matingPool[i] = pop[selected];
}
void crossover(int &a, int &b) {
int point = rand() % L + 1; // 1..L
bitset A(a), B(b), C, D;
for (int i = 0; i < point; i++) { if (A[i]) C.set(i); if (B[i]) D.set(i); }
for (int i = point; i < L; i++) { if (B[i]) C.set(i); if (A[i]) D.set(i); }
a = (int)C.to_ulong(); b = (int)D.to_ulong();
}
for (int &ind : pop) {
bitset b(ind);
for (int i = 0; i < L; i++)
if (rand()/(double)RAND_MAX < P_MUT) b.flip(i);
ind = (int)b.to_ulong();
}
初始種群: 12 5 23 18 2 29 7 14
繁殖代數: t=0 ... t=20
最終結果: 30 30 30 30 30 30 30 30 (收斂到 x=30, f(30)=1000 附近最大值)
| 環節 | 關鍵點 | 常見錯誤 |
|---|---|---|
| 編碼長度 | 需覆蓋定義域上限 (2^L > max) | L 太小導致搜索空間不足 |
| 輪盤賭 | 累積概率必須歸一化到 1.0 | 未歸一化導致選擇失效 |
| 交叉點 | 1..L-1,不可 0 或 L | point=0 導致無交換 |
| 變異率 | pm 過大退化為隨機搜索,過小早熟 | pm=0 或 >0.2 |
| bitset 索引 | 最低位 index=0 對應 2^0 | 高低位混淆 |
這個 150 行左右的 C++ GA 完整演示了「編碼→適應度→選擇→交叉→變異→迭代」核心流程。通過 bitset 封裝位運算,代碼既清晰又高效。作為進階學習 NSGA-II、CMA-ES、差分進化等現代演化算法的基石極為合適。