交叉的是这道题里的第二个难点,由于序列交叉会导致一个工件在一个顺序中出现两次,而有的工件会没有被排序,导致顺序不存在。我们要设计算法去避免交叉带来的重复问题。
var FUSION_NUM = 3;
// 发生交叉时,交换的序列数
fusion(poor
, POOR_SIZE, SUVIVAL_SIZE, FUSION_NUM, WORKPIECE_NUM);
/** 进行个体交叉
* @param {*} poor 种群池
* @param {*} poor_size 种群池的大小(自然环境的容量)(流程顺序方案数目)
* @param {*} surival_size 自然选择下存活的方案数(最优的n种解决方案)
* @param {*} fusion_num 发生交叉时,交换的序列数
* @param {*} workpiece_num 总共要完成的零件数目(也是每个个体的基因数)
*/
function fusion(poor
, poor_size
, surival_size
, fusion_num
, workpiece_num
) {
var poor_p
= surival_size
; // 位置标记,要被修改的组的位置
// 将幸存区里的每两个进行交叉
for(var i
=0; i
<surival_size
; i
++){
for(var j
=i
+1; j
<surival_size
; j
++){
// 随机生成一个位置,将两个个体的一段进行交换
var fusion_pos
= random(workpiece_num
-fusion_num
+1);
// 交叉生成两个新的个体
createNew(poor
, workpiece_num
, fusion_num
, fusion_pos
, i
, j
, poor_p
);
poor_p
= poor_p
+1;
createNew(poor
, workpiece_num
, fusion_num
, fusion_pos
, j
, i
, poor_p
);
poor_p
= poor_p
+1;
}
}
}
/** 创建一个新的个体, 这个个体由 i 加入部分 j 构成
* @param {二维数组} poor 种群池
* @param {Int} fusion_pos 交叉标志位, 从交叉标记位开始,往后的n个会被替换,n为交换的序列数,是个常量
* @param {Int} workpiece_num 一个体的所拥有的基因数(工件的数目)
* @param {Int} i 初始个体i, i是一个int
* @param {Int} j 初始个体i, j是一个int
* @param {Int} poor_p 目标个体poor_p,新产生的个体数据会被放到这个个体中
*/
function createNew(poor
,workpiece_num
, fusion_num
, fusion_pos
, i
, j
, poor_p
){
var kk_p
= fusion_pos
; // 记录这个位置,用于更高效的完成循环
// 构建第一个新的数组(个体)
for(var ii
=0; ii
<workpiece_num
; ii
++){
if(ii
<fusion_pos
|| ii
>= fusion_pos
+ fusion_num
){ // 如果是非交换的位置
var is_repeat
= false; // 数据重复标志位
for(var jj
= fusion_pos
; jj
< fusion_num
+fusion_pos
; jj
++){
if(poor
[i
][ii
] == poor
[j
][jj
]){ // 如果要交换的位置检查出了重复
is_repeat
= true;
for(var kk
=kk_p
; kk
< fusion_num
+fusion_pos
; kk
++){ // 就从要交换过去的位置里去找一个替换部分不一样的,用这个数来消除重复
var is_repeat2
= false; // 数据重复标志位
for(var iii
= fusion_pos
; iii
< fusion_num
+fusion_pos
; iii
++){
if(poor
[i
][kk
] == poor
[j
][iii
]){ // 如果在交替部分发生重复就不用考虑这一位了
is_repeat2
= true;
kk_p
++; break;
}
}
if(!is_repeat2
){ // 如果不是重复的,
poor
[poor_p
][ii
] = poor
[i
][kk
]; // 我们就将这个基因赋值给新的个体
kk_p
++;break; // kk的起始位置 +1
}
}
}
}
if(!is_repeat
){ // 两个交换的部分没有重复,代表这个数会在原数列的非交换部分出现。
poor
[poor_p
][ii
] = poor
[i
][ii
];
}
}else{ // 如果是两序列相互交换的位置就直接交换
poor
[poor_p
][ii
] = poor
[j
][ii
];
}
}
}
7、变异