图
问:
- prim算法求最小生成树。
- kruskal算法求最小生成树。
解:
- 从某个节点开始,把它的所有边放入小根堆结构,选出最小边,如果最小边链接的节点没出现过,就把这个节点重复上述过程
function prim(graph) {
const nodes = graph.nodes
const res = []
const nodeSet = new Set()
const edgesArr = []
for (let i of nodes) {
// 可能存在点不连通的情况,所以每个点都执行一遍
const queue = [nodes[i]]
while (queue.length) {
const curNode = queue.shift()
// 把节点放入nodeSet
if (!nodeSet.has(curNode)) {
nodeSet.add(curNode)
res.push(curNode)
}
// 遍历这个节点所有边,放入edgesArr并转为小根堆
curNode.edges.forEach((item) => {
if (!edgesArr.includes(item)) {
edgesArr.push(curNode)
heapInsert(edgesArr.length - 1,edgesArr)
}
})
// 找到最小的边,如果不是闭环,就加进res
const minEdge = edgesArr.shift()
if (!nodeSet.has(minEdge.to)) {
nodeSet.add(minEdge.to)
res.push(minEdge.to)
queue.push(minEdge.to)
}
}
}
return res
}
function heapInsert(idx, arr) {
// 若当前值小于自己的父节点就和父节点交换位置
while (arr[idx].weight < arr[Math.floor((idx - 1) / 2)].weight) {
[arr[idx],arr[Math.floor((idx - 1) / 2)]] = [arr[Math.floor((idx - 1) / 2)],arr[idx]]
idx = Math.floor((idx - 1) / 2)
}
}
function kruskal(graph) {
const nodes = graph.nodes
const edges = graph.edges
// 记录每个node指向的集合
const nodeMap = new Map()
const res = []
// 把边集合按权重从小到大排序
edges.sort((a, b) => a.weight - b.weight)
// 给每个node创建一个集合表明这个node属于哪个集合
nodes.forEach(item => {
const self = [item]
nodeMap.set(item, self)
})
while (edges.length) {
const minEdge = edges.shift()
const { to, from } = minEdge
// 如果两个节点不属于同一集合,求并集,并且把nodeMap中这两个节点指向用一个并集
if (nodeMap.get(to) !== nodeMap.get(from)) {
const union = nodeMap.get(to).concat(nodeMap.get(from))
nodeMap.set(to, union)
nodeMap.set(from, union)
if (!res.includes(to)) res.push(to)
if (!res.includes(from)) res.push(from)
}
}
return res
}