数据结构与算法C++之最小生成树问题 Kruskal

下面是 Kruskal 算法实现最小生成树
(1)下面是有权无向图,初始边的连接如下图
在这里插入图片描述
(2)对上图的权重按照从小到大排序,如下图
在这里插入图片描述
(3)按照权重从小到大寻找边,只要不形成环该权重边就符合要求,如下图前5个标为红色的都没有形成环,而边1-3会形成环,舍弃,1-5也会形成环,舍弃,4-5不会形成环,保留,边2-6不会形成环,保留,下图标红的形成最小生成树
在这里插入图片描述
在这里插入图片描述
使用堆实现权重排序

#include <iostream>
#include <iomanip>
#include <vector>
#include <ctime>
#include <string>
#include "DenseGraph.h"
#include "SparseGraph.h"
#include "ReadGraph.h"
#include "LazyPrimMST.h"
#include "PrimMST.h"
#include "KruskalMST.h"

using namespace std;

int main() {

    string filename1 = "testG1.txt";
    int V1 = 8;

    string filename2 = "testG2.txt";
    int V2 = 250;

    string filename3 = "testG3.txt";
    int V3 = 1000;

    string filename4 = "testG4.txt";
    int V4 = 10000;


    SparseGraph<double> g1 = SparseGraph<double>(V1, false);
    ReadGraph<SparseGraph<double>, double> readGraph1(g1, filename1);
    cout<<filename1<<" load successfully."<<endl;

    SparseGraph<double> g2 = SparseGraph<double>(V2, false);
    ReadGraph<SparseGraph<double>,double> readGraph2(g2, filename2);
    cout<<filename2<<" load successfully."<<endl;

    SparseGraph<double> g3 = SparseGraph<double>(V3, false);
    ReadGraph<SparseGraph<double>,double> readGraph3(g3, filename3);
    cout<<filename3<<" load successfully."<<endl;

    SparseGraph<double> g4 = SparseGraph<double>(V4, false);
    ReadGraph<SparseGraph<double>,double> readGraph4(g4, filename4);
    cout<<filename4<<" load successfully."<<endl;

    cout<<endl;


    clock_t startTime, endTime;

    // Test Lazy Prim MST
    cout<<"Test Lazy Prim MST:"<<endl;

    startTime = clock();
    LazyPrimMST<SparseGraph<double>, double> lazyPrimMST1(g1);
    endTime = clock();
    cout<<"Test for G1: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    startTime = clock();
    LazyPrimMST<SparseGraph<double>, double> lazyPrimMST2(g2);
    endTime = clock();
    cout<<"Test for G2: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    startTime = clock();
    LazyPrimMST<SparseGraph<double>, double> lazyPrimMST3(g3);
    endTime = clock();
    cout<<"Test for G3: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    startTime = clock();
    LazyPrimMST<SparseGraph<double>, double> lazyPrimMST4(g4);
    endTime = clock();
    cout<<"Test for G4: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    cout<<endl;


    // Test Prim MST
    cout<<"Test Prim MST:"<<endl;

    startTime = clock();
    PrimMST<SparseGraph<double>, double> PrimMST1(g1);
    endTime = clock();
    cout<<"Test for G1: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    startTime = clock();
    PrimMST<SparseGraph<double>, double> PrimMST2(g2);
    endTime = clock();
    cout<<"Test for G2: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    startTime = clock();
    PrimMST<SparseGraph<double>, double> PrimMST3(g3);
    endTime = clock();
    cout<<"Test for G3: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    SparseGraph<double> g5 = SparseGraph<double>(V4, false);
    ReadGraph<SparseGraph<double>,double> readGraph5(g5, filename4);

    startTime = clock();
    PrimMST<SparseGraph<double>, double> PrimMST4(g5);
    endTime = clock();
    cout<<"Test for G4: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    cout<<endl;


    // Test Kruskal MST
    cout<<"Test Kruskal MST:"<<endl;

    startTime = clock();
    KruskalMST<SparseGraph<double>, double> KruskalMST1(g1);
    endTime = clock();
    cout<<"Test for G1: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    startTime = clock();
    KruskalMST<SparseGraph<double>, double> KruskalMST2(g2);
    endTime = clock();
    cout<<"Test for G2: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    startTime = clock();
    KruskalMST<SparseGraph<double>, double> KruskalMST3(g3);
    endTime = clock();
    cout<<"Test for G3: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;

    startTime = clock();
    KruskalMST<SparseGraph<double>, double> KruskalMST4(g4);
    endTime = clock();
    cout<<"Test for G4: "<<(double)(endTime-startTime)/CLOCKS_PER_SEC<<" s."<<endl;


    return 0;
}

KruskalMST.h

#include <iostream>
#include <vector>
#include "UF.h"

#ifndef _EDGE_H_
#define _EDGE_H_
#include "Edge.h"
#endif

#ifndef _MINHEAP_H_
#define _MINHEAP_H_
#include "MinHeap.h"
#endif

using namespace std;

template <typename Graph, typename Weight>
class KruskalMST{

private:
    vector< Edge<Weight> > mst;
    Weight mstWeight;

public:

    KruskalMST(Graph &graph){
        MinHeap< Edge<Weight> > pq( graph.E() );
        for ( int i = 0; i < graph.V(); i++ ){
            typename Graph::adjIterator adj(graph, i);
            for ( Edge<Weight> *e = adj.begin(); !adj.end(); e = adj.next() )
                if ( e->v() < e->w() )
                    pq.insert(*e);
        }

        UnionFind uf = UnionFind(graph.V());
        while( !pq.isEmpty() && mst.size() < graph.V() - 1){
            Edge<Weight> e = pq.extractMin();
            if (uf.isConnected( e.v(), e.w() ))
                continue;

            mst.push_back(e);
            uf.unionElements( e.v(),e.w() );
        }

        mstWeight = mst[0].wt();
        for( int i = 1; i < mst.size(); i++ )
            mstWeight += mst[i].wt();

    }

    ~KruskalMST(){

    }

    vector< Edge<Weight> > mstEdges(){
        return mst;
    }

    Weight result(){
        return mstWeight;
    }

};

UF.h

#include <iostream>
#include <cassert>

using namespace std;

// Quick Union + rank + path compression
class UnionFind{

private:
    int* parent;
    int* rank;
    int count;

public:
    UnionFind(int count){
        parent = new int[count];
        rank = new int[count];
        this->count = count;
        for( int i = 0 ; i < count ; i ++ ){
            parent[i] = i;
            rank[i] = 1;
        }
    }

    ~UnionFind(){
        delete[] parent;
        delete[] rank;
    }

    int size(){
        return count;
    }

    bool isConnected( int p , int q ){
        return find(p) == find(q);
    }

    int find(int p){

        assert( p >= 0 && p < count );

        // path compression 1
        while( p != parent[p] ){
            parent[p] = parent[parent[p]];
            p = parent[p];
        }
        return p;

    }

    void unionElements(int p, int q){

        int pRoot = find(p);
        int qRoot = find(q);

        if( pRoot == qRoot )
            return;

        if( rank[pRoot] < rank[qRoot] )
            parent[pRoot] = qRoot;
        else if( rank[qRoot] < rank[pRoot])
            parent[qRoot] = pRoot;
        else{ // rank[pRoot] == rank[qRoot]
            parent[pRoot] = qRoot;
            rank[qRoot] ++;
        }

    }

    void show(){
        for( int i = 0 ; i < count ; i ++ )
            cout<<i<<" : "<<parent[i]<<endl;
    }
};

输出为
在这里插入图片描述
可以看出 Kruskal 的运行时间要比 Prim 慢,但是由于Kruskal算法简单,容易实现,对于比较小的图比较适用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值