Kruskal算法实现最小生成树

Kruskal算法思想

  G=(V,E)是无向连通网,T=(U,TE)是G的最小生成树算法的基本思想是:初始状态为U=V、TE={ },即T中的顶点各自构成一个连通分量,然后按照边的权值由小到大的顺序,依次考察边E中的各条边。若被考察边的两个顶点属于两个不同的连通分量,则将此边加入到TE中,同时把两个连通分量连接为一个连通分量;若被考察边的两个顶点属于同一个连通分量,则舍去此边,以免造成回路,如此下去,当T中的连通分量个数为1时,此连通分量便为G的一棵最小 Kruskal生成树。

  相比于Prim的加点,Kruskal是通过加边实现最小生成树。即从所有边中选取权值最小的边,在满足加入条件后,将其的两个端点加入最小生成树。在被考察边的两个顶点是否位于两个联通分量(是否与生成树中的边形成回路)。如果如果将同一个连通分量的顶点放入一个集合中,则 Kruskal算法需要判断被考察边的两个顶点是否位于两个集合,以及将两个集合进行合并等操作。

Kruskal伪代码

算法: Kruskal算法
输入:无向连通网G=(V,E)
输出:最小生成树T=(U,TE)
1.初始化:U=V;TE={}
2.重复下述操作直到所有顶点位于一个连通分量
  2.1在E中选取最短边(u,v);
  2.2如果顶点u、v位于两个连通分量,则
     2.2.1将边(u,v)并入TE;
     2.2.2将这两个连通分量合成一个连通分量;
  2.3在E中标记边(u,v),使得(u,v)不参加后续最短边的选取;

Kruskal算法存储结构

  图的存储结构:因为 Kruskal算法依次对图中的边进行操作,因此考虑采用边集数组(edge set array)存储。为了提高查找最短边的速度,可以先对边集数组按边上的权值排序。

边集数组结构体定义:

struct
{
    int from;
    int to;
    int weight;
}

  连通分量的顶点所在的集合:由于涉及集合的查找和合并等操作,考虑采用并查集来实现。并查集是将集合中的元素组织成树的形式,合并两个集合,即将一个集合的根点作为另一个集合根结点的孩子。为了便于在并查集中进行查找和合并操作,树采用双亲表示法存储设数组parent[n],元素parent[i]表示顶点i的双亲(0≤i≤n-1)。初始时,令parent[i]=-1,表示顶点没有双亲,即每个集合只有一个元素。对于边(u,v),设vex1和vex2分别表示两个顶点所在集合的根,如果vex1≠vex2,则顶点和u和v一定位于两个集合,令 parent[vex2]=vex1,实现合并两个集合。

Kruskal实现最小生成树代码

#include<iostream>
using namespace std;

struct EdgeType //定义边集数组的元素类型
{
    int from, to, weight; //假设权值为整数
};

const int MaxVertex = 10; //图中最多顶点数
const int MaxEdge = 100; //图中最多边数
template //定义模板类
class EdgeGraph 
{
    public:
    EdgeGraph(DataType a[ ], int n, int e); //构造函数,生成n个顶点e条边的连通图
    ~EdgeGraph( ); //析构函数
    void Kruskal( ); //Kruskal算法求最小生成树
    private:
    int FindRoot(int parent[ ], int v); //求顶点v所在集合的根

    DataType vertex[MaxVertex]; //存储顶点的一维数组
    EdgeType edge[MaxEdge]; //存储边的边集数组
    int vertexNum, edgeNum; 
};

template 
EdgeGraph :: EdgeGraph(DataType a[ ], int n, int e)
{
    int i, j, k, w;
    vertexNum = n; edgeNum = e;
    for (i = 0; i < vertexNum; i++)
        vertex[i] = a[i];
    for (k = 0; k < edgeNum; k++)
    {
        cout << "请输入边依附的两个顶点的编号,以及边上的权值:";
        cin >> i >> j >> w; //输入边依附的两个顶点的编号
        edge[k].from = i; edge[k].to = j; edge[k].weight = w;
    }
}

template 
EdgeGraph :: ~EdgeGraph( ){}

template 
void EdgeGraph :: Kruskal( )
{
    int num = 0, i, vex1, vex2;
    int parent[vertexNum]; //双亲表示法存储并查集
    for (i = 0; i < vertexNum; i++)
        parent[i] = -1; //初始化n个连通分量
    for (num = 0, i = 0; num < vertexNum - 1; i++) //依次考察最短边
    {
        vex1 = FindRoot(parent, edge[i].from);
        vex2 = FindRoot(parent, edge[i].to);
        if (vex1 != vex2) { //位于不同的集合
            cout << "(" << edge[i].from << "," << edge[i].to << ")" << edge[i].weight << endl;
       parent[vex2] = vex1; //合并集合
       num++;
     }
  }
}

template 
int EdgeGraph :: FindRoot(int parent[ ], int v) //求顶点v所在集合的根
{
    int t = v;
    while (parent[t] > -1) //求顶点t的双亲一直到根
        t = parent[t]; 
    return t;
}

int main( )
{
    char ch[ ]={'A','B','C','D','E','F'}; 
    EdgeGraph EG{ch, 6, 9}; 
    EG.Kruskal( );
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Kruskal算法实现最小生成树的Python代码示例: ```python # 定义边的类 class Edge: def __init__(self, src, dest, weight): self.src = src self.dest = dest self.weight = weight # 定义并查集类 class UnionFind: def __init__(self, vertices): self.parent = {} self.rank = {} for v in vertices: self.parent[v] = v self.rank[v] = 0 def find(self, v): if self.parent[v] != v: self.parent[v] = self.find(self.parent[v]) return self.parent[v] def union(self, v1, v2): root1 = self.find(v1) root2 = self.find(v2) if self.rank[root1] < self.rank[root2]: self.parent[root1] = root2 elif self.rank[root1] > self.rank[root2]: self.parent[root2] = root1 else: self.parent[root2] = root1 self.rank[root1] += 1 # 定义最小生成树函数 def kruskal(graph): result = [] # 将的边按权重排序 graph.sort(key=lambda x: x.weight) # 获取中的所有顶点 vertices = set() for edge in graph: vertices.add(edge.src) vertices.add(edge.dest) # 创建并查集 uf = UnionFind(vertices) # 遍历的边 for edge in graph: root1 = uf.find(edge.src) root2 = uf.find(edge.dest) # 如果两个顶点的根节点不同,则将边加入最小生成树中 if root1 != root2: result.append(edge) uf.union(root1, root2) return result # 示例用法 graph = [ Edge('A', 'B', 4), Edge('A', 'H', 8), Edge('B', 'C', 8), Edge('B', 'H', 11), Edge('C', 'D', 7), Edge('C', 'F', 4), Edge('C', 'I', 2), Edge('D', 'E', 9), Edge('D', 'F', 14), Edge('E', 'F', 10), Edge('F', 'G', 2), Edge('G', 'H', 1), Edge('G', 'I', 6), Edge('H', 'I', 7) ] minimum_spanning_tree = kruskal(graph) for edge in minimum_spanning_tree: print(f"{edge.src} - {edge.dest}: {edge.weight}") ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值