最小生成樹總結(prim、並查集和kruskal) C++實現
阿新 • • 發佈:2018-12-24
#ifndef ___00_alg_tests__minimal_spanning_tree__ #define ___00_alg_tests__minimal_spanning_tree__ #include <stdio.h> #include <string.h> #include <list> #include <vector> #include "union_find.h" #define _DEBUG_ #ifdef _DEBUG_ #include <iostream> using namespace std; #endif #define MAX_DISTENCE 0xfffffff // Vertex value template<class T,class keyType = long> class Vertex { public: typedef T valueType; Vertex(keyType key, T value) : m_key(key), m_value(value) { m_dis = MAX_DISTENCE; m_known = false; m_isVisited = false; }; ~Vertex(){}; int getDis() { return m_dis;}; void setDis(int dis) { m_dis = dis; return ;}; bool isknown() { return m_known;}; keyType getKey() { return m_key;}; void init() { m_known = false; m_isVisited = false;}; void setKnown() { m_known = true; return ;}; bool isVisited() { return m_isVisited;}; void setVisited() { m_isVisited = true; return ;}; private: keyType m_key; /* 頂點關鍵字. */ valueType m_value; /* 頂點值. */ int m_dis; /* 距離. */ bool m_known; /* 是否已被遍歷(prim演算法). */ bool m_isVisited; /* 標識是否被訪問過(DFS演算法). */ }; // Edge template<class T,class weightType = int> class Edge { public: typedef T nodeType; Edge(T *ori, T *des, weightType weight) : \ m_ori(ori), m_des(des), m_weight(weight) { }; ~Edge() { }; T *getOri() { return m_ori;}; T *getDes() { return m_des;}; weightType getWeight() { return m_weight;} bool operator< (const Edge<T,weightType> *M) const { return m_weight < M->getWeight(); }; private: nodeType *m_ori; /* 邊的起始點. */ nodeType *m_des; /* 邊的終止點. */ weightType m_weight; /* 邊的權值. */ }; template<class T, class edgeType> class VertexNode { public: typedef T nodeType; VertexNode(T *node) : m_vertex(node) { m_iter = m_adj.begin();}; ~VertexNode() { }; /* 清除演算法對頂點的副作用. */ void init() { if (m_vertex){ m_vertex->init(); } return ;}; /* 新增邊到圖. */ void addEdge(edgeType *edge) { m_adj.push_back(edge);}; /* 獲取頂點的臨接邊. */ edgeType *getAdj() { m_iter = m_adj.begin();return *m_iter;}; /* 獲取該頂點的下一條臨接邊 .*/ edgeType *getNext() { m_iter++; return (m_iter != m_adj.end()) ? *m_iter : NULL;}; /* 獲取頂點元素. */ T *getVertex() { return m_vertex;}; /* 標識此頂點是否被訪問過(prim演算法). */ bool isKnown() { return (m_vertex) ? m_vertex->isknown() : false;}; /* 設定此頂點已經被訪問過(prim演算法). */ void setKnown() { if (m_vertex) {m_vertex->setKnown();} return ;}; /* 獲取距離--prim演算法*/ int getDis() { if (m_vertex) { return m_vertex->getDis();} exit(-1);} /* 設定距離. */ void setDis(int dis) { if (m_vertex) { m_vertex->setDis(dis);} return ;}; /* 標識此頂點是否被訪問過(dfs演算法). */ bool isVisited() { return (m_vertex) ? m_vertex->isVisited() : false ;}; /* 設定此頂點已經被訪問過(dfs演算法). */ void setVisited() { if (m_vertex) {m_vertex->setVisited();} return ;}; private: nodeType *m_vertex; /* 頂點元素 */ std::list<edgeType*> m_adj; /* 頂點的鄰接表. */ typename std::list<edgeType*>::iterator m_iter; /* 用於遍歷鄰接點. */ }; template<class T,class edgeType> class Graph { public: Graph(){}; ~Graph(){}; typedef VertexNode<T,edgeType> VertexNodeType; /* 清除演算法對圖的副作用. */ void init(); /* Prim演算法. */ void prim(); /* 深度優先遍歷. */ void dfs(VertexNodeType* src); /* 向圖中增加一個頂點. */ void addNode(VertexNode<T,edgeType> *node) { m_vertexNodeSet.push_back(node);}; void kruskal(); private: /* 頂點集. */ std::list<VertexNodeType*> m_vertexNodeSet; /* 找到最短的邊集--用於prim演算法 */ VertexNodeType* findMindis(); void sortEdge(list<edgeType*> &edgeSet); }; template<class T,class edgeType> void Graph<T,edgeType>::init() { typename std::list<VertexNodeType*>::iterator it; for (it = m_vertexNodeSet.begin(); it != m_vertexNodeSet.end(); ++it) { it->init(); } return ; } template<class T,class edgeType> VertexNode<T,edgeType>* Graph<T,edgeType>::findMindis() { int min = MAX_DISTENCE; VertexNodeType* minDisNode = NULL; // for_each node. typename std::list<VertexNodeType*>::iterator iter; for (iter = m_vertexNodeSet.begin(); \ iter != m_vertexNodeSet.end(); ++iter) { VertexNodeType* tmp = *iter; if (tmp->isKnown()) { continue; } if (min > tmp->getDis()) { min = tmp->getDis(); minDisNode = tmp; } } return minDisNode; } template<class T,class edgeType> void Graph<T,edgeType>::prim() { VertexNodeType *nodeTmp = m_vertexNodeSet.front(); if (!nodeTmp) { //cout<<"No Node exist in this Graph."<<endl; return ; } nodeTmp->setDis(0); nodeTmp->setKnown(); #ifdef _DEBUG_ cout<<"Node's key = "<<nodeTmp->getVertex()->getKey(); cout<<",Distence = "<<nodeTmp->getVertex()->getDis()<<endl; #endif // For_each node. for (; ;) { edgeType* edgeTmp = nodeTmp->getAdj(); // For_each adj node. while (edgeTmp) { T * Vtmp = edgeTmp->getDes(); #ifdef _DEBUG_ cout<<"Node("<<Vtmp->getKey()<<") "<<endl;; #endif if (Vtmp->isknown()) { edgeTmp = nodeTmp->getNext(); continue; } // Update dis. if (edgeTmp->getWeight() < Vtmp->getDis()) { Vtmp->setDis((int)edgeTmp->getWeight()); } edgeTmp = nodeTmp->getNext(); } // Find the node which has min dis. nodeTmp = findMindis(); if (!nodeTmp) { break; } nodeTmp->setKnown(); #ifdef _DEBUG_ cout<<"Node's key = "<<nodeTmp->getVertex()->getKey(); cout<<",Distence = "<<nodeTmp->getVertex()->getDis()<<endl; #endif } return ; } template<class T,class edgeType> void Graph<T,edgeType>::sortEdge(list<edgeType*> &edgeSet) { typename std::list<VertexNodeType*>::iterator it; for (it = m_vertexNodeSet.begin(); it != m_vertexNodeSet.end(); ++it) { edgeType *edgeTmp = it->getAdj(); while (edgeTmp) { edgeSet->push_back(edgeTmp); edgeTmp = it->getNext(); } } sort(edgeSet.begin(), edgeSet.end(), less<edgeType>()); return ; } template<class T,class edgeType> void Graph<T,edgeType>::kruskal() { // Init list<edgeType*> edgeSet;// 這裡用優先佇列效率更高 sortEdge(edgeSet); list<edgeType*> treeEdgeSet;//最小生成樹邊集 int vertexArraySize = m_vertexNodeSet.size(); T *vertexArray = (T*)malloc(sizeof(T*)*vertexArraySize); typename std::list<VertexNodeType*>::iterator iter; int i = 0; for (iter = m_vertexNodeSet.begin(); iter != m_vertexNodeSet.end(); ++iter) { vertexArray[i] = iter->getVertex(); i++; } UnionFind<T*> vertexUnion(vertexArray,vertexArraySize); typename std::list<edgeType*>::iterator it; for (it = edgeSet.begin(); it != edgeSet.end(); ++it) { // Find Min dis edge. edgeType *edgeMin = it->front();it->pop_front(); // Is the ori node and des node in same set? T *ori = edgeMin->getOri(); T *des = edgeMin->getOri(); // If in same set,Ignore.If not,combain the set and add this edge. if (vertexUnion.isConnected(ori, des)) { continue; } else { vertexUnion.unionT(ori, des); treeEdgeSet->push_back(edgeMin); } } #ifdef _DEBUG_ typename std::list<edgeType*>::iterator itera; for (itera = treeEdgeSet.begin(); itera != treeEdgeSet.end(); itera++) { cout<<itera->getWeight()<<endl; } #endif // Free vertexArray. if (vertexArray) { free(vertexArray); vertexArray = NULL; } return ; } /* 深度優先遍歷. */ template<class T,class edgeType> void Graph<T,edgeType>::dfs(VertexNodeType *src) { // Set node Visited. VertexNodeType *V = src; V->setVisited(); // For each W adj to V. edgeType *edgeTmp = V->getAdj(); while (edgeTmp) { T *Vtmp = edgeTmp->getDes(); if (!Vtmp->isKnown()) { dfs(Vtmp); } edgeTmp = V->getNext(); } return ; } int testGraphPrim(); int testGraphKruskal(); #endif /* defined(___00_alg_tests__minimal_spanning_tree__) */
單元測試程式原始碼: