📜  生成树和最小生成树(1)

📅  最后修改于: 2023-12-03 14:56:16.882000             🧑  作者: Mango

生成树和最小生成树

什么是生成树

生成树是指在一个连通图中,选取一些边和顶点,形成一个不包含回路的子图,即生成树。生成树包含原图所有顶点,但只包含足以支撑这个图的边。

生成树的应用

生成树有很多实际的应用。其中一些:

  1. 网络设计:用生成树来连通网络,保证每个节点都可以被访问到。

  2. 最优化问题:在一些最优化问题中,我们需要分别找到最大和最小的生成树,来寻找最优的方案。

最小生成树

与生成树相似,最小生成树也是一个连通图的子图。最小生成树是指其边的总权值最小的生成树。

最小生成树的应用

最小生成树也有很多实际的应用。其中一些:

  1. 网络设计:用最小生成树来连接所有的节点,保证网络的总成本最小。

  2. 群体聚类:将数据集聚类成若干子集时,使用最小生成树提取共性。

常用算法
Kruskal算法

Kruskal算法是解决最小生成树问题的一个经典算法。它的思路是先将所有边按权值从小到大排序,对于每个边,若该边所连接的两个节点不在同一个集合中,就将这两个节点所在的集合合并,并将该边加入最小生成树中。重复此过程,直到所有的边都被加入最小生成树为止。

def find(parent, i):
    if parent[i] == i:
        return i
    return find(parent, parent[i])

def union(parent, rank, x, y):
    xroot = find(parent, x)
    yroot = find(parent, y)

    if rank[xroot] < rank[yroot]:
        parent[xroot] = yroot
    elif rank[xroot] > rank[yroot]:
        parent[yroot] = xroot
    else :
        parent[yroot] = xroot
        rank[xroot] += 1

def kruskalMST(graph, V):
    result =[] # 存储最小生成树的边
    i = 0 # 排序后的边下标
    e = 0 # 已经添加到最小生成树中的边的数量

    graph =  sorted(graph,key=lambda item: item[2]) # 根据权值排序的边列表

    parent = [] ; rank = []

    for node in range(V):
        parent.append(node)
        rank.append(0)

    while e < V -1 :
        u,v,w =  graph[i]
        i = i + 1
        x = find(parent, u)
        y = find(parent ,v)

        if x != y:
            e = e + 1
            result.append([u,v,w])
            union(parent, rank, x, y)

    return result
Prim算法

Prim算法也是解决最小生成树问题的一个经典算法。它的思路是从一个节点开始,每次选择与当前生成树相邻的最小边加入最小生成树,直到所有节点都在最小生成树中为止。

import sys


class Graph():

    def __init__(self, vertices):
        self.V = vertices
        self.graph = [[0 for column in range(vertices)]
                      for row in range(vertices)]

    def printMST(self, parent):
        print("Edge \tWeight")
        for i in range(1, self.V):
            print(parent[i], "-", i, "\t", self.graph[i][ parent[i] ])

    def minKey(self, key, mstSet):

        min = sys.maxsize # 初始化最小值
        for v in range(self.V):
            if key[v] < min and mstSet[v] == False:
                min = key[v]
                min_index = v

        return min_index

    def primMST(self):

        key = [sys.maxsize] * self.V # 最小边的权值列表
        parent = [None] * self.V # 存储最小生成树中节点的父节点
        key[0] = 0 # 0号节点是根节点
        mstSet = [False] * self.V

        parent[0] = -1  # 初始化根节点为-1

        for cout in range(self.V):

            u = self.minKey(key, mstSet) # 从未处理的节点中选取一个最小的节点
            mstSet[u] = True # 标记该节点已经处理过了

            for v in range(self.V):

                if self.graph[u][v] > 0 and mstSet[v] == False and key[v] > self.graph[u][v]:

                    key[v] = self.graph[u][v]
                    parent[v] = u

        self.printMST(parent)


g = Graph(5)
g.graph = [[0, 2, 0, 6, 0],
           [2, 0, 3, 8, 5],
           [0, 3, 0, 0, 7],
           [6, 8, 0, 0, 9],
           [0, 5, 7, 9, 0]]

g.primMST();