最小生成樹,普利姆算法.
簡述算法:
先初始化一棵只有一個頂點的樹,以這一頂點開始,找到它的最小權值,將這條邊上的令一個頂點添加到樹中
再從這棵樹中的所有頂點中找到一個最小權值(而且權值的另一頂點不屬於這棵樹)
重復上一步.直到所有頂點並入樹中.
圖示:


注:以a點開始,最小權值為1,另一頂點是c,將c加入到最小生成樹中.樹中 a-c
在最小生成樹中的頂點找到一個權值最小且另一頂點不在樹中的,最小權值是4,另一個頂點是f,將f並入樹中, a-c-f
重復上一步驟,a-c-f-d, a-c-f-d-b, a-c-f-d-b-e.
鄰接矩陣的實現
我又構建了一個鄰接矩陣(prim_tree),將我們求出的最小生成樹寫入其中.
我們還需要一個visited數組,來確定一個頂點是否已被納入最小生成樹中.
1)初始化,visited數組,prim_tree節點信息,矩陣.1-11,41-55行
2)將一個頂點並入樹(prim_tree)中.以這個頂點開始,進行遍歷尋找最小權值.
這里用了三層循環嵌套.
i這一層的作用是遍歷圖的節點信息,我們要將所有節點都納入樹中.
j這一層的作用是遍歷樹的節點信息.(我們是通過visited數組來確定一個節點是否屬於最小生成樹的,19行,if的作用)
k這一層的作用是在j節點所在所在矩陣的行中找到最小權值.
(注:j和k配合,找到樹中的最小權值(最小權值的另一個節點沒有被納入樹中,23行if的作用).j查找的節點信息的下標,但矩陣是正方形的,所以j既是節點信息的下標,又是該節點在矩陣中的列位置.而k則在j這一列查找最小權值.當j將樹遍歷一遍,這時會找到一個最小權值,這個最小權值的另一個頂點就是我們將要納入樹中的節點.)
3)將上面獲得的信息寫入樹中.(寫入時也要判斷該節點是否已被納入樹中.沒有納入樹中的節點才會將其納入樹中.)
1 //最小生成樹prim算法 2 static void init_prim(Graph * graph, Graph * prim_tree); 3 void Prim(Graph * graph, Graph * prim_tree) 4 { 5 bool visited[graph->vertexs]; 6 int i, j, k, h; 7 int power, power_j, power_k; 8 9 for ( i = 0; i < graph->vertexs; i++ ) 10 visited[i] = false; 11 init_prim(graph, prim_tree); 12 13 visited[0] = true; 14 for ( i = 0; i < graph->vertexs; i++ ) 15 { 16 power = MAX_VALUE; 17 for ( j = 0; j < graph->vertexs; j++ ) 18 { 19 if ( visited[j] ) 20 { 21 for ( k = 0; k < graph->vertexs; k++ ) 22 { 23 if ( power > graph->arcs[j][k] && !visited[k] ) 24 { 25 power = graph->arcs[j][k]; 26 power_j = j; 27 power_k = k; 28 } 29 } 30 } 31 } 32 //min power 33 if ( !visited[power_k] ) 34 { 35 visited[power_k] = true; 36 prim_tree->arcs[power_j][power_k] = power; 37 } 38 } 39 } 40 41 static void init_prim(Graph * graph, Graph * prim_tree) 42 { 43 int i, j; 44 45 prim_tree->vertexs = graph->vertexs; 46 for ( i = 0; i < prim_tree->vertexs; i++ )//初始化節點 47 prim_tree->vertex[i] = graph->vertex[i]; 48 for ( i = 0 ; i < prim_tree->vertexs; i++ )//初始化矩陣 49 { 50 for ( j = 0; j < prim_tree->vertexs; j++ ) 51 { 52 prim_tree->arcs[i][j] = MAX_VALUE; 53 } 54 } 55 }
上述代碼適用於連通圖.
如果想運行這個程序,到http://www.cnblogs.com/ITgaozy/p/5187483.html找源碼,將上面的代碼粘到里面就可以了.
鄰接表的實現
算法和矩陣一樣,只是由於數據結構不同,在代碼上有些差別.
static void init_prim(Graph * graph, Graph * prim_tree); void g_prim(Graph * graph, Graph * prim_tree) { bool visited[graph->vertexs]; int i, j, k; int power, pos; Arc_node * tmp; for ( i = 0; i < graph->vertexs; i++ ) visited[i] = false; init_prim(graph, prim_tree); visited[0] = true; for ( i = 0; i < graph->vertexs; i++ ) { power = INT_MAX;//limits.h for ( j = 0; j < graph->vertexs; j++ ) { if ( visited[j] ) { tmp = graph->adjlist[j].next; while ( tmp != NULL ) { if ( power > tmp->distance && !visited[tmp->pos] ) { power = tmp->distance; pos = tmp->pos; k = j; } tmp = tmp->next; } } } if ( !visited[pos] ) { if ( prim_tree->adjlist[k].next == NULL ) { prim_tree->adjlist[k].next = make_node(pos, power); } else { tmp = prim_tree->adjlist[k].next; while ( tmp->next != NULL ) tmp = tmp->next; tmp->next = make_node(pos, power); } visited[pos] = true; } } } static void init_prim(Graph * graph, Graph * prim_tree) { int i; for ( i = 0; i < graph->vertexs; i++ ) { prim_tree->adjlist[i].info = graph->adjlist[i].info; prim_tree->adjlist[i].next = NULL; } prim_tree->vertexs = graph->vertexs; }
到http://www.cnblogs.com/ITgaozy/p/5187526.html里找到源碼,將上述代碼粘到源碼中,就可以了.
由於本人水平有限,不足之處還望大家不吝指教.
