zoukankan      html  css  js  c++  java
  • 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 << "-----------------------
    ";
    31     PrintTable(Table, n);33     return 0;
    34 }

     最后的结果如下所示:

    写的有点乱,见谅见谅

    其实这个也可以实现Dijkstra算法,那个好像没学过,看看以后有时间再来写。

  • 相关阅读:
    Python运行时遇到UnicodeDecodeError: 'ascii' codec can't decode byte 0xb0 in position 1: ordinal not in range(128)的问题
    Android 网络通信架构学习
    将Windows MyEclipse的web项目移植到Debian下
    build-essential : Depends: libc6-dev but it is not going to be installed or libc-dev 解决办法
    Debian可用的源 —— 23% waiting for headers解决办法
    将访问服务器的工作交由Service承担
    Servlet回传的数据显示在界面上
    Android客户端和Servlet服务器端通过JSON交互
    Welcome to My Blog!
    【三木夜话】无穷级的恐惧
  • 原文地址:https://www.cnblogs.com/-wang-cheng/p/5081027.html
Copyright © 2011-2022 走看看