亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

【算法和數據結構】1.10--圖的最小生成樹之Kruskal算法(C++實現)

2019-11-06 07:04:09
字體:
來源:轉載
供稿:網友

      在前面兩節圖和圖的最小生成樹之PRim算法的基礎上,這里給出另外一種求解MST(最小生成樹)的算法—–Kruskal算法。

       Kruskal算法可以概括為:

取出連通無向圖G的所有邊。從第一步形成的邊集合中選取權值最小的邊,加入最小生成樹邊集合T中。求出第二步中選出邊的兩端頂點,判斷他們所在頂點集的關系以確認是否存在回路。若不存在回路,則確認將此最小邊加入T中,若存在回路,則丟棄。

       同Prim算法,我們用下面這一連通無向圖作為示例: 這里寫圖片描述

       下面給出實現代碼以及測試代碼:(在圖以及Prim算法的基礎上增加而來,若讀者覺得閱讀有困難,可參看前兩節文章)

#include<iostream>#include<cstdlib>#include<vector>using namespace std;/*節點類*/class Node{public: Node(char identifier = 0); char m_identifier; //頂點編號 bool m_isVisited; //頂點訪問標志位:true表示已經被訪問};Node::Node(char identifier){ m_identifier = identifier; m_isVisited = false;}/*邊類,用于輔助實現生成最小生成樹*/class Edge{public: Edge(int NodeIndexA = 0, int NodeIndexB = 0, int WeightValue = 0); int m_NodeIndexA, m_NodeIndexB; //邊的兩端點(索引),這里以無向圖為例 int m_weightValue; //邊的權值 bool m_selected; //選擇標志位,true表示已被選擇};Edge::Edge(int NodeIndexA, int NodeIndexB, int WeightValue){ m_NodeIndexA = NodeIndexA; m_NodeIndexB = NodeIndexB; m_weightValue = WeightValue; m_selected = false; //初始時未被選擇}/*圖類*/class Graph{public: Graph(int capacity); ~Graph(); int getGraphSize(); //獲取當前圖的大小 void resetNode(); //重置所有頂點的訪問標志位為false,未訪問 bool addNode(Node *pNode); //添加新頂點 bool addEdgeForUndirectedGraph(int row, int col, int val = 1); //添加邊以構造無向圖,val表示權值,默認權值1 bool addEdgeForDirectedGraph(int row, int col, int val = 1); //添加邊以構造有向圖,val表示權值,默認權值1 void printMatrix(); //打印鄰接矩陣 void depthFirstTraverse(int nodeIndex); //深度優先遍歷,指定第一個點 void widthFirstTraverse(int nodeIndex); //廣度優先遍歷,指定第一個點 void MSTPrim(int nodeIndex); //Prim算法求最小生成樹,指定第一個點 void MSTKruskal(); //Kruskal算法求最小生成樹,指定第一個點private: bool getValueOfEdge(int row, int col, int &val); //獲取邊權值 void widthFirstTraverseImplement(vector<int> preVec); //利用vector實現廣度優先遍歷 int getMinEdge(vector<Edge> edgeVec); //最小生成樹算法輔助函數,用于在邊集中選擇權值最小的邊 bool isInSet(vector<int> nodeSet, int target); //Kruskal輔助函數,用于判斷指定頂點是否在給定點集中 void mergeNodeSets(vector<int> &nodeSetA, vector<int> nodeSetB); //Kruscal輔助函數,用于合并兩個點集 int m_iCapacity; //圖容量,即申請的數組空間最多可容納的頂點個數 int m_iNodeCount; //圖的現有頂點個數 Node *m_pNodeArray; //存放頂點的數組 int *m_pMatrix; //為了方便,用一維數組存放鄰接矩陣 Edge *m_pEgde; //邊指針,存儲最小生成樹的邊};Graph::Graph(int capacity){ m_iCapacity = capacity; m_iNodeCount = 0; m_pNodeArray = new Node[m_iCapacity]; m_pMatrix = new int[m_iCapacity*m_iCapacity]; for (int i = 0;i < m_iCapacity*m_iCapacity;i++) //初始化鄰接矩陣 { m_pMatrix[i] = 0; } m_pEgde = new Edge[m_iCapacity - 1]; //最小生成樹節點和邊數量關系}Graph::~Graph(){ delete []m_pNodeArray; delete []m_pMatrix; delete []m_pEgde;}int Graph::getGraphSize(){ return m_iNodeCount;}void Graph::resetNode(){ for (int i = 0;i < m_iNodeCount;i++) { m_pNodeArray[i].m_isVisited = false; }}bool Graph::addNode(Node *pNode){ if (pNode == NULL) return false; m_pNodeArray[m_iNodeCount].m_identifier = pNode->m_identifier; m_iNodeCount++; return true;}bool Graph::addEdgeForUndirectedGraph(int row, int col, int val){ if (row < 0 || row >= m_iCapacity) return false; if (col < 0 || col >= m_iCapacity) return false; m_pMatrix[row*m_iCapacity + col] = val; m_pMatrix[col*m_iCapacity + row] = val; return true;}bool Graph::addEdgeForDirectedGraph(int row, int col, int val){ if (row < 0 || row >= m_iCapacity) return false; if (col < 0 || col >= m_iCapacity) return false; m_pMatrix[row*m_iCapacity + col] = val; return true;}void Graph::printMatrix(){ for (int i = 0;i < m_iCapacity;i++) { for (int k = 0;k < m_iCapacity;k++) cout << m_pMatrix[i*m_iCapacity + k] << " "; cout << endl; }}void Graph::depthFirstTraverse(int nodeIndex){ int value = 0; //訪問第一個頂點 cout << m_pNodeArray[nodeIndex].m_identifier << " "; m_pNodeArray[nodeIndex].m_isVisited = true; //訪問其他頂點 for (int i = 0;i < m_iCapacity;i++) { getValueOfEdge(nodeIndex, i, value); if (value != 0) //當前頂點與指定頂點連通 { if (m_pNodeArray[i].m_isVisited == true) //當前頂點已被訪問 continue; else //當前頂點沒有被訪問,則遞歸 { depthFirstTraverse(i); } } else //沒有與指定頂點連通 { continue; } }}void Graph::widthFirstTraverse(int nodeIndex){ //訪問第一個頂點 cout << m_pNodeArray[nodeIndex].m_identifier << " "; m_pNodeArray[nodeIndex].m_isVisited = true; vector<int> curVec; curVec.push_back(nodeIndex); //將第一個頂點存入一個數組 widthFirstTraverseImplement(curVec);}void Graph::widthFirstTraverseImplement(vector<int> preVec){ int value = 0; vector<int> curVec; //定義數組保存當前層的頂點 for (int j = 0;j < (int)preVec.size();j++) //依次訪問傳入數組中的每個頂點 { for (int i = 0;i < m_iCapacity;i++) //傳入的數組中的頂點是否與其他頂點連接 { getValueOfEdge(preVec[j], i, value); if (value != 0) //連通 { if (m_pNodeArray[i].m_isVisited==true) //已經被訪問 { continue; } else //沒有被訪問則訪問 { cout << m_pNodeArray[i].m_identifier << " "; m_pNodeArray[i].m_isVisited = true; //保存當前點到數組 curVec.push_back(i); } } } } if (curVec.size()==0) //本層次無被訪問的點,則終止 { return; } else { widthFirstTraverseImplement(curVec); }}bool Graph::getValueOfEdge(int row, int col, int &val){ if (row < 0 || row >= m_iCapacity) return false; if (col < 0 || col >= m_iCapacity) return false; val = m_pMatrix[row*m_iCapacity + col]; return true;}void Graph::MSTPrim(int nodeIndex){ int value = 0; //存儲當前邊的權值 int edgeCount = 0; //已選出的邊數量,用以判斷算法終結 vector<int> nodeVec; //存儲點(索引)集的數組 vector<Edge> edgeVec; //存儲邊的數組 cout << m_pNodeArray[nodeIndex].m_identifier << endl; nodeVec.push_back(nodeIndex); m_pNodeArray[nodeIndex].m_isVisited = true; while (edgeCount < m_iCapacity - 1) { int temp = nodeVec.back(); //將當前頂點索引復制給temp for (int i = 0;i < m_iCapacity;i++) //循環判斷每一個頂點與當前頂點連接情況 { getValueOfEdge(temp, i, value); if (value != 0) //連通 { if (m_pNodeArray[i].m_isVisited == true) //已經被訪問 continue; else //未被訪問,則將邊放入被選邊集合 { Edge edge(temp, i, value); edgeVec.push_back(edge); } } } /*選擇最小邊*/ int edgeIndex = getMinEdge(edgeVec); if (edgeIndex == -1) { cout << "獲取最小邊失敗,請重置后再試!" << endl; break; } edgeVec[edgeIndex].m_selected = true; //設置選擇標志位為true,已被選擇 cout << edgeVec[edgeIndex].m_NodeIndexA << "---" << edgeVec[edgeIndex].m_NodeIndexB<<" "; cout << edgeVec[edgeIndex].m_weightValue << endl; m_pEgde[edgeCount] = edgeVec[edgeIndex]; edgeCount++; /*尋找當前選擇的最小邊相連的下一個頂點*/ int nextNodeIndex = edgeVec[edgeIndex].m_NodeIndexB; nodeVec.push_back(nextNodeIndex); m_pNodeArray[nextNodeIndex].m_isVisited = true; cout << m_pNodeArray[nextNodeIndex].m_identifier << endl; } cout << "最小生成樹計算完畢,如上所示!";}void Graph::MSTKruskal(){ int value = 0; //存儲當前邊的權值 int edgeCount = 0; //已選出的邊數量 /*存放節點集合的數組,不同于Prim,Kruskal算法過程中可能出現多個點集*/ vector<vector<int>> nodeSets; /*取出所有邊*/ vector<Edge> edgeVec; for (int i = 0;i < m_iCapacity;i++) //去鄰接矩陣的右上角的三角部分,不含對角線。無向圖鄰接矩陣對稱 { for (int k = i + 1;k < m_iCapacity;k++) { getValueOfEdge(i, k, value); if (value != 0) { Edge edge(i, k, value); edgeVec.push_back(edge); } } } /*循環尋找最小生成樹的邊*/ while (edgeCount < m_iCapacity - 1) { int minEdgeIndex = getMinEdge(edgeVec); edgeVec[minEdgeIndex].m_selected = true; //選出最小邊,并標記為已選 int nodeAIndex = edgeVec[minEdgeIndex].m_NodeIndexA; int nodeBIndex = edgeVec[minEdgeIndex].m_NodeIndexB; //找出最小邊兩端頂點 bool nodeAIsInSet = false; //標記某個頂點是否在指定點集中 bool nodeBIsInSet = false; int nodeAInSetLabel = -1; //某個頂點所在點集的索引 int nodeBInSetLabel = -1; for (int i = 0;i < (int)nodeSets.size();i++) //尋找A頂點所在點集 { nodeAIsInSet = isInSet(nodeSets[i], nodeAIndex); if (nodeAIsInSet) { nodeAInSetLabel = i; //保存當前點集索引 } } for (int i = 0;i < (int)nodeSets.size();i++) //尋找B頂點所在點集 { nodeBIsInSet = isInSet(nodeSets[i], nodeBIndex); if (nodeBIsInSet) { nodeBInSetLabel = i; //保存當前點集索引 } } /*根據結果做相應處理*/ if (nodeAInSetLabel == -1 && nodeBInSetLabel == -1) //兩頂點均不在已有點集中 { //建立新的點集 vector<int> vec; vec.push_back(nodeAIndex); vec.push_back(nodeBIndex); nodeSets.push_back(vec); } else if (nodeAInSetLabel == -1 && nodeBInSetLabel != -1) //某頂點在已有點集中 { //將另外一個節點加入已有點集 nodeSets[nodeBInSetLabel].push_back(nodeAIndex); } else if (nodeAInSetLabel != -1 && nodeBInSetLabel == -1) { nodeSets[nodeAInSetLabel].push_back(nodeBIndex); } else if (nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel != nodeBInSetLabel) //兩個頂點在不同的點集中 { //合并兩個集合,到前一參數點集,并將頂點從第二個參數點集刪除 mergeNodeSets(nodeSets[nodeAInSetLabel], nodeSets[nodeBInSetLabel]); for (int k = nodeBInSetLabel;k < (int)nodeSets.size()-1;k++) { nodeSets[k] = nodeSets[k + 1]; } } else if (nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel == nodeBInSetLabel) //兩個頂點在同一點集 { //存在回路,放棄當前邊 continue; } m_pEgde[edgeCount] = edgeVec[minEdgeIndex]; edgeCount++; cout << edgeVec[minEdgeIndex].m_NodeIndexA << "---" << edgeVec[minEdgeIndex].m_NodeIndexB << " "; cout << edgeVec[minEdgeIndex].m_weightValue << endl; }}int Graph::getMinEdge(vector<Edge> edgeVec){ int minWeight = 0; //用于輔助選擇最小權值邊 int edgeIndex = 0; //用于存儲最小邊索引 int i = 0; /*找出第一條未被選擇的邊*/ for (;i < (int)edgeVec.size();i++) { if (edgeVec[i].m_selected == false) //當前邊未被選擇 { minWeight = edgeVec[i].m_weightValue; edgeIndex = i; break; } } if (minWeight == 0) //邊集所有邊被訪問 { return -1; } for (;i < (int)edgeVec.size();i++) { if (edgeVec[i].m_selected == true) continue; else { if (minWeight > edgeVec[i].m_weightValue) { minWeight = edgeVec[i].m_weightValue; edgeIndex = i; } } } return edgeIndex;}bool Graph::isInSet(vector<int> nodeSet, int target){ for (int i = 0;i < (int)nodeSet.size();i++) { if (nodeSet[i] == target) return true; } return false;}void Graph::mergeNodeSets(vector<int> &nodeSetA, vector<int> nodeSetB){ for (int i = 0;i < (int)nodeSetB.size();i++) { nodeSetA.push_back(nodeSetB[i]); }}int main(){ Graph *pGraph = new Graph(6); cout << "初始化頂點中……" << endl; Node *pNodeA = new Node('A'); Node *pNodeB = new Node('B'); Node *pNodeC = new Node('C'); Node *pNodeD = new Node('D'); Node *pNodeE = new Node('E'); Node *pNodeF = new Node('F'); cout << "添加頂點至圖中……" << endl; pGraph->addNode(pNodeA); pGraph->addNode(pNodeB); pGraph->addNode(pNodeC); pGraph->addNode(pNodeD); pGraph->addNode(pNodeE); pGraph->addNode(pNodeF); pGraph->addEdgeForUndirectedGraph(0, 1, 6); pGraph->addEdgeForUndirectedGraph(0, 4, 5); pGraph->addEdgeForUndirectedGraph(0, 5, 1); pGraph->addEdgeForUndirectedGraph(1, 5, 2); pGraph->addEdgeForUndirectedGraph(1, 2, 3); pGraph->addEdgeForUndirectedGraph(2, 5, 8); pGraph->addEdgeForUndirectedGraph(2, 3, 7); pGraph->addEdgeForUndirectedGraph(3, 5, 4); pGraph->addEdgeForUndirectedGraph(3, 4, 2); pGraph->addEdgeForUndirectedGraph(4, 5, 9); cout << "鄰接矩陣如下:" << endl; pGraph->printMatrix(); cout << endl << endl; cout << "深度優先遍歷:" << endl; pGraph->depthFirstTraverse(0); cout << endl << endl; pGraph->resetNode(); cout << "廣度優先遍歷:" << endl; pGraph->widthFirstTraverse(0); cout << endl << endl; pGraph->resetNode(); cout << "最小生成樹為:" << endl; pGraph->MSTKruskal(); cout << endl; system("pause");}

       測試結果如下: 這里寫圖片描述

       在文章開始對Kruskal算法的描述中,涉及到循環的每一次都要尋找最小邊的問題。我們可以換一種思路,作如下描述:

對G的邊以飛降序權重排序。對于排序表中的每條邊,如果現在把它加入T不會形成回路,則將其加入T集合中,否則丟棄。

      有興趣的讀者可以自己用這一種算法描述來改進Krukal算法,這樣就不需要每進行一次循環就需要調用getMinEdge()函數,可以減少算法時間開銷。這樣一來,若G含有m條邊,則其算法時間復雜度為O(m * log m)。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲国产精品专区久久| 久久99视频免费| 亚洲人成毛片在线播放| 欧美夜福利tv在线| 午夜精品一区二区三区在线视频| 欧美成人在线免费视频| 亚洲区一区二区| 久久人人97超碰精品888| 91久久精品美女高潮| 国产精品美女久久久久久免费| 欧美裸体xxxx极品少妇软件| 国产精品自产拍高潮在线观看| 午夜精品美女自拍福到在线| 国产一区私人高清影院| 国产精品一香蕉国产线看观看| 欧美成人午夜影院| 久久国产精品免费视频| 精品调教chinesegay| 欧美性xxxxxxxxx| 欧洲成人性视频| 亚洲第一福利网| 亚洲a成v人在线观看| 九九热在线精品视频| 亚洲欧美精品一区二区| 狠狠躁18三区二区一区| 精品久久久久久久久中文字幕| 96国产粉嫩美女| 亚洲欧美日韩在线高清直播| 91超碰caoporn97人人| 91精品久久久久久久久中文字幕| 91美女福利视频高清| 国产成人精品久久二区二区91| 久久人人爽人人爽爽久久| 成人精品在线视频| 国模吧一区二区三区| 亚洲视频自拍偷拍| 亚洲国产成人精品久久久国产成人一区| 国产不卡av在线免费观看| 久久99亚洲精品| 成人福利网站在线观看| 欧美日韩国产丝袜美女| 精品国产一区二区三区久久| 欧美在线精品免播放器视频| 欧美香蕉大胸在线视频观看| 91高清免费视频| 91国偷自产一区二区三区的观看方式| 欧美黄色三级网站| 亚洲最大成人免费视频| 国产精品久久久久7777婷婷| 亚洲日本中文字幕免费在线不卡| 欧美午夜精品久久久久久人妖| 国产精品高潮呻吟视频| 国产午夜精品理论片a级探花| 欧美另类高清videos| 久久国产精品久久精品| 欧美国产日韩精品| 日韩成人av在线| 亚洲xxxx妇黄裸体| 亚洲天堂网站在线观看视频| 欧美另类交人妖| 国产日韩精品视频| 中文字幕在线视频日韩| 欧美亚洲另类制服自拍| 欧美性xxxx极品高清hd直播| 久久影院资源网| 91久久精品国产91久久| 亚洲第一页中文字幕| 日韩精品高清视频| 91日本视频在线| 亚洲色图50p| 亚洲亚裔videos黑人hd| 亚洲精品美女免费| 欧美日韩国产中字| 亚洲成人性视频| 久久精品国产成人| 伊人久久大香线蕉av一区二区| 亚洲精品电影久久久| 国产精品亚洲第一区| 精品国产精品三级精品av网址| 国产婷婷色综合av蜜臀av| 96国产粉嫩美女| 日韩欧美黄色动漫| 亚洲va久久久噜噜噜久久天堂| 日韩性生活视频| 欧美性猛交视频| 欧美一级高清免费| www.久久久久| 精品国产区一区二区三区在线观看| 国产国产精品人在线视| 日韩精品999| 奇门遁甲1982国语版免费观看高清| 色综合天天狠天天透天天伊人| 欧美激情欧美激情在线五月| 最新69国产成人精品视频免费| 亚洲国产精品va在线看黑人| 97视频在线观看免费高清完整版在线观看| 91av在线精品| 久久影院资源站| 91麻豆国产精品| 日韩欧美国产高清91| 国产精品扒开腿做爽爽爽的视频| 欧美视频一二三| 亚洲人成在线观看网站高清| 亚洲在线观看视频网站| 国产精品亚洲综合天堂夜夜| 国产精品青青在线观看爽香蕉| 国产精品狼人色视频一区| 欧美黑人极品猛少妇色xxxxx| 91国产精品91| 国产精品白嫩初高中害羞小美女| 久久视频免费在线播放| 4k岛国日韩精品**专区| 日韩亚洲国产中文字幕| 欧美国产精品人人做人人爱| 亚洲黄色av女优在线观看| 亚洲高清免费观看高清完整版| 欧美激情精品久久久久久蜜臀| 久久伊人色综合| 激情成人中文字幕| 欧美精品videofree1080p| 亚洲国产成人精品久久| 中文字幕久久久| 亚洲女人天堂色在线7777| 午夜精品三级视频福利| 91精品久久久久久久久久另类| 亚洲自拍小视频| 欧美性xxxxhd| 欧美激情网友自拍| 91中文字幕在线观看| 亚洲嫩模很污视频| 久久久久久久久久久av| 国产日产欧美a一级在线| 亚洲毛茸茸少妇高潮呻吟| 97av在线影院| 亚洲自拍偷拍一区| 久久91精品国产| 久久成人免费视频| 亚洲视频日韩精品| 欧美精品激情在线观看| 久久在精品线影院精品国产| 久久青草精品视频免费观看| 在线观看日韩欧美| 国产精品久久激情| 久久精品福利视频| 日韩av在线网页| 国产玖玖精品视频| 日韩成人av在线播放| 国产精品久久久久99| 日韩二区三区在线| 红桃视频成人在线观看| 精品视频在线播放| 久久五月天色综合| 成人性生交xxxxx网站| 国产不卡av在线| 日韩中文字幕网站| 91国内揄拍国内精品对白| 九九精品在线视频| 日韩在线视频导航| 成人a在线视频| 国产精品爽黄69天堂a| 精品视频在线播放免| 精品国产一区av| 亚洲影影院av| 美女av一区二区|