算法学习记录(十四)

110 阅读1分钟

问:

  1. prim算法求最小生成树。
  2. kruskal算法求最小生成树。

解:

  1. 从某个节点开始,把它的所有边放入小根堆结构,选出最小边,如果最小边链接的节点没出现过,就把这个节点重复上述过程
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
    }