📜  数据结构-生成树(1)

📅  最后修改于: 2023-12-03 15:26:09.262000             🧑  作者: Mango

数据结构-生成树

在计算机科学中,生成树是一个连通无向图的生成子图,它包含了图中所有顶点,并且是一棵树。生成树通常用于研究网络中的广播通信和计算最小成本基础设施等问题。

常见的生成树算法
Kruskal 算法

Kruskal 算法是一种贪心算法,用于查找加权无向图的最小生成树。这个算法和 Prim 算法类似,通过选择边加入生成树,但是不同的是,Kruskal 算法不需要选择一个根节点,而是选择一组边使它们构成一个森林,然后逐步合并其中的树。在构建这个森林期间,算法会选取图中边权值最小的边,并且不选择那些连接已经在同一个树中的两个节点的边。最终生成的森林会变成一棵树,也就是我们所要找的最小生成树。

Prim 算法

Prim 算法也是一种贪心算法,用于查找加权无向图的最小生成树。这个算法需要选择一个根节点,然后从它开始逐步扩展,直到生成整个子图为止。在扩展每个节点的过程中,算法会选取与已有节点之间边权值最小的边,以此添加新的节点到已有的树中。最终生成的树就是我们所要找的最小生成树。

示例代码
Kruskal 算法
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.size = [1] * n

    def find(self, x):
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return False
        if self.size[px] < self.size[py]:
            px, py = py, px
        self.parent[py] = px
        self.size[px] += self.size[py]
        return True

def kruskal(n, edges):
    uf = UnionFind(n)
    result = []
    for weight, u, v in sorted(edges):
        if uf.union(u, v):
            result.append((weight, u, v))
            if len(result) == n - 1:
                break
    return result

n = 6
edges = [(1, 0, 1), (5, 0, 2), (3, 2, 3), (2, 1, 2), (4, 3, 4), (6, 4, 5)]
result = kruskal(n, edges)
print(result)  # [(1, 0, 1), (2, 1, 2), (3, 2, 3), (4, 3, 4), (5, 0, 2)]
Prim 算法
from heapq import heappop, heappush

def prim(n, adj):
    visited = [0] * n
    q = [(0, 0)]
    result = []
    while q:
        weight, u = heappop(q)
        if visited[u]:
            continue
        visited[u] = 1
        result.append((weight, u))
        for v, w in adj[u]:
            if not visited[v]:
                heappush(q, (w, v))
    return result

n = 6
adj = [[] for _ in range(n)]
adj[0].append((1, 1))
adj[0].append((5, 2))
adj[1].append((2, 2))
adj[1].append((1, 0))
adj[2].append((3, 3))
adj[2].append((2, 1))
adj[3].append((3, 2))
adj[3].append((4, 4))
adj[4].append((6, 5))
adj[5].append((6, 4))
result = prim(n, adj)
print(result)  # [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (6, 5)]

以上代码给出了 Kruskal 算法和 Prim 算法的 Python 示例实现。其中,Kruskal 算法使用了并查集来实现集合合并和查找操作,Prim 算法则使用了堆来实现找到下一个要加入树中的边。