您好,登錄后才能下訂單哦!
直接上代碼:代碼里面有注釋
#pragma once #include <assert.h> #include <queue> #include "Heap.hpp" #include "UnionFindSet.hpp" // // 臨接矩陣表示無向圖&有向圖 // template<class V, class W> class GraphMatrix { public: GraphMatrix(const V* vertexs, int size, bool isDirected) :_vertexSize(size) ,_isDirected(isDirected) { // 開辟矩陣和邊集 _matrix = new W*[_vertexSize]; _vertexs = new V[_vertexSize]; for (int i = 0; i < _vertexSize; ++i) { // 初始化矩陣 _matrix[i] = new W[_vertexSize]; memset(_matrix[i], 0, sizeof(W)*_vertexSize); // 初始化邊集 _vertexs[i] = vertexs[i]; } } int GetVertexIndex(const V& vtx) { for (int i = 0; i < _vertexSize; ++i) { if (_vertexs[i] == vtx) { return i; } } return -1; } void AddEdge(const V& src, const V& dst, const W& weight) { int srcIndex = GetVertexIndex(src); int dstIndex = GetVertexIndex(dst); assert(srcIndex != -1); assert(dstIndex != -1); if (_isDirected) { _matrix[srcIndex][dstIndex] = weight; } else { _matrix[srcIndex][dstIndex] = weight; _matrix[dstIndex][srcIndex] = weight; } } void Display() { for (int i = 0; i < _vertexSize; ++i) { cout<<_vertexs[i]<<" "; } cout<<endl<<endl; for (int i = 0; i < _vertexSize; ++i) { for (int j = 0; j < _vertexSize; ++j) { cout<<_matrix[i][j]<<" "; } cout<<endl; } cout<<endl; } private: W** _matrix; // 臨接矩陣 V* _vertexs; // 頂點集 int _vertexSize; // 頂點數 //int _edgeSize; // 邊條數 bool _isDirected; }; // 無向圖 void Test1() { GraphMatrix<char, int> g("ABCDE", 5, false); g.AddEdge('A', 'D', 10); g.AddEdge('A', 'E', 20); g.AddEdge('B', 'C', 10); g.AddEdge('B', 'D', 20); g.AddEdge('B', 'E', 30); g.AddEdge('C', 'E', 40); g.Display(); } // 有向圖 void Test2() { GraphMatrix<char, int> g("ABCDE", 5, true); g.AddEdge('A', 'D', 10); g.AddEdge('E', 'A', 20); g.AddEdge('B', 'C', 10); g.AddEdge('D', 'B', 20); g.AddEdge('E', 'B', 30); g.AddEdge('C', 'E', 40); g.Display(); } // // 臨接表 // template<class V, class W> struct LinkEdge { int _srcIndex; // 源頂點下標 int _dstIndex; // 目標頂點下標 W _weight; // 權重 LinkEdge<V, W>* _next; // 指向下一個節點的指針 LinkEdge(int srcIndex = -1, int dstIndex = -1, const W& weight = W()) :_srcIndex(srcIndex) ,_dstIndex(dstIndex) ,_weight(weight) ,_next(NULL) {} }; template<class V, class W> struct CompareLinkEdge { bool operator()(LinkEdge<V, W>* lhs, LinkEdge<V, W>* rhs) { return lhs->_weight < rhs->_weight; } }; template<class V, class W> class GraphLink { protected: vector<V> _vertexs; // 頂點集合 vector<LinkEdge<V,W>*> _linkTables; // 臨接表 bool _isDirected; // 是否是有向圖 public: GraphLink(bool isDirected = false) :_isDirected(isDirected) {} GraphLink(const V* ar, int size, bool isDirected = false) :_isDirected(isDirected) { _vertexs.resize(size); _linkTables.resize(size); for (size_t i = 0; i < size; ++i) { _vertexs[i] = ar[i]; } } public: int GetVertexIndex(const V& vertex) { for (int i = 0; i < _vertexs.size(); ++i) { if(_vertexs[i] == vertex) return i; } return -1; } void _AddEdge(int srcIndex, int dstIndex, const W& weight) { LinkEdge<V, W>* tmp = new LinkEdge<V, W>(srcIndex, dstIndex, weight); tmp->_next = _linkTables[srcIndex]; _linkTables[srcIndex] = tmp; } void AddEdge(const V& src, const V& dst, const W& weight) { int srcIndex = GetVertexIndex(src); int dstIndex = GetVertexIndex(dst); assert(srcIndex != -1); assert(dstIndex != -1); // 無向圖 if(_isDirected) { _AddEdge(srcIndex, dstIndex, weight); } else { _AddEdge(srcIndex, dstIndex, weight); _AddEdge(dstIndex, srcIndex, weight); } } void Display() { for (int i = 0; i < _vertexs.size(); ++i) { cout<<_vertexs[i]<<"["<<i<<"]->"; LinkEdge<V, W>* begin = _linkTables[0]; while (begin) { cout<<begin->_weight<<"["<<begin->_dstIndex<<"]""->"; begin = begin->_next; } cout<<"NULL"<<endl; } cout<<endl; } // 獲取臨接表里的下一條邊 LinkEdge<V,W>* _GetNextEdge(int src, int cur) { LinkEdge<V,W>* edge = _linkTables[src]; while (edge) { if (edge->_dstIndex == cur) { return edge->_next; } edge = edge->_next; } return NULL; } void DFS() { cout<<"DFS:"; bool* visited = new bool[_vertexs.size()]; memset(visited, false, sizeof(bool)*_vertexs.size()); for (size_t i = 0; i < _vertexs.size(); ++i) { if (visited[i] == false) { // 1.訪問當前節點 cout<<_vertexs[i]<<" "; visited[i] = true; _DFS(i, visited); } } delete[] visited; cout<<endl; } void _DFS(int src, bool* visited) { // 2.獲取當前臨接表的第一個頂點 LinkEdge<V,W>* edge = _linkTables[src]; // 3.依次獲取臨接表后面的頂點進行深度優先遍歷 while (edge) { if (visited[edge->_dstIndex] == false) { cout<<_vertexs[edge->_dstIndex]<<" "; visited[edge->_dstIndex] = true; _DFS(edge->_dstIndex, visited); } edge = edge->_next; } } void BFS() { cout<<"BFS:"; bool* visited = new bool[_vertexs.size()]; memset(visited, false, sizeof(bool)*_vertexs.size()); for (size_t i = 0; i < _vertexs.size(); ++i) { if (visited[i] == false) { _BFS(i, visited); } } delete[] visited; cout<<endl; } void _BFS(int cur, bool* visited) { cout<<_vertexs[cur]<<" "; visited[cur] = true; queue<int> q; q.push(cur); while (!q.empty()) { cur = q.front(); q.pop(); LinkEdge<V,W>* edge = _linkTables[cur]; while (edge) { if (visited[edge->_dstIndex] == false) { cout<<_vertexs[edge->_dstIndex]<<" "; visited[edge->_dstIndex] = true; q.push(edge->_dstIndex); } edge = edge->_next; } } } bool Kruskal(GraphLink& minSpanTree) { // 1.初始化最小生成樹 minSpanTree._vertexs = _vertexs; minSpanTree._linkTables.resize(_vertexs.size()); minSpanTree._isDirected = _isDirected; // // 2.將所有的邊放到一個最小堆 // 假設有V個頂點,E條邊 // Heap<LinkEdge<V,W>*, CompareLinkEdge<V,W>> minHeap; for (int i = 0; i < _vertexs.size(); ++i) { LinkEdge<V, W>* begin = _linkTables[i]; while (begin) { // 無向圖的邊需要進行過濾 if (begin->_srcIndex < begin->_dstIndex) { minHeap.Push(begin); } begin = begin->_next; } } // 3.使用并差集和最小堆構建最小生成樹 UnionFindSet UFSet(_vertexs.size()); int count = _vertexs.size(); while (--count) { if (minHeap.Empty()) { return false; } LinkEdge<V,W>* edge = minHeap.Top(); minHeap.Pop(); int src = UFSet.FindRoot(edge->_srcIndex); int dst = UFSet.FindRoot(edge->_dstIndex); if(src != dst) { UFSet.Union(src, dst); minSpanTree._AddEdge(edge->_srcIndex, edge->_dstIndex, edge->_weight); } } return true; } bool Prim(GraphLink& minSpanTree) { // 1.初始化最小生成樹 minSpanTree._vertexs = _vertexs; minSpanTree._linkTables.resize(_vertexs.size()); minSpanTree._isDirected = _isDirected; bool* visitedSet = new bool[_vertexs.size()]; memset(visitedSet, false, sizeof(bool)*_vertexs.size()); int src = 0; visitedSet[src] = true; Heap<LinkEdge<V,W>*, CompareLinkEdge<V,W>> minHeap; int count = 1; do { // 2.取出一個頂點所有未訪問過的臨接邊放到一個最小堆里面 LinkEdge<V, W>* edge = _linkTables[src]; while(edge) { if (visitedSet[edge->_dstIndex] == false) { minHeap.Push(edge); } edge = _GetNextEdge(src, edge->_dstIndex); } // 2.選出堆中最小的邊加入生成樹 while(!minHeap.Empty() && count < _vertexs.size()) { edge = minHeap.Top(); minHeap.Pop(); if (visitedSet[edge->_dstIndex] == false) { minSpanTree._AddEdge(edge->_srcIndex, edge->_dstIndex,edge->_weight); visitedSet[edge->_dstIndex] = true; src = edge->_dstIndex; ++count; break; } } }while (count < _vertexs.size()); return true; } W _GetWeight(int src, int dst, const W& maxValue) { if (src == dst) return maxValue; LinkEdge<V,W>* edge = _linkTables[src]; while (edge) { if (edge->_dstIndex == dst) { return edge->_weight; } edge = edge->_next; } return maxValue; } // 非負單源最短路徑--Dijkstra(迪科斯徹) // 求src到其他頂點的最短路徑 void _Dijkstra(int src, W* dist, int* path, bool* vSet, int size, const W& maxValue) { // // 1.dist初始化src到其他頂點的的距離 // 2.path初始化src到其他頂點的路徑 // 3.初始化頂點集合 // for (int i = 0; i < size; ++i) { dist[i] = _GetWeight(src, i, maxValue); path[i] = src; vSet[i] = false; } // 將src加入集合 vSet[src] = true; int count = size; while(count--) { // // 選出與src頂點連接的邊中最小的邊 // src->min W min = maxValue; int minIndex = src; for (int j = 0; j < size; ++j) { if (vSet[j] == false && dist[j] < min) { minIndex = j; min = dist[j]; } } vSet[minIndex] = true; for (int k = 0; k < size; ++k) { if(k == src) continue; // // 更新src->k的距離 // 如果dist(src,min)+dist(min, k)的權值小于dist(src, k) // 則更新dist(src,k)和path(src->min->k) // W w = _GetWeight(minIndex, k, maxValue); if (vSet[k] == false && dist[minIndex] + w < dist[k]) { dist[k] = dist[minIndex] + w; path[k] = minIndex; } } } } void _Dijkstra_OP(int src, W* dist, int* path, bool* vSet, int size, const W& maxValue) { // // 1.dist初始化src到其他頂點的的距離 // 2.path初始化src到其他頂點的路徑 // 3.初始化頂點集合 // for (int i = 0; i < size; ++i) { dist[i] = _GetWeight(src, i, maxValue); path[i] = src; vSet[i] = false; } struct Compare { bool operator()(const pair<W, int>& lhs, const pair<W, int>& rhs) { return lhs.first < rhs.first; } }; Heap<pair<W, int>, Compare> minHeap; for (int i = 0; i < size; ++i) { if (dist[i] < maxValue) { minHeap.Push(make_pair(dist[i], i)); } } // 將src加入集合 vSet[src] = true; int count = size; while(count--) { // // 選出與src頂點連接的邊中最小的邊 // src->min if (minHeap.Empty()) continue; int minIndex = minHeap.Top().second; minHeap.Pop(); vSet[minIndex] = true; for (int k = 0; k < size; ++k) { // // 如果dist(src->min)+dist(min, k)的權值小于dist(src, k) // 則更新dist(src,k)和path(src->min->k) // W w = _GetWeight(minIndex, k, maxValue); if (vSet[k] == false && dist[minIndex] + w < dist[k]) { dist[k] = dist[minIndex] + w; path[k] = minIndex; minHeap.Push(make_pair(dist[k], k)); } } } } void PrintPath(int src, W* dist, int* path, int size) { int* vPath = new int[size]; for (int i = 0; i < size; ++i) { if (i != src) { int index = i, count = 0; do{ vPath[count++] = index; index = path[index]; }while (index != src); vPath[count++] = src; //cout<<"頂點:"<<_linkTable[src]._vertex\ <<"->頂點:"<<_linkTable[i]._vertex<<"的路徑為:"; cout<<src<<","<<i<<"的路徑為:"; while(count) { //cout<<_linkTable[ vSet[--count] ]._vertex<<"->"; cout<<vPath[--count]<<"->"; } cout<<"路徑長度為:"<<dist[i]<<endl; } } } void Dijkstra(int src, const W& maxValue) { W* dist = new W[_vertexs.size()]; int* path = new int[_vertexs.size()]; bool* vSet = new bool[_vertexs.size()]; //_Dijkstra(src, dist, path, vSet, _vertexs.size(), maxValue); _Dijkstra_OP(src, dist, path, vSet, _vertexs.size(), maxValue); // 打印最短路徑 PrintPath(src, dist, path, _vertexs.size()); delete[] dist; delete[] path; delete[] vSet; } }; // 無向圖 void Test3() { GraphLink<char, int> g("ABCDE", 5, false); g.AddEdge('A', 'D', 10); g.AddEdge('A', 'E', 20); g.AddEdge('B', 'C', 10); g.AddEdge('B', 'D', 20); g.AddEdge('B', 'E', 30); g.AddEdge('C', 'E', 40); g.Display(); // 生成最小生成樹 GraphLink<char, int> minSpanTree1(false); g.Kruskal(minSpanTree1); minSpanTree1.Display(); // 生成最小生成樹 GraphLink<char, int> minSpanTree2(false); g.Prim(minSpanTree2); minSpanTree2.Display(); g.DFS(); g.BFS(); } // 有向圖 void Test4() { GraphLink<char, int> g("ABCDE", 5, true); g.AddEdge('A', 'D', 10); g.AddEdge('E', 'A', 20); g.AddEdge('B', 'C', 10); g.AddEdge('D', 'B', 20); g.AddEdge('E', 'B', 30); g.AddEdge('C', 'E', 40); g.AddEdge('A', 'C', 50); g.AddEdge('A', 'E', 50); g.Display(); g.Dijkstra(0, 10000); //g.Dijkstra(1, 10000); }
以上
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。