Kruskal-最小生成树

Kruskal算法是寻找图中最小生成树的一种方法,它通过不断选取权值最小的边并判断是否连接不同连通分量来构建。文章介绍了算法的基本过程,并指出可以使用并查集和最小堆来优化实现。同时提供了面向邻接矩阵和邻接表的实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Kruskal算法的基本过程:任给一个有n个顶点的连通网络N={V,E},首先构造一个由这n个顶点组成、不含任何边的图T={V,\phi},其中每个顶点自成一个连通分量。不断从E中取出权值最小的一条边(若有多条,任取其一),若该边的两个端点来自不同的连通分量,则将此边加入到T中。如此重复,直到所有顶点在同一个连通分量上为止。

实现分析:

  • 由于需要不断判断两个端点是否来自同一个连通分量,否的话,两个连通分量的顶点并起来,这里可以用并查集实现。
  • 由于不断从边集中取出权值最小的一条边,这里可以用最小堆来实现。

下面提供面向邻接矩阵和面向邻接表的Kruskal算法实现:

//
//  main.cpp
//  Kruskal-最小生成树
//
//  Created by scnulpc on 2018/10/25.
//  Copyright © 2018年 scnulpc. All rights reserved.
//

#include <iostream>
#include <queue>
#define maxWeight 99
#define  size 100
using namespace std;
//邻接矩阵的存储结构
struct Edge {
    int v1,v2;
    int weight;
    Edge(int a,int b,int cost):v1(a),v2(b),weight(cost){}
    friend bool operator < (Edge a,Edge b)
    {
        return a.weight > b.weight;     //权重小的优先级高,构造最小堆
    }
};
int map[size][size];

//邻接表的存储结构
struct edge
{
    int dest;
    int weight;
    edge* link;
    edge(int a,int b):dest(a),weight(b),link(NULL){}
};
struct VertexNode
{
    int v;
    edge* adjacent;
    VertexNode(int a):v(a),adjacent(NULL){}
};

VertexNode* vertecies[size];


int  Find(int x,int *parent)
{
    if (parent[x]<0) return x;
    else return Find(parent[x], parent);
}
bool Union(int v1,int v2,int *parent)
{
    int num1 = Find(v1, parent);
    int num2 = Find(v2, parent);
    if (num1==num2&&num1!=-1) return false;
    if (num1<num2) {
        parent[num1] += parent[num2];
        parent[num2] = num1;
    }
    else
    {
        parent[num2]+=parent[num1];
        parent[num1] = num2;
    }
    return true;
}
//基于邻接矩阵的有权无向图的Kruskal算法
void Kruskal(int n)
{
    priority_queue<Edge> q;
    int UFSet[n];
    
    for (int i=0; i<n; i++)
    {UFSet[i]=-1;}
    
    for (int i=0; i<n; i++)
    {
        for (int j=i+1; j<n; j++) {
            if (map[i][j]>0&&map[i][j]<maxWeight)
            {
                q.push(*(new Edge(i,j,map[i][j])));
            }
        }
    }                                               //上面都是准备工作,初始化并查集,所有边入最小堆
    int vertex = 1;
    while (vertex!=n&&!q.empty())
    {
        Edge top = q.top();q.pop();
        if(Union(top.v1, top.v2, UFSet)) vertex++;
    }
    if (vertex==n) cout<<"最小生成树已生成"<<endl;  //这个判断条件也可以为 是否存在这样的n-1条边,把n个顶点连接起来
    else cout<<"不存在最小生成树"<<endl;
}

//基于邻接表有权无向图(有向图)的Kruskal算法
void Kruskal1(int n)
{
    priority_queue<Edge> q;
    int UFSet[n];
    for (int i=0; i<n; i++)
        UFSet[i]=-1;
    for (int i=0; i<n; i++)
    {
        edge* p = vertecies[i]->adjacent;
        while (p!=NULL) {
            q.push(*(new Edge(i,p->dest,p->weight)));  //如果为无向图,这里可以改进,判断边的重复,进一半的边
            p=p->link;
        }
    }
    int numEdge = 0;
    int count = 1;
    while (count!=n&&!q.empty())
    {
        Edge temp = q.top();q.pop();
        if (Union(temp.v1, temp.v2, UFSet)) {
            numEdge++;
        }
    }
    if (numEdge==n-1) {
        cout<<"最小生成树存在"<<endl;
    }
    else
    {
        cout<<"最小生成树不存在"<<endl;
    }
}
/*
 测试数据
 0 1 99 3 99
 1 0 2 4 99
 99 2 0 99 99
 3 99 99 0 5
 99 99 99 5 0
 */
int main(int argc, const char * argv[])
{
    int n=5;
    
    for (int i=0; i<n; i++) {
        for (int j=0; j<n; j++) {
            cin>>map[i][j];
        }
    }
    Kruskal(n);
    for (int i=0; i<n; i++) {
        vertecies[i] = new VertexNode(i);
    }
    vertecies[0]->adjacent = new edge(1,1);
    vertecies[0]->adjacent->link = new edge(3,3);
    vertecies[1]->adjacent = new edge(0,1);
    vertecies[1]->adjacent->link = new edge(2,2);
    vertecies[1]->adjacent->link->link = new edge(3,4);
    vertecies[2]->adjacent = new edge(1,2);
    vertecies[3]->adjacent = new edge(0,3);
    vertecies[3]->adjacent->link = new edge(4,5);
    vertecies[4]->adjacent = new edge(3,5);
    Kruskal1(n);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值