C++實現Prim算法


閑來無聊,前兩天看到一篇關於算法實現的文章。里面又關於圖的各種算法介紹,正好上學期還學過圖論,現在還記得一點點,先來實現個prim算法:

表示圖的文件的內容大體上是這樣的:

 1 2.0    1.0    1.0
 2 3.0    1.0    1.0
 3 4.0    1.0    1.0
 4 5.0    1.0    1.0
 5 6.0    1.0    1.0
 6 7.0    1.0    1.0
 7 8.0    1.0    1.0
 8 9.0    1.0    1.0
 9 11.0 1.0 1.0
10 12.0 1.0 1.0
11 13.0 1.0 1.0
12 14.0 1.0 1.0
13 18.0 1.0 1.0
14 20.0 1.0 1.0
15 22.0 1.0 1.0
16 32.0 1.0 1.0
17 34.0 10.0 1.0
18 34.014.0 1.0
19 33.0 15.0 1.0
20 34.0 15.0 1.0
21 33.0 16.0 1.0
22 34.0 16.0 1.0
23 33.0 19.0 1.0
24 34.0 19.0 1.0
25 3.0    2.0    1.0
26 4.0    2.0    1.0
27 8.0    2.0    1.0
28 14.0 2.0 1.0
29 18.0 2.0 1.0
30 20.0 2.0 1.0
31 22.0 2.0 1.0
32 31.0 2.0 1.0
33 34.0 20.0 1.0
34 33.0 21.0 1.0
35 34.0 21.0 1.0
36 33.0 23.0 1.0
37 34.0 23.0 1.0
38 26.0 24.0 1.0
39 28.0 24.0 1.0
40 30.0 24.0 1.0
41 33.0 24.0 1.0
42 34.0 24.0 1.0
43 26.0 25.0 1.0
44 28.0 25.0 1.0
45 32.0 25.0 1.0
46 32.0 26.0 1.0
47 30.0 27.0 1.0
48 34.0 27.0 1.0
49 34.0 28.0 1.0
50 32.0 29.0 1.0
51 34.0 29.0 1.0
52 4.0    3.0    1.0
53 8.0    3.0    1.0
54 9.0    3.0    1.0
55 10.0 3.0 1.0
56 14.0 3.0 1.0
57 28.0 3.0 1.0
58 29.0 3.0 1.0
59 33.0 3.0 1.0
60 33.0 30.0 1.0
61 34.0 30.0 1.0
62 33.0 31.0 1.0
63 34.0 31.0 1.0
64 33.0 32.0 1.0
65 34.0 32.0 1.0
66 34.0 33.0 1.0
67 8.0    4.0    1.0
68 13.0 4.0 1.0
69 14.0 4.0 1.0
70 7.0    5.0    1.0
71 11.0 5.0 1.0
72 7.0    6.0    1.0
73 11.0 6.0 1.0
74 17.0 6.0 1.0
75 17.0 7.0 1.0
76 31.0 9.0 1.0
77 33.0 9.0 1.0
78 34.0 9.0 1.0
View Code

注意,從左到右分別是當前節點,連接的節點,邊的權重,下面首先就是設計數據結構了:

1 class Pair {        //pair代表了與某個點相連的一條邊的權重
2 private:            //,以及和這條變相連的另一個頂點是哪個
3     double edge_weight;
4     int adacent_vertex;
5 public:
6     Pair(int, double);
7     double weight() const;
8     int vertex() const;
9 };

上面的pair代表一個點相鄰的邊的權重以及這條邊與哪一個頂點是相連的。

1 class Node { //代表了一個節點,其包含的信息有與其相連的
2 private:     //某一條邊的權重以及和這條邊相連的另一個頂點。 
3     Pair element;
4     Node *next_node;
5 public:
6     Node(Pair e, Node * = NULL);
7     Pair retrieve() const;
8     Node *next() const;
9 };

代表一個節點,注意這個節點的next_node的值與相鄰節點沒有任何關系,只是代表鏈表的下一個節點,下面介紹的是鏈表:

 1 class List { //List中存放的是每個具體的節點,
 2 private:     //每個節點后面的鏈表代表的是與其相鄰接的節點
 3     Node *list_head;
 4 public:
 5     List();
 6     // Accessors
 7     bool empty() const;
 8     Pair front() const;
 9     Node *head() const;
10     void push_front(Pair);
11     Pair pop_front();
12     void print();
13 };

下面的cell實際上代表的就是一顆生成樹了:

 1 class Cell { //cell代表的就是一個具體的生成樹了
 2 private:
 3     bool visited;
 4     double distance;
 5     int parent;
 6 public:
 7     Cell(bool = false, double = INFTY, int = 0);
 8     bool isvisited() const;
 9     double get_distance() const;
10     int get_parent() const;
11 };

-----------------------------------------------------------------------------------------------------------

下面是數據結構的具體定義了:

  1 #include "structure.h"
  2 
  3 Pair::Pair(int e, double m) :
  4 edge_weight(m),
  5 adacent_vertex(e) {
  6     // empty constructor
  7 }
  8 
  9 double Pair::weight()const {
 10     return edge_weight;
 11 }
 12 int Pair::vertex()const {
 13     return adacent_vertex;
 14 }
 15 
 16 
 17 Node::Node(Pair e, Node *n) :
 18 element(e),
 19 next_node(n) {
 20     // empty constructor
 21 }
 22 
 23 Pair Node::retrieve() const{
 24     return element;
 25 }
 26 Node *Node::next() const {
 27     return next_node;
 28 }
 29 
 30 
 31 List::List() :list_head(NULL) {
 32     // empty constructor
 33 }
 34 
 35 bool List::empty() const {
 36     if (list_head == NULL) {
 37         return true;
 38     }
 39     else {
 40         return false;
 41     }
 42 }
 43 
 44 Node *List::head() const {
 45     return list_head;
 46 
 47 }
 48 
 49 Pair List::front() const {
 50 
 51     if (empty()) {
 52         cout << "error! the list is empty";
 53     }
 54     return head()->retrieve();
 55 }
 56 
 57 
 58 void List::push_front(Pair e) {
 59     if (empty()) {
 60         list_head = new Node(e, NULL);
 61     }
 62     else {
 63         list_head = new Node(e, head());
 64     }
 65 
 66 }
 67 
 68 Pair List::pop_front() {
 69     if (empty()) {
 70         cout << "error! the list is empty";
 71     }
 72     Pair e = front();
 73     Node *ptr = list_head;
 74     list_head = list_head->next();
 75     delete ptr;
 76     return e;
 77 
 78 }
 79 
 80 
 81 void List::print() {
 82     if (empty()) {
 83         cout << "empty" << endl;
 84     }
 85     else {
 86         for (Node *ptr = head(); ptr != NULL; ptr = ptr->next())
 87         {
 88             cout << "<" << ptr->retrieve().vertex() << " " << ptr->retrieve().weight() << "> ";
 89         }
 90         cout << endl;
 91     }
 92 }
 93 
 94 
 95 Cell::Cell(bool v, double d, int p) :
 96 visited(v),
 97 distance(d),
 98 parent(p) {
 99     // empty constructor
100 }
101 
102 bool Cell::isvisited() const {
103     return visited;
104 }
105 
106 double Cell::get_distance()const {
107     return distance;
108 }
109 int Cell::get_parent()const {
110     return parent;
111 }

 

好了有了上面的數據結構,實現Prim算法就比較簡單了:

 1 Cell* Prim(List * graph, int n, int start)  //傳入一個鄰接數組,以及數組的大小,
 2 {                                            //以及鄰接矩陣的起始點,求一個最小生成樹
 3     Cell* Table = new Cell[n + 1]; //n+1的目的是節點是從1開始數的,所以要多添加一個
 4     //Table[start]=Cell(false,0,0);//這里的false是否換成True會好一點?
 5     Table[start] = Cell(true, 0, 0);
 6     /* 實現prim算法*/
 7     int currMinNode, currParent = 0;
 8     double currMin;
 9     for (;;){
10         currMin = INFTY; //注意這個的類型是double類型
11         currMinNode = 0;
12         currParent = 0;
13         for (int i = 1; i <= n; ++i){
14             if (Table[i].isvisited()){//已經被訪問過了
15                 Node * currNode = graph[i].head();
16                 while (currNode != NULL){ //從該節點開始,然后訪問其所有的鄰接的節點
17                     int tmpNode = currNode->retrieve().vertex();
18                     double tmpWeight = currNode->retrieve().weight();
19                     if (!Table[tmpNode].isvisited() && tmpWeight < currMin){
20                         currMin = tmpWeight;
21                         currMinNode = tmpNode;
22                         currParent = i;
23                     }
24                     currNode = currNode->next(); //取下一個鄰接的節點
25                 }
26             }
27             else
28                 continue;
29 
30         }
31         Table[currMinNode] = Cell(true, currMin, currParent);//找到下一個節點,將其置為True
32         if (currMinNode == 0) //如果所有的節點都已經遍歷完畢的話,就停止下一次的尋找
33             break;
34 
35     }
36     return Table;
37 }

 

順手寫個打印生成樹的函數:

1 void PrintTable(Cell* Table, int n)
2 {
3     for (int i = 1; i <= n; i++)
4         cout << Table[i].isvisited() << " " <<
5         Table[i].get_distance() << " " <<
6         Table[i].get_parent() << endl;
7 }

主函數如下所示:

 1 #include "structure.h"
 2 #include "Prim.h"
 3 int main()
 4 {
 5     List * graph = new List[N];
 6     char *inputfile = "primTest.txt";
 7     ifstream fin; //輸入文件 .join后結果
 8     int n = 0;
 9     double x, y, w;
10     fin.open(inputfile);
11     while (!fin.eof())
12     {
13         fin >> x >> y >> w;
14         Pair a(y, w);
15         Pair b(x, w);
16         graph[int(x)].push_front(a);
17         graph[int(y)].push_front(b);
18         if (n <= x)
19             n = x;
20         if (n <= y)
21             n = y;
22     }
23     fin.close();
24     cout << "The total Node number is "
25         << n << endl;
26     for (int i = 1; i <= n; i++)
27         graph[i].print();
28 
29     Cell* Table = Prim(graph, n, 2);
30     cout << "-----------------------\n";
31     PrintTable(Table, n);33     return 0;
34 }

 最后的結果如下所示:

寫的有點亂,見諒見諒

其實這個也可以實現Dijkstra算法,那個好像沒學過,看看以后有時間再來寫。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM