最小生成树经典算法(C++版)

来源:互联网 发布:淘宝怎样设置分享有赏 编辑:程序博客网 时间:2024/05/17 00:50

EdgeWeightedGraph.h

#pragma once#include <memory>#include <stdexcept>#include <fstream>#include <iterator>#include <sstream>#include "priority_queue.h"template <typename T>class LazyPrimMST;template <typename T>class PrimMST;template<typename T>class Kruskal;template<typename T>class EdgeWeightedGraph{public:    class AdjacentcyList    {    public:        class Edge        {        public:            std::shared_ptr<Edge> next;            int v1;            int v2;            T weight;            Edge(const int& v1,const int& v2,const T& w):v1(v1),v2(v2),weight(w),next(nullptr)            {            }            Edge(const Edge& e) :v1(e.v1), v2(e.v2), weight(e.weight), next(nullptr)            {            }            Edge() = default;            friend std::ostream& operator << (std::ostream& os, const Edge& e);            friend bool operator < (const Edge& lhs,const Edge& rhs)            {                return lhs.weight < rhs.weight;            }            friend bool operator == (const Edge& lhs,const Edge& rhs)            {                return lhs.weight == rhs.weight;            }/******************************************函数名称:   Weight函数说明:   返回相应边的权重返回值:        T*******************************************/            T Weight()const            {                return weight;            }/******************************************函数名称:   either函数说明:   返回边顶点之一返回值      int*******************************************/            int either()const            {                return v1;            }/******************************************函数名称:   other函数说明:   返回边的另一顶点返回值:        int*******************************************/            int other(const int& v)            {                if (v == v1)                    return v2;                else if (v == v2)                    return v1;                else                    throw std::out_of_range("other's arguement out_of_range");            }        };        std::shared_ptr<Edge> head;        class Iterator        {        private:            std::shared_ptr<Edge> it;        public:            Iterator(std::shared_ptr<Edge> i):it(i)            {            }            bool operator ==(const Iterator& rhs)const            {                return it == rhs.it;            }            bool operator !=(const Iterator& rhs)const            {                return it != rhs.it;            }            Iterator operator ++()            {                it = it->next;                return *this;            }            Edge operator *()            {                if (it == nullptr)                    throw std::logic_error("can't * nullpoint");                return *it;            }        };    public:        Iterator begin()const        {            return Iterator(head);        }        Iterator end()const        {            return Iterator(nullptr);        }        AdjacentcyList() :head(nullptr)        {        }/******************************************函数名称:   addEdge函数说明:   增加边返回值:        void*******************************************/        void addEdge(const Edge& e)        {            if (head == nullptr)            {                head = std::make_shared<Edge>(e);                return;            }            std::shared_ptr<Edge> curr = head;            while (curr->next != nullptr)                curr = curr->next;            curr->next = std::make_shared<Edge>(e);            return;        }    };    private:        std::unique_ptr<AdjacentcyList[]> adj;        int nV;         int nE;    public:        EdgeWeightedGraph(const std::string& file)        {            std::ifstream in(file);            in >> nV;            adj = std::move(std::unique_ptr<AdjacentcyList[]>(new AdjacentcyList[nV]));            while (!in.eof())            {                int pre, curr;                T w;                in >> pre >> curr >> w;                adj[pre].addEdge({ pre, curr, w });                adj[curr].addEdge({ curr, pre, w });                ++nE;            }        }        friend class LazyPrimMST<T>;        friend class PrimMST<T>;        friend class Kruskal<T>;};template<typename T>std::ostream& operator << (std::ostream& os, const typename EdgeWeightedGraph<T>::AdjacentcyList::Edge& e){    os << e.v1 << ends << e.v2 << ends << e.weight << endl;    return os;}template<typename T>bool operator < (const typename EdgeWeightedGraph<T>::AdjacentcyList::Edge& lhs, const typename EdgeWeightedGraph<T>::AdjacentcyList::Edge& rhs){    return lhs.weight < rhs.weight;}

Prim算法借助于优先队列数据结构

#pragma once#include <memory>#include <functional>#include <stdexcept>template<typename T,typename Cmp = less<T>>class priority_queue{private:    int SIZE = 100;    std::unique_ptr<T[]> theap;    int count;public:    priority_queue():count(0),theap(std::move(std::unique_ptr<T[]>(new T[SIZE + 1])))    {    }private:    void swim(int k)    {        while (k > 1 && Cmp()(theap[k], theap[k / 2]))        {            std::swap(theap[k], theap[k / 2]);            k = k / 2;        }    }    void sink(int k,const int& N)    {        while (2 * k <= N)        {            int j = 2 * k;            if (j < N && Cmp()(theap[j + 1], theap[j])) ++j;            if (Cmp()(theap[k], theap[j])) break;            std::swap(theap[k], theap[j]);            k = j;        }    }    void resize(const int& n)    {        std::unique_ptr<T[]> tmp(new T[n]);        for (int i = 1; i <= count; ++i)        {            tmp[i] = theap[i];        }        theap = std::move(tmp);        SIZE = n - 1;    }public:    void push(const T& t)    {        if (count == SIZE)            resize(2 * count + 1);        theap[++count] = t;        swim(count);    }    void pop()    {        if (count == 0)            return;        if (count == 1)        {            --count;            return;        }        std::swap(theap[1], theap[count]);        --count;        sink(1, count);        if (count <= SIZE / 4)            resize(SIZE / 2 + 1);    }    T top()const    {        if (count == 0)            throw std::out_of_range("top error");        return theap[1];    }    bool empty()const    {        return count == 0;    }/***************for pair*************************/    void push(const int& k,const T& p)    {        int pos = 1;        for (pos = 1; pos <= count; ++pos)            if (theap[pos].first == k)                break;        if (theap[pos].first == k)        {            if (count == 1)            {                theap[1] = p;                return;            }            theap[pos] = theap[count--];            sink(pos, count);            push(p);            return;        }        else            push(p);        return;    }/*-----------------for pair----------------------*/};

Prim算法延时实现 LazyPrimMST.h

#pragma once#include "EdgeWeightedGraph.h"#include <deque>#include <functional>#include "priority_queue.h"template<typename T>class LazyPrimMST{    using Ed = typename EdgeWeightedGraph<T>::AdjacentcyList::Edge;    class Less    {    public:        Less() {}        bool operator()(const Ed& lhs, const Ed& rhs)        {            return lhs.weight < rhs.weight;        }    };private:    void visit(EdgeWeightedGraph<T> *ewg, const int& v)    {        marked[v] = true;        for (auto &e : ewg->adj[v])            if (!marked[e.other(v)])                pq.push(e);    }public:    LazyPrimMST(EdgeWeightedGraph<T> *ewg)    {        marked = std::move(std::unique_ptr<bool[]>(new bool[ewg->nV]));        for (int i = 0; i < ewg->nV; ++i)            marked[i] = false;        visit(ewg, 0);        while (!pq.empty())        {            Ed e = pq.top();            pq.pop();            int v1 = e.either();            int v2 = e.other(v1);            if (marked[v1] && marked[v2]) continue;            mst.push_back(e);            if (!marked[v1]) visit(ewg, v1);            if (!marked[v2]) visit(ewg, v2);        }    }    T min_weight()    {        T ret{};        for (auto &w : mst)            ret = ret + w.weight;        return ret;    }private:    std::unique_ptr<bool[]> marked;    std::deque<Ed> mst;    priority_queue<Ed, Less> pq;};

Prim算法实时实现 PrimMST.h

#pragma once#include "EdgeWeightedGraph.h"#include "priority_queue.h"template <typename T>class PrimMST{    using Ed = typename EdgeWeightedGraph<T>::AdjacentcyList::Edge;private:    class Less    {    public:        Less()        {        }        bool operator()(const std::pair<int,T>& lhs,const std::pair<int,T>& rhs)        {            return lhs.second < rhs.second;        }    };private:    void visit(EdgeWeightedGraph<T>* ewg,const int& v)    {        marked[v] = true;        for (auto e : ewg->adj[v])        {            int v2 = e.other(v);            if (marked[v2]) continue;            if (e.weight < disTo[v2])            {                edgeTo[v2] = &e;                disTo[v2] = e.weight;                pq.push(v2, std::pair<int,T>(v2,e.weight));            }        }    }public:    PrimMST(EdgeWeightedGraph<T> *ewg)    {        marked = std::move(std::unique_ptr<bool[]>(new bool[ewg->nV]));        disTo = std::move(std::unique_ptr<T[]>(new T[ewg->nV]));        edgeTo = std::move(std::unique_ptr<Ed*[]>(new Ed*[ewg->nV]));        nv = ewg->nV;        for (int i = 0; i < ewg->nV; ++i)        {            marked[i] = false;            disTo[i] = std::numeric_limits<T>::max();            edgeTo[i] = nullptr;        }        disTo[0] = T{};        pq.push(std::make_pair<int, T>(0, T{}));        while (!pq.empty())        {            visit(ewg, pq.top().first);            pq.pop();        }    }    T min_weight()    {        T ret{};        for (int i = 0; i < nv; ++i)            ret += disTo[i];        return ret;    }private:    std::unique_ptr<bool[]> marked;    std::unique_ptr<T[]> disTo;    std::unique_ptr<Ed*[]> edgeTo;    priority_queue<std::pair<int, T>, Less> pq;    int nv;};

Kruskal算法借助于加权路径压缩union-find算法完成

#pragma once#include <memory>class UF{private:    std::unique_ptr<int[]> id;    std::unique_ptr<int[]> sd;public:    UF(const int& c)    {        id = std::move(std::unique_ptr<int[]>(new int[c]));        sd = std::move(std::unique_ptr<int[]>(new int[c]));        for (int i = 0; i < c; ++i)        {            id[i] = i;            sd[i] = 1;        }    }    bool connect(const int& l, const int& r)    {        return find(l) == find(r);    }    int find(int l)    {        while (id[l] != l)        {            id[l] = id[id[l]];            l = id[l];        }        return l;    }    void quick_union(const int& l, const int& r)    {        int m = find(l);        int n = find(r);        if (m == n) return;        if (sd[m] > sd[n])        {            id[n] = m;            sd[m] += sd[n];        }        else        {            id[m] = n;            sd[n] += sd[m];        }    }};

Kruskal算法 Kruskal.h

#pragma once#include "EdgeWeightedGraph.h"#include <deque>#include "UF.h"template<typename T>class Kruskal{    using Ed = typename EdgeWeightedGraph<T>::AdjacentcyList::Edge;private:    class Less    {    public:        Less()        {        }        bool operator()(const Ed& lhs,const Ed& rhs)        {            return lhs.weight < rhs.weight;        }    };private:    priority_queue<Ed,Less> pq;    std::deque<Ed> edge;    std::unique_ptr<UF> uf;private:    void init_pq(EdgeWeightedGraph<T>* ewg)    {        for (int i = 0; i < ewg->nV; ++i)            for (auto &e : ewg->adj[i])                if (e.other(i) > i)                     pq.push(e);    }public:    Kruskal(EdgeWeightedGraph<T>* ewg)    {        init_pq(ewg);        uf = std::move(std::unique_ptr<UF>(new UF(ewg->nV)));        while (!pq.empty())        {            Ed e = pq.top();            int v1 = e.either();            int v2 = e.other(v1);            pq.pop();            if (uf->connect(v1, v2)) continue;            edge.push_back(e);            uf->quick_union(v1, v2);        }    }    T min_weight()    {        T ret{};        for (auto& e : edge)            ret += e.weight;        return ret;    }};

main.cpp

#include <iostream>#include "EdgeWeightedGraph.h"#include "priority_queue.h"#include "LazyPrimMST.h"#include "PrimMST.h"#include "Kruskal.h"using namespace std;int main(){    EdgeWeightedGraph<double> ewg("test.txt");    //ewg.less_display();    LazyPrimMST<double> lpm(&ewg);    cout << lpm.min_weight() << endl;    //LazyPrimMST<double> lpm;    PrimMST<double> pm(&ewg);    cout << pm.min_weight() << endl;    Kruskal<double> ks(&ewg);    cout << ks.min_weight();    system("pause");    return 0;}

测试文件:

84 5 0.354 7 0.375 7 0.280 7 0.161 5 0.320 4 0.382 3 0.171 7 0.190 2 0.261 2 0.361 3 0.292 7 0.346 2 0.403 6 0.526 0 0.586 4 0.93

运行结果:

这里写图片描述

三种结果都是求同一个图最小生成树的权值和。。。

原创粉丝点击