日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【数据结构-图】2.多图详解最小生成树(多图详解+实现代码)

發布時間:2025/3/20 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【数据结构-图】2.多图详解最小生成树(多图详解+实现代码) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最小生成樹:

這個定義有兩個約束:最小和樹

對于樹,從而引出以下三個最小生成樹的特點

  • 在圖中無環
  • 連接所有圖中的點
  • N個頂點,有N-1條邊
  • 最小:指的是生成這棵樹的邊的權值之和最小

    最小生成樹的求取有兩種經典的算法,分別是Prim(普里姆) 算法和Kruskal(克魯斯卡爾)算法

    這兩種算法的算法思想都是基于貪心算法的,也就是選擇權值最小的邊,但是這兩種算法的實現方法不同

    Prim(普里姆)算法:從頂點出發,優先選擇與連接兩個頂點集合中的權值最小的邊

    Kruskal(克魯斯卡爾)算法:直接選擇權值最小的邊


    Prim(普里姆)算法

    prim算法的核心是實時更新三個列表信息構成的

    第一個列表selected,是判斷是否已選頂點,若為true,表示頂點已選,若為false,表示頂點未選,初始為false;

    第二個列表minDist,表示兩個點之間的距離,初始為∞(無窮大);

    第三個列表parent,存放它的雙親結點,初始為-1

  • 整個生成過程是,首先(Update)更新列表信息,從列表下標由小到大更新minDist列表
  • 然后(Scan)掃描整個列表,更新parent列表
  • 最后(Add)將選擇的點添加到已選頂點中,也就是更新selected列表
  • 圖示過程

    如下圖

    第一個列表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(V2),不依賴于 ∣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(克魯斯卡爾)算法

  • 把圖中所有的邊和權重放入一個列表,并按權值從小到大排序
  • 從列表中按次序每次選擇一條邊放入圖中(此時邏輯上圖中只有頂點沒有邊)
  • 在放入圖中需要做判斷,圖中是否形成環
  • 若沒有環,則這條邊成為最小生成樹的一條邊
  • 相反,如果加上這條邊后形成了環,那么這邊就被丟棄,繼續將下一條邊放入圖中
  • 重復步驟2到步驟5
  • 直到選擇了n-1條邊,算法完成
  • 圖示過程

    存在一張圖,它有6個點和10條邊,如圖a所示,最后完成Kruskal算法后,會有5條邊被選定(即挑選完符合條件的5條邊)。

    圖a各邊權值如下,現在將邊和權重放入一個列表,并按權值從小到大排序。

  • 從列表中按次序選擇v1-v3放入圖中,該邊權重為1,此時圖中不存在環,所以V1-V3被選定,且此時邊數為1,如圖b
  • 從列表中按次序選擇v4-v6放入圖中,該邊權重為2,此時圖中不存在環,所以V4-V6被選定,且此時邊數為2,如圖c
  • 從列表中按次序選擇v2-v5放入圖中,該邊權重為3,此時圖中不存在環,所以v2-v5被選定,且此時邊數為3,如圖d
  • 從列表中按次序選擇v3-v6放入圖中,該邊權重為4,此時圖中不存在環,所以v3-v6被選定,且此時邊數為4,如圖e
  • 從列表中按次序選擇v1-v4放入圖中,該邊權重為5,但此時圖中存在環,所以v1-v4不能被選定,且此時邊數仍為4,如圖f
  • 從列表中按次序選擇v3-v4放入圖中,該邊權重為5,但此時圖中存在環,所以v3-v4不能被選定,且此時邊數仍為4,如圖g
  • 從列表中按次序選擇v2-v3放入圖中,該邊權重為5,此時圖中不存在環,所以v2-v3被選定,如圖h,且此時邊數為5,最小生成樹生成完畢

  • Prim算法的時間復雜度 O(∣E∣log∣E∣)O(|E|log|E|)O(ElogE),因此它適用于求解邊稀疏(頂點較多)的圖的最小生成樹。

    代碼提示
    /** @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.多图详解最小生成树(多图详解+实现代码)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。