C++实现Prim算法
2015-12-27 22:24
453 查看
闲来无聊,前两天看到一篇关于算法实现的文章。里面又关于图的各种算法介绍,正好上学期还学过图论,现在还记得一点点,先来实现个prim算法:
表示图的文件的内容大体上是这样的:
View Code
注意,从左到右分别是当前节点,连接的节点,边的权重,下面首先就是设计数据结构了:
上面的pair代表一个点相邻的边的权重以及这条边与哪一个顶点是相连的。
代表一个节点,注意这个节点的next_node的值与相邻节点没有任何关系,只是代表链表的下一个节点,下面介绍的是链表:
下面的cell实际上代表的就是一颗生成树了:
-----------------------------------------------------------------------------------------------------------
下面是数据结构的具体定义了:
好了有了上面的数据结构,实现Prim算法就比较简单了:
顺手写个打印生成树的函数:
主函数如下所示:
最后的结果如下所示:
写的有点乱,见谅见谅
其实这个也可以实现Dijkstra算法,那个好像没学过,看看以后有时间再来写。
表示图的文件的内容大体上是这样的:
2.0 1.0 1.0 3.0 1.0 1.0 4.0 1.0 1.0 5.0 1.0 1.0 6.0 1.0 1.0 7.0 1.0 1.0 8.0 1.0 1.0 9.0 1.0 1.0 11.0 1.0 1.0 12.0 1.0 1.0 13.0 1.0 1.0 14.0 1.0 1.0 18.0 1.0 1.0 20.0 1.0 1.0 22.0 1.0 1.0 32.0 1.0 1.0 34.0 10.0 1.0 34.014.0 1.0 33.0 15.0 1.0 34.0 15.0 1.0 33.0 16.0 1.0 34.0 16.0 1.0 33.0 19.0 1.0 34.0 19.0 1.0 3.0 2.0 1.0 4.0 2.0 1.0 8.0 2.0 1.0 14.0 2.0 1.0 18.0 2.0 1.0 20.0 2.0 1.0 22.0 2.0 1.0 31.0 2.0 1.0 34.0 20.0 1.0 33.0 21.0 1.0 34.0 21.0 1.0 33.0 23.0 1.0 34.0 23.0 1.0 26.0 24.0 1.0 28.0 24.0 1.0 30.0 24.0 1.0 33.0 24.0 1.0 34.0 24.0 1.0 26.0 25.0 1.0 28.0 25.0 1.0 32.0 25.0 1.0 32.0 26.0 1.0 30.0 27.0 1.0 34.0 27.0 1.0 34.0 28.0 1.0 32.0 29.0 1.0 34.0 29.0 1.0 4.0 3.0 1.0 8.0 3.0 1.0 9.0 3.0 1.0 10.0 3.0 1.0 14.0 3.0 1.0 28.0 3.0 1.0 29.0 3.0 1.0 33.0 3.0 1.0 33.0 30.0 1.0 34.0 30.0 1.0 33.0 31.0 1.0 34.0 31.0 1.0 33.0 32.0 1.0 34.0 32.0 1.0 34.0 33.0 1.0 8.0 4.0 1.0 13.0 4.0 1.0 14.0 4.0 1.0 7.0 5.0 1.0 11.0 5.0 1.0 7.0 6.0 1.0 11.0 6.0 1.0 17.0 6.0 1.0 17.0 7.0 1.0 31.0 9.0 1.0 33.0 9.0 1.0 34.0 9.0 1.0
View Code
注意,从左到右分别是当前节点,连接的节点,边的权重,下面首先就是设计数据结构了:
class Pair { //pair代表了与某个点相连的一条边的权重 private: //,以及和这条变相连的另一个顶点是哪个 double edge_weight; int adacent_vertex; public: Pair(int, double); double weight() const; int vertex() const; };
上面的pair代表一个点相邻的边的权重以及这条边与哪一个顶点是相连的。
class Node { //代表了一个节点,其包含的信息有与其相连的 private: //某一条边的权重以及和这条边相连的另一个顶点。 Pair element; Node *next_node; public: Node(Pair e, Node * = NULL); Pair retrieve() const; Node *next() const; };
代表一个节点,注意这个节点的next_node的值与相邻节点没有任何关系,只是代表链表的下一个节点,下面介绍的是链表:
class List { //List中存放的是每个具体的节点, private: //每个节点后面的链表代表的是与其相邻接的节点 Node *list_head; public: List(); // Accessors bool empty() const; Pair front() const; Node *head() const; void push_front(Pair); Pair pop_front(); void print(); };
下面的cell实际上代表的就是一颗生成树了:
class Cell { //cell代表的就是一个具体的生成树了 private: bool visited; double distance; int parent; public: Cell(bool = false, double = INFTY, int = 0); bool isvisited() const; double get_distance() const; int get_parent() const; };
-----------------------------------------------------------------------------------------------------------
下面是数据结构的具体定义了:
#include "structure.h" Pair::Pair(int e, double m) : edge_weight(m), adacent_vertex(e) { // empty constructor } double Pair::weight()const { return edge_weight; } int Pair::vertex()const { return adacent_vertex; } Node::Node(Pair e, Node *n) : element(e), next_node(n) { // empty constructor } Pair Node::retrieve() const{ return element; } Node *Node::next() const { return next_node; } List::List() :list_head(NULL) { // empty constructor } bool List::empty() const { if (list_head == NULL) { return true; } else { return false; } } Node *List::head() const { return list_head; } Pair List::front() const { if (empty()) { cout << "error! the list is empty"; } return head()->retrieve(); } void List::push_front(Pair e) { if (empty()) { list_head = new Node(e, NULL); } else { list_head = new Node(e, head()); } } Pair List::pop_front() { if (empty()) { cout << "error! the list is empty"; } Pair e = front(); Node *ptr = list_head; list_head = list_head->next(); delete ptr; return e; } void List::print() { if (empty()) { cout << "empty" << endl; } else { for (Node *ptr = head(); ptr != NULL; ptr = ptr->next()) { cout << "<" << ptr->retrieve().vertex() << " " << ptr->retrieve().weight() << "> "; } cout << endl; } } Cell::Cell(bool v, double d, int p) : visited(v), distance(d), parent(p) { // empty constructor } bool Cell::isvisited() const { return visited; } double Cell::get_distance()const { return distance; } int Cell::get_parent()const { return parent; }
好了有了上面的数据结构,实现Prim算法就比较简单了:
Cell* Prim(List * graph, int n, int start) //传入一个邻接数组,以及数组的大小, { //以及邻接矩阵的起始点,求一个最小生成树 Cell* Table = new Cell[n + 1]; //n+1的目的是节点是从1开始数的,所以要多添加一个 //Table[start]=Cell(false,0,0);//这里的false是否换成True会好一点? Table[start] = Cell(true, 0, 0); /* 实现prim算法*/ int currMinNode, currParent = 0; double currMin; for (;;){ currMin = INFTY; //注意这个的类型是double类型 currMinNode = 0; currParent = 0; for (int i = 1; i <= n; ++i){ if (Table[i].isvisited()){//已经被访问过了 Node * currNode = graph[i].head(); while (currNode != NULL){ //从该节点开始,然后访问其所有的邻接的节点 int tmpNode = currNode->retrieve().vertex(); double tmpWeight = currNode->retrieve().weight(); if (!Table[tmpNode].isvisited() && tmpWeight < currMin){ currMin = tmpWeight; currMinNode = tmpNode; currParent = i; } currNode = currNode->next(); //取下一个邻接的节点 } } else continue; } Table[currMinNode] = Cell(true, currMin, currParent);//找到下一个节点,将其置为True if (currMinNode == 0) //如果所有的节点都已经遍历完毕的话,就停止下一次的寻找 break; } return Table; }
顺手写个打印生成树的函数:
void PrintTable(Cell* Table, int n) { for (int i = 1; i <= n; i++) cout << Table[i].isvisited() << " " << Table[i].get_distance() << " " << Table[i].get_parent() << endl; }
主函数如下所示:
#include "structure.h" #include "Prim.h" int main() { List * graph = new List ; char *inputfile = "primTest.txt"; ifstream fin; //输入文件 .join后结果 int n = 0; double x, y, w; fin.open(inputfile); while (!fin.eof()) { fin >> x >> y >> w; Pair a(y, w); Pair b(x, w); graph[int(x)].push_front(a); graph[int(y)].push_front(b); if (n <= x) n = x; if (n <= y) n = y; } fin.close(); cout << "The total Node number is " << n << endl; for (int i = 1; i <= n; i++) graph[i].print(); Cell* Table = Prim(graph, n, 2); cout << "-----------------------\n"; PrintTable(Table, n); return 0; }
最后的结果如下所示:
写的有点乱,见谅见谅
其实这个也可以实现Dijkstra算法,那个好像没学过,看看以后有时间再来写。