數據結構(構造連通網的最小生成樹)

普利姆算法算法

  形象問題:幾個村莊之間有N條路,要再路邊修下水管道,求在那些路上修管道能在所有村莊連通的基礎上使修的管道最短數組

  中心思想:從一個頂點逐漸鏈接到所有頂點;在鏈接過程當中找權最小的邊加入生成樹中spa

方法code

  • 規定從第一個結點出發,找到鏈接的邊中權最小的
  • 將這條邊加入生成樹中
  • 循環①,②步,不斷找到鏈接一個頂點的權最小的邊,直到鏈接玩所有頂點
  • 頂點和這些邊就構成了連通網的最小生成樹

 1 //G是一個圖結構體:
 2 //numVertexes:頂點個數
 3 //arc:鄰接矩陣
 4 void MinSpanTree_prim(MGraph G){
 5     int min , i , j , k;
 6     int adjvax[MAXVEX];//到該位置對應頂點的最短路徑的邊的另外一個頂點【方便找到邊後打印這條邊的兩個頂點下標】
 7     int lowcost[MAXVEX];//鏈接到下標對應頂點的邊的最小權【爲0表示已經找到;INFINITY表示還沒找到;其餘表示:目前爲止的值】
 8             //既然說是目前爲止,是由於之後鏈接到其餘頂點,還會添加可選擇的邊;在這些新加的邊中可能會刷新鏈接它的邊的權最小記錄
 9 
10     lowcost[0]=0;//第一個頂點做爲最小生成樹的根,權直接爲0
11     adjvax[0]=0;//第一個頂點先加入
12 
13     //初始化操做
14     for(i=1;i<G.numVertexes;i++){
15         lowcost[i]=G.arc[0][i];//將鄰接矩陣第0行全部權值加入數組(從第一個頂點開始到其餘頂點的權)
16         adjvax[i]=0;//初始化所有爲第一個頂點的下標
17     }
18 
19     //開始構建最下生成樹
20     for(i=1;i<G.numVertexes;i++){//鏈接N個頂點,找N-1條邊,分別從一個頂點找到其餘N-1個頂點
21         min = INFINITY;//記錄最小權值;初始化爲65535;
22         j=1;//循環使用的索引值
23         k=0;//記錄此次鏈接到的頂點的下標
24 
25         //遍歷所有頂點
26         while(j<G.numVertexes){//找到可鏈接的最小權
27             if(lowcost[j]!=0 && lowcost[j]<min){
28                 min=lowcost[j];
29                 k=j;//將找到的最小權值下標存入k;
30             }
31             j++;
32         }
33 
34         printf("(%d,%d)  ",adjcex[k],k);//打印當前頂點邊中權值最小的邊;adjcex[k],邊的起始下標;k,當前位置
35         lowcost[k]=0;//將當前頂點的權值設置爲0,表示此頂點已經鏈接到生成樹中,繼續進行鏈接下一個頂點
36 
37         //鄰接矩陣k行逐個遍歷所有頂點
38         for(j=1;j<G.numVertexes;j++){
39             if(lowcost[j]!=0 && G.[k][j] < lowcost[j]){
40                 lowcost[j]=G.arc[k][j];//剛剛鏈接的頂點下標k,鏈接到j位置頂點的權小於原先鏈接到j位置的權;那麼就刷新鏈接他的最小權
41                 adjvax[j]=k;//將刷新鏈接j位置最小權的頂點的下標記錄到adjvax數組j位置下;利用該值打印這條權最小記錄的邊:(adjvax[k],k)
42             }
43         }
44     }
45 }

克魯斯卡爾算法blog

  直接去找權最小的邊來構建生成樹(構建過程當中只要避免構成環便可)排序

方法索引

  • 將圖中全部邊以權排序成邊集,圖中頂點去掉所有邊(構成樹林)
  • 遍歷邊集數組,檢測每條邊依附的兩頂點是否在同一顆樹中【不在的話鏈接兩頂點(樹)組成一顆樹;若在鏈接後就會構成環,因此捨棄這種邊】
  • 遍歷完邊集數組時就構造出了最小生成樹

 1 int find(int *parent,int f){
 2     while(parent[f]>0){
 3         f=parent[f];
 4     }
 5     return f;
 6 }
 7 //parent數組:存儲當前位置對應頂點在一棵樹上的另外一個頂點的對應下標
 8     //因此剛開始時,存儲下標對應的頂點是與自身位置對應頂點是直接相連的
 9     //當這個位置構建最小生成樹會直接相連一個頂點以上時,那麼下一個鏈接頂點下標會存儲在第一個鏈接下標頂點對應位置
10     //例如:0下標頂點構建最小生成樹時會鏈接1下標和3下標兩個頂點對應位置頂點;那麼:parent[0]=1;parent[1]=3;或者parent[0]=3;parent[3]=1
11 //總之parent數組中將同一顆樹頂點的下標利用相似鏈表的方法鏈接在一塊兒;
12     //給f傳入一顆樹任意頂點對應的下標返回的值(x)都是同樣的;而且在parent[x]這個位置是存放這顆樹下一次新加的頂點下標的
13 
14 //Kruskal算法生成最小生成樹
15 void MiniSpanTree_Kruskal(MGraph G){
16     int i,n,m;
17     Edge edges[MAGEDGE];//定義邊集數組
18     int parent[MAGEDGE];//定義parent數組用來判斷邊與邊是否造成環路
19 
20     for(i=0;i<G.numVertexes;i++){
21         parent[i]=0;
22     }
23     for(i=0;i<G.numEdges;i++){
24         //edges:邊集數組;邊的結構:begin,起點;end,終點;weight,這條邊的權
25         //n獲得的是edges[i].begin這個下標所屬樹下一次新加頂點下標在prent數組中存儲位置
26         //m獲得的值也有edges[i].end頂點所屬樹的相同做用
27         //因此m==n就說明兩頂點屬於同一顆樹(已經間接鏈接了,不須要再重複直接鏈接了;也就是不要造成環路)
28         //只有所屬不一樣樹時才同時有添加的能力,合併兩棵樹至關於要用掉一棵樹的添加能力,合併後的數的添加能力就要原先被添加樹承擔
29         n=find(parent,edges[i].begin);
30         m=find(parent,edges[i].end);
31         if(n!=m){//若是n==m,則造成環路
32             parent[n]=m;//將此邊的結尾頂點放入下標起點的parent數組中,表示此頂點已經在生成樹集合中
33             printf("(%d,%d)%d  ",edges[i].begin,edges[i].end,edges[i].weight);
34         }
35     }
36 }
相關文章
相關標籤/搜索