克鲁斯卡尔算法//加边法
1:选择最短的边进行连接(此处的连接是连接最短边两端的点)
2:要保证连接的两端至少一个点是新的点
3:或者这个边将是两个部分进行连接(可以将已经连接的边看做是一个小部落,可以将两个小部落连接为一个大部落)
4:重复1-3的步骤直到所有的点都连接起来
如上图进行加边法
最短的边 4 也就是AB两点 符合步骤1 将两点连接
第二短的边 5 也就是CD两点 符合步骤1 将两点连接
第三短的边 6 也就是BD两点 符合步骤3 将两点连接
第四短的边 7 也就是 DE 两点 符合步骤2 将两点连接
let max = 999999;
let pointSet = []; //储存点
let distance = [
[0, 4, 7, max, max],
[4, 0, 8, 6, max],
[7, 8, 0, 5, max],
[max, 6, 5, 0, 7],
[max, max, max, 7, 0]
] // 将图的信息储存下来
class Node {
constructor(value) {
this.value = value;
this.neighbor = [];
}
}
let a = new Node('A');
let b = new Node('B');
let c = new Node('C');
let d = new Node('D');
let e = new Node('E');
pointSet.push(a)
pointSet.push(b)
pointSet.push(c)
pointSet.push(d)
pointSet.push(e)
/**
* 是否可以连接
* @param {*} firstMember 第一个部落
* @param {*} secondMember 第二个部落
* @param {*} tribeArr 所有的大部落 距离最近的两个部落可以合并成一个大部落,最后所有的部落合成一个部落
* @returns
*/
function isLink(firstMember, secondMember, tribeArr) {
let beforePoin = null;
let endPoin = null;
// 查看所属部落
// 当俩个都不属于任何部落进行连接
// 当其中一个有部落,另一个没可以进行连接
// 当为一个部落不能进行接连
// 当两个为同一个部落的话,无法进行连接
for (let i = 0; i < tribeArr.length; i++) {
if (tribeArr[i].indexOf(firstMember) > -1) {
beforePoin = tribeArr[i]
}
if (tribeArr[i].indexOf(secondMember) > -1) {
endPoin = tribeArr[i]
}
}
if (beforePoin!=null && endPoin != null&& beforePoin == endPoin) {
return false;
}
return true;
}
/**
* 将线两个端连接起来
* @param {*} firstMember 第一个部落
* @param {*} secondMember 第二个部落
* @param {*} tribeArr 所有的大部落 距离最近的两个部落可以合并成一个大部落,最后所有的部落合成一个部落
*/
function link(firstMember, secondMember, tribeArr) {
let beforePoin = null;
let endPoin = null;
// 查看所属部落
// 当俩个都不属于任何部落进行连接
// 当其中一个有部落,另一个没可以进行连接
// 当两个都有部落且部落不相同时可进行连接
// 当为一个部落不能进行接连
for (let i = 0; i < tribeArr.length; i++) {
if (tribeArr[i].indexOf(firstMember) > -1) {
beforePoin = tribeArr[i]
}
if (tribeArr[i].indexOf(secondMember) > -1) {
endPoin = tribeArr[i]
}
}
if (beforePoin == null && endPoin == null) {
//当俩个都不属于任何部落 创建一个部落 并将其记录在部落数组中
let tribe = []
tribe.push(firstMember)
tribe.push(secondMember)
tribeArr.push(tribe)
} else if (beforePoin != null && endPoin == null) {
// 当前一个有部落,后一个没部落,将后一个纳入部落
beforePoin.push(endPoin)
} else if (beforePoin == null && endPoin != null) {
// 当后一个有部落,前一个没部落,将第一个纳入部落
endPoin.push(beforePoin)
} else if (beforePoin != null && endPoin != null && beforePoin != endPoin) {
// 当俩个都有部落且部落不一样,将两个部落合并成一个部落
let newTribe = beforePoin.concat(endPoin)
let index = tribeArr.indexOf(endPoin)
tribeArr.splice(index, 1)
index = tribeArr.indexOf(beforePoin)
tribeArr.splice(index, 1)
tribeArr.push(newTribe)
}
firstMember.neighbor.push(secondMember)
secondMember.neighbor.push(firstMember)
}
/**
* 加边法
* @param {*} pointSet 所有点的集合
* @param {*} distance 所有线的集合
*/
function kruskal(pointSet, distance) {
let tribeArr = []
while (true) {
let minDistance = max;
let begin = null;
let end = null;
let nowValue = null;
for (let i = 0; i < distance.length; i++) {
for (let j = 0; j < distance[i].length; j++) {
nowValue = distance[i][j]
let firstMember = pointSet[i]
let secondMember = pointSet[j]
if (nowValue > 0 && nowValue < minDistance && isLink(firstMember, secondMember, tribeArr)) {
minDistance = nowValue;
begin = firstMember;
end = secondMember;
}
}
}
link(begin, end, tribeArr)
if (tribeArr.length == 1 && tribeArr[0].length == pointSet.length) {
break;
}
}
}
kruskal(pointSet, distance)
console.log(pointSet)