【数据结构-图】2.多图详解最小生成树(多图详解+实现代码)
最小生成樹:
這個定義有兩個約束:最小和樹
對于樹,從而引出以下三個最小生成樹的特點
最小:指的是生成這棵樹的邊的權值之和最小
最小生成樹的求取有兩種經典的算法,分別是Prim(普里姆) 算法和Kruskal(克魯斯卡爾)算法
這兩種算法的算法思想都是基于貪心算法的,也就是選擇權值最小的邊,但是這兩種算法的實現方法不同
Prim(普里姆)算法:從頂點出發,優先選擇與連接兩個頂點集合中的權值最小的邊
Kruskal(克魯斯卡爾)算法:直接選擇權值最小的邊
Prim(普里姆)算法
prim算法的核心是實時更新三個列表信息構成的
第一個列表selected,是判斷是否已選頂點,若為true,表示頂點已選,若為false,表示頂點未選,初始為false;
第二個列表minDist,表示兩個點之間的距離,初始為∞(無窮大);
第三個列表parent,存放它的雙親結點,初始為-1
圖示過程
如下圖
第一個列表selected,是判斷是否已選頂點,若為T,表示頂點已選,若為F,表示頂點未選,初始為F;
第二個列表minDist,表示兩個點之間的距離,初始為inf(無窮大);
第三個列表parent,存放它的雙親結點,初始為-1
與V1相連接的點分別是V2,V3,V4,在列表中minDist和列表parent中更新數據,找到minDist最小且selected列表為F的結點,就是連接結點,即下圖中為V3
與V1,V3相連接的點分別是V2,V4,V5,V6,在列表中minDist和列表parent中更新數據,找到minDist最小且selected列表為F的結點,就是連接結點,即下圖中為V6
與V1,V3,V6相連接的點分別是V2,V4,V5,在列表中minDist和列表parent中更新數據,找到minDist最小且selected列表為F的結點,就是連接結點,即下圖中為V4
與V1,V3,V6,V4相連接的點分別是V2,V5,在列表中minDist和列表parent中更新數據,找到minDist最小且selected列表為F的結點,就是連接結點,即下圖中為V2
與V1,V3,V6,V4,V2相連接的點分別是V5,在列表中minDist和列表parent中更新數據,找到minDist最小且selected列表為F的結點,就是連接結點,即下圖中為V5,是selected列表中的值都為T,生成最小生成樹完畢
Prim算法的時間復雜度 O(∣V∣2)O(|V|^2)O(∣V∣2),不依賴于 ∣E∣|E|∣E∣,因此它適用于求解邊稠密的圖的最小生成樹。
代碼提示
void Prim(MGraph g, int v) {//普利姆算法(參數:鄰接矩陣,起點(即第一個生成的點,可隨便取))int lowcost[MAXV], closest[MAXV], i, min, j, k;//賦初值,即將closest數組都賦為第一個節點v,lowcost數組賦為第一個節點v到各節點的權重for (i = 0; i < g.n; i++) {closest[i] = v;lowcost[i] = g.edges[v][i];}//接下來找剩下的n-1個節點(g.n是圖的節點個數)for (i = 1; i < g.n; i++) {min = INF;//遍歷所有節點for (j = 0; j < g.n; j++) {//若該節點還未被選且權值小于之前遍歷所得到的最小值if (lowcost[j] != 0 && lowcost[j] < min) { //更新min的值min = lowcost[j];//記錄當前最小權重的節點的編號k = j;}}//表明k節點已被選了(作標記)lowcost[k] = 0;//遍歷所有節點for (j = 0; j < g.n; j++) {if (g.edges[k][j] != 0 && g.edges[k][j] < lowcost[j]) {//更新lowcost數組,closest數組//更新權重,使其當前最小lowcost[j] = g.edges[k][j];//進入到該if語句里,說明剛選的節點k與當前節點j有更小的權重,則closest[j]的被連接節點需作修改為kclosest[j] = k;}}} }Kruskal(克魯斯卡爾)算法
圖示過程
存在一張圖,它有6個點和10條邊,如圖a所示,最后完成Kruskal算法后,會有5條邊被選定(即挑選完符合條件的5條邊)。
圖a各邊權值如下,現在將邊和權重放入一個列表,并按權值從小到大排序。
Prim算法的時間復雜度 O(∣E∣log∣E∣)O(|E|log|E|)O(∣E∣log∣E∣),因此它適用于求解邊稀疏(頂點較多)的圖的最小生成樹。
代碼提示
/** @Prama:傳進來一個edge和weight列表mapnode,* @Prama:一個結點數v* @return:nums<map<pair<int,int>,int> >,返回一棵最小生成樹*/ stack<map<pair<int,int>,int> > kruskal(nums<map<pair<int,int>,int> > mapnode, int v){// 按weight從小到大排列,也就是map<pair<int,int>,int>中的對應值sort_weight(mapnode);// 最小生成樹的邊棧stack<map<pair<int,int>,int> > ans; int edge=0;// 邊 = 頂點數 - 1;while(edge<v){ans.push_back(nums[i]);edge++;// 有環,將插入的邊去掉,同時掃描下一條邊if (isLoop(ans)) {ans.pop();edge--;}i++;} }總結
以上是生活随笔為你收集整理的【数据结构-图】2.多图详解最小生成树(多图详解+实现代码)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【数据结构-图】1.图的构造和遍历(基本
- 下一篇: 【数据结构-图】3.图的最短路径的几种算