最小生成树经典算法(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
运行结果:
三种结果都是求同一个图最小生成树的权值和。。。
阅读全文
1 0
- 最小生成树经典算法(C++版)
- prim经典算法求最小生成树
- 经典算法之最小生成树
- 经典算法6:贪心算法之最小生成树
- 最小生成树Prim算法朴素版 C语言实现
- 最小生成树Prim算法朴素版 C语言实现
- 图的最小生成树Prim算法朴素版(C++)
- 图的最小生成树Kruskal算法朴素版(C++)
- 最小生成树Prim算法朴素版 C语言实现
- 最小生成树Kruskal算法朴素版 C语言实现
- 最小生成树Prim算法C语言
- 最小生成树Kruskal算法C语言
- Prim最小生成树算法(C++)
- Kruscal最小生成树算法(C++)
- 最小生成树 kruscal算法 C语言
- 【经典算法】:图中的最小生成树算法之Prim算法和Kruskal算法
- [C++]最小生成树--Prim算法&Kruskal算法
- 最小生成树算法
- Spring中ApplicationContext对Beanfactory扩展
- BZOJ1925 地精部落
- asdasd
- Android编程权威指南(第2版)—第8章挑战练习
- [Leetcode] 4.Median of Two Sorted Arrays
- 最小生成树经典算法(C++版)
- UE4网络复制Tips
- 洛谷 P3384 【模板】树链剖分(指针版)
- jquery ajax上传文件
- Http状态码(404、500等)
- ZOJ2006 一道很尴尬的string操作题
- QT5 Ubuntu下c++调用linux命令、显示输出、执行多条命令
- 解决“动软代码生成器在SqlServer中会将唯一索引识别为主键"的Bug
- 最长公共子序列的长度