把构造连通网的最小代价生成树称为最小生成树。经典的算法有两种,普利姆算法和克鲁斯卡尔算法。
一、普利姆算法 (Prim算法)
先选择其中一个点,把该顶点的边加入数组。
再按照权值最小的原则选边,选完最小权值的边,把所选边的另一顶点的边加入数组。
再选权值最小的边,如此循环(有多少顶点循环多少次)。
function Node(value) {
this.value = value;
this.neighbor = [];
this.distance = [];
}
const a = new Node("A");
const b = new Node("B");
const c = new Node("C");
const d = new Node("D");
const e = new Node("E");
let max = Number.POSITIVE_INFINITY; //无穷大;
let pointSet = [a, b, c, d, e];
let distance = [
[0, 3, max, 2, max],
[3, 0, 5, max, max],
[max, 5, 0, 7, 1],
[2, max, 7, 0, 2],
[max, max, 1, 2, 0]
];
function getMinPoint(pointSet, distance, nowPointSet) {
let fromNode = null;//起始节点
let endNode = null;//终止节点
let minDistance = max;//最小距离默认为max
for(let i = 0; i < nowPointSet.length; i ++) { //遍历已连接的点
let nowPointIndex = getIndex(nowPointSet[i].value); //获取已连接节点在pointSet中的索引值 拿到序号
let pointDistance = distance[nowPointIndex]; //通过nowPointIndex找到该连接节点对应所有边的开销
for(let j = 0; j < pointDistance.length; j ++) { //遍历所有边的开销 遍历一整行
let thisNode = pointSet[j]; //行里的每个节点
if (nowPointSet.indexOf(thisNode) < 0 //最小距离连接的节点不能在nowPointSet中 && 要小于minDistance
&& pointDistance[j] < minDistance) {
fromNode = nowPointSet[i];
endNode = thisNode;
minDistance = pointDistance[j];
}
}
}
fromNode.neighbor.push(endNode);//起始节点 将开销最小的节点加入
fromNode.distance.push({//起始节点 将开销最小的节点的值和距离加入
from: fromNode.value,
to: endNode.value,
distance: minDistance
});
endNode.neighbor.push(fromNode);
endNode.distance.push({
from: fromNode.value,
to: endNode.value,
distance: minDistance
});
return endNode;//返回开销最小的节点
}
function getIndex(str) {
for (var i = 0; i < pointSet.length; i++) {
if (str == pointSet[i].value) {
return i;
}
}
return -1;
}
function prim(pointSet, distance, start) {
let nowPointSet = [];
nowPointSet.push(start); //将开始节点放入已连接数组中
while(true) {
let minPoint = getMinPoint(pointSet, distance, nowPointSet); //通过已连接节点,找到和它们相连接开销最小的节点
nowPointSet.push(minPoint); //将开销最小的节点加入已连接数组中
if(pointSet.length == nowPointSet.length) break; //所有节点都连接,跳出循环
}
console.log(nowPointSet);
}
prim(pointSet, distance, pointSet[2]);
// [
// Node { value: 'C', neighbor: [ [Node] ], distance: [ [Object] ] },
// Node {
// value: 'E',
// neighbor: [ [Node], [Node] ],
// distance: [ [Object], [Object] ]
// },
// Node {
// value: 'D',
// neighbor: [ [Node], [Node] ],
// distance: [ [Object], [Object] ]
// },
// Node {
// value: 'A',
// neighbor: [ [Node], [Node] ],
// distance: [ [Object], [Object] ]
// },
// Node { value: 'B', neighbor: [ [Node] ], distance: [ [Object] ] }
// ]
二、克鲁斯卡尔算法