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

上篇博客中使用Lazy Prim实现的最小生成树算法复杂度为 O ( E l o g E ) O(ElogE) O(ElogE)
下面使用Prim实现最小生成树,算法复杂度为 O ( E l o g V ) O(ElogV) O(ElogV)
使用最小索引堆实现Prim
在这里插入图片描述
(1)将与节点0相连接的节点的权值放入数组中,节点7的权重最小,那么边0-7属于最小生成树
在这里插入图片描述
(2)下面开始考察与节点7相连接的节点,对于节点1来说,数组中没有,直接将0.19放入;对于节点5来说,数组中也没有,直接将0.28放入;对于节点2来说,其权重为0.34,而数组中2的权重为0.26,比0.34小,继续保留,把0.34舍去;对于节点4来说,其权重为0.37,数组中4的权重为0.38,那么将原来的0.38舍去,将0.37放入数组中
在这里插入图片描述
(3)将节点7的相连接的节点都选择性的放入数组中后,数组中的最小值为0.19,那么将节点1标红,继续考察节点1相连接的节点,对于节点5,边1-5权重为0.32,比数组中0.28要大,舍弃0.32;对于节点3,权重0.29,数组中没有,将0.29放入数组中;对于节点2,权重0.36,数组中为0.26,将0.36舍弃
在这里插入图片描述
(4)按照上述步骤,就可将数组中全部元素都标红,标红的权重的边组成最小生成树
在这里插入图片描述
下面是程序实现
程序中的四个txt文件在百度网盘

#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"

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;


    return 0;
}

PrimMST.h

#include <iostream>
#include <vector>
#include <cassert>

#include "IndexMinHeap.h"

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

using namespace std;

template<typename Graph, typename Weight>
class PrimMST{

private:
    Graph &G;
    IndexMinHeap< Weight > ipq;
    vector< Edge<Weight>* > edgeTo;
    bool *marked;
    vector< Edge<Weight> > mst;
    Weight mstWeight;

    void visit(int v){

        assert( !marked[v] );
        marked[v] = true;

        typename Graph::adjIterator adj(G,v);
        for (Edge<Weight>* e = adj.begin(); !adj.end(); e = adj.next() ){
            int w = e->other(v);

            if ( !marked[w]){
                if ( !edgeTo[w] ){
                    edgeTo[w] = e;
                    ipq.insert(w, e->wt());
                }
                else if ( e->wt() < edgeTo[w]->wt() ){
                    edgeTo[w] = e;
                    ipq.change(w, e->wt());
                }
            }
        }
    }

public:
    // 构造函数, 使用Prim算法求图的最小生成树
    PrimMST(Graph &graph):G(graph), ipq(IndexMinHeap<double>(graph.V())){

        assert( graph.E() >= 1 );

        // 算法初始化
        marked = new bool[G.V()];
        for( int i = 0 ; i < G.V() ; i ++ ){
            marked[i] = false;
            edgeTo.push_back(NULL);
        }
        mst.clear();

        // Prim
        visit(0);

        while( !ipq.isEmpty() ){
            // 使用最小索引堆找出已经访问的边中权值最小的边
            // 最小索引堆中存储的是点的索引, 通过点的索引找到相对应的边
            int v = ipq.extractMinIndex();
            assert( edgeTo[v] );
            mst.push_back( *edgeTo[v] );
            visit( v );
        }

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

    ~PrimMST(){
        delete[] marked;
    }

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

    Weight result(){
        return mstWeight;
    }

};

IndexMinHeap.h

#include <iostream>
#include <algorithm>
#include <cassert>

using namespace std;

template<typename Item>
class IndexMinHeap{
private:
    Item *data;
    int count;
    int capacity;

    int *indexes;
    int *reverse;

    void shiftUp(int k){
        while (k > 1 && data[indexes[k/2]] > data[indexes[k]]){
            swap(indexes[k/2], indexes[k]);
            reverse[indexes[k/2]] = k/2;
            reverse[indexes[k]] = k;
            k /= 2;
        }
    }

    void shiftDown(int k){
        while (k <= count/2){
            int j = 2*k; //此轮循环中,data[k]和data[j]交换位置
            if (data[indexes[j]] > data[indexes[j+1]] && j + 1 <= count)
                j += 1;
            if (data[indexes[k]] <= data[indexes[j]])
                break;

            swap(indexes[j], indexes[k]);
            reverse[indexes[j]] = j;
            reverse[indexes[k]] = k;
            k = j;
        }
    }

public:
    IndexMinHeap(int capacity){
        data = new Item[capacity + 1];
        indexes = new int[capacity + 1];
        reverse = new int[capacity + 1];

        for (int i = 0; i <= capacity; i++)
            reverse[i] = 0;

        count = 0;
        this->capacity = capacity;
    }

    ~IndexMinHeap(){
        delete[] data;
        delete[] indexes;
        delete[] reverse;
    }

    int size(){
        return count;
    }

    bool isEmpty(){
        return count == 0;
    }

    void insert(int index, Item item){

        assert( count + 1 <= capacity );
        assert( index + 1 >= 1 && index + 1 <= capacity );

        index += 1;
        data[index] = item;
        indexes[count+1] = index;
        reverse[index] = count+1;
        count++;
        shiftUp(count);
    }

    Item extractMin(){
        assert( count > 0 );

        Item ret = data[indexes[1]];
        swap( indexes[1] , indexes[count] );
        reverse[indexes[count]] = 0;
        reverse[indexes[1]] = 1;
        count--;
        shiftDown(1);
        return ret;
    }

    int extractMinIndex(){
        assert( count > 0 );

        int ret = indexes[1] - 1;
        swap( indexes[1] , indexes[count] );
        reverse[indexes[count]] = 0;
        reverse[indexes[1]] = 1;
        count--;
        shiftDown(1);
        return ret;
    }


    Item getMin(){
        assert( count>0 );
        return data[indexes[1]];
    }

    int getMinIndex(){
        assert( count > 0 );
        return indexes[1]-1;
    }

    bool contain( int index ){

        return reverse[index+1] != 0;
    }

    Item getItem( int index ){
        assert( contain(index) );
        return data[index+1];
    }

    void change( int index , Item newItem ){

        assert( contain(index) );
        index += 1;
        data[index] = newItem;

        shiftUp( reverse[index] );
        shiftDown( reverse[index] );
    }
};

输出为
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值