最小生成树的PRIM算法(即时版本)

  1 #include <iostream>
  2 #include <map>
  3 #include <fstream>
  4 #include <set>
  5 #include <vector>
  6 #include <algorithm>
  7 
  8 using namespace std;
  9 
 10 
 11 class edge{
 12 private:
 13     double weight;
 14     int v;
 15     int w;
 16 public:
 17     edge() = default;  // 用 = default 来告诉编译器要为我们创建默认构造函数 (因为自定义了有参数的构造函数后编译器就不会创建默认构造函数)
 18     edge(const edge&) = default;   // !!!
 19     edge(edge &e){weight = e.weight;v = e.v; w = e.w;}
 20     edge(int _v, int _w, double _weight):v(_v),w(_w),weight(_weight){}
 21     double getWeight() const {return weight;}   // 为什么要在后面加const? 因为当edge是一个const实例时,也调用这个函数(否则报错)
 22     int either(){return v;}
 23     int another(int k) const {if(k == v)return w;else if(k == w)return v;}
 24     bool operator<(const edge &ed) const;  //should be friend?(不用,因为是自己的成员运算符,所以可以访问ed的私有成员)
 25     bool operator>(const edge &ed){return !operator<(ed);}
 26     void show() const {cout << "v: " << v << " w: " << w << " weight: " << weight << endl;}  // 没有const会报错: passing ‘const edge’ as ‘this’ argument discards qualifiers [-fpermissive]: ed.show();
 27     virtual ~edge(){}
 28 };
 29 
 30 bool edge::operator<(const edge &ed) const{
 31     return weight < ed.weight;
 32 }
 33 
 34 class graph{
 35 private:
 36     map<int, set<edge>> adj;  //这样直接把edge存放到set中有什么不妥吗?是不是应该用智能指针管理?
 37     int V;
 38     int E;
 39 public:
 40     graph(ifstream &in);
 41     map<int, set<edge>> getAdj();
 42     void show();
 43     int getv(){return V;}
 44     set<int> getAlle();
 45     set<edge> getEdge(int v);
 46     ~graph(){}
 47 };
 48 
 49 graph::graph(ifstream &in){
 50     in >> V >> E;
 51     int v, w;
 52     double weight;
 53     while(in >> v >> w >> weight){
 54         //edge temp(v,w,weight);
 55         auto v_iter = adj.find(v);
 56         if(v_iter != adj.end()){
 57             v_iter->second.emplace(v,w,weight);
 58         }
 59         else{
 60             set<edge> temps;
 61             temps.emplace(v,w,weight);
 62             adj[v] = temps;
 63         }
 64         auto w_iter = adj.find(w);
 65         if(w_iter != adj.end()){
 66             w_iter->second.emplace(v,w,weight);
 67         }
 68         else{
 69             set<edge> temps;
 70             temps.emplace(v,w,weight);
 71             adj[w] = temps;
 72         }
 73     }
 74 }
 75 
 76 set<int> graph::getAlle(){
 77     set<int> temp;
 78     for(auto &item : adj){
 79         temp.insert(item.first);
 80     }
 81 
 82     return temp;
 83 }
 84 
 85 set<edge> graph::getEdge(int v){
 86     return adj[v];
 87 }
 88 
 89 void graph::show(){
 90     for(auto & item : adj){
 91         cout << "node: " << item.first << endl;
 92         for(auto &ed : item.second){
 93             ed.show();
 94         }
 95 
 96     }
 97 }
 98 
 99 class primMST
100 {
101 private:
102     graph gp;
103     map<int, bool> marked;
104     map<int, edge> edgeTo;  
105     map<int, double> dist;  //edgeTo, dist 必须同时更新,因为他们是同一个节点对应的2个值
106     set<int> que;
107 public:
108     primMST() = delete;
109     int getMin();
110     primMST(graph &_gp);
111     void visit(int v);
112     void show() const;
113     ~primMST(){}
114 };
115 
116 primMST::primMST(graph &_gp):gp(_gp){
117     int num = gp.getv();
118     set<int> alle = gp.getAlle();
119     for(auto &item : alle){
120         dist[item] = INT32_MAX;
121     }
122     int seed = *(alle.begin());
123     cout << "seed: " << seed << endl;
124     dist[seed] = 0.0;
125     que.insert(seed);
126     while (que.size()!=0)
127     {
128         visit(getMin());
129     }
130 
131 }
132 
133 int primMST::getMin(){
134     int minior;
135     double weight = INT32_MAX;
136     for_each(que.begin(), que.end(), [&](const int &item){if(this->dist[item] < weight){minior=item;weight = this->dist[item];}});
137     que.erase(minior);
138     return minior;
139 }
140 
141 void primMST::visit(int v){
142     marked[v]= true;
143     auto allEdge = gp.getEdge(v);
144     for(auto &e : allEdge){  // 因为这里迭代的每一项e是个const对象,所以下面使用e的类方法必须确保不会改变e的成员变量(所以这些类方法必须在声名式和定义式后加const(即表示不会修改类内成员))
145         int w = e.another(v);
146         if(marked.find(w)!=marked.end())continue;
147         if(e.getWeight() < dist[w]){  //  dist[w] == edgeTo[w].getWeight()
148             edgeTo[w] = e;  // 注意不能用 edgeTo.insert(make_pair(w, e)); 当w重复时就会插入失败, 不像 edgeTo[w] = e 一样会更新
149             dist[w] = e.getWeight();
150         }
151         if(que.find(w)==que.end()){
152             que.insert(w);
153         }
154     }
155 }
156 
157 void primMST::show() const{
158     cout << "the selected edge: " << endl;
159     for_each(edgeTo.begin(), edgeTo.end(), [](auto &item){cout << "node " << item.first << ": "; item.second.show();});
160 }
161 
162 
163 int main(){
164     edge a(1,2,3);
165     edge b(4,5,6);
166     if(a>b) cout << "a" << endl;
167 
168     ifstream file("/home/tanweimin/code/program_practice/ALGORITHM/sort/MST.txt");
169     graph gp(file);
170     gp.show();
171     primMST pm(gp);
172     pm.show();
173 
174     return 0;
175 }

 预期结果:

the selected edge: 
node 1: v: 1 w: 7 weight: 0.19
node 2: v: 0 w: 2 weight: 0.26
node 3: v: 2 w: 3 weight: 0.17
node 4: v: 4 w: 5 weight: 0.35
node 5: v: 5 w: 7 weight: 0.28
node 6: v: 6 w: 2 weight: 0.4
node 7: v: 0 w: 7 weight: 0.16

 

MST.txt
8 16
4 5 0.35
5 7 0.28
4 7 0.37
0 7 0.16
1 5 0.32
0 4 0.38
2 3 0.17
1 7 0.19
0 2 0.26
1 2 0.36
1 3 0.29
2 7 0.34
6 2 0.4
3 6 0.52
6 0 0.58
6 4 0.93

 

posted @ 2021-12-05 16:14  大黑耗  阅读(43)  评论(0编辑  收藏  举报