prim算法和kruskal算法(C语言)
生活随笔
收集整理的這篇文章主要介紹了
prim算法和kruskal算法(C语言)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
prim算法:
/* 鄰接矩陣存儲 - Prim最小生成樹算法 */Vertex FindMinDist( MGraph Graph, WeightType dist[] ) { /* 返回未被收錄頂點中dist最小者 */Vertex MinV, V;WeightType MinDist = INFINITY;for (V=0; V<Graph->Nv; V++) {if ( dist[V]!=0 && dist[V]<MinDist) {/* 若V未被收錄,且dist[V]更小 */MinDist = dist[V]; /* 更新最小距離 */MinV = V; /* 更新對應頂點 */}}if (MinDist < INFINITY) /* 若找到最小dist */return MinV; /* 返回對應的頂點下標 */else return ERROR; /* 若這樣的頂點不存在,返回-1作為標記 */ }int Prim( MGraph Graph, LGraph MST ) { /* 將最小生成樹保存為鄰接表存儲的圖MST,返回最小權重和 */WeightType dist[MaxVertexNum], TotalWeight;Vertex parent[MaxVertexNum], V, W;int VCount;Edge E;/* 初始化。默認初始點下標是0 */for (V=0; V<Graph->Nv; V++) {/* 這里假設若V到W沒有直接的邊,則Graph->G[V][W]定義為INFINITY */dist[V] = Graph->G[0][V];parent[V] = 0; /* 暫且定義所有頂點的父結點都是初始點0 */ }TotalWeight = 0; /* 初始化權重和 */VCount = 0; /* 初始化收錄的頂點數 *//* 創建包含所有頂點但沒有邊的圖。注意用鄰接表版本 */MST = CreateGraph(Graph->Nv);E = (Edge)malloc( sizeof(struct ENode) ); /* 建立空的邊結點 *//* 將初始點0收錄進MST */dist[0] = 0;VCount ++;parent[0] = -1; /* 當前樹根是0 */while (1) {V = FindMinDist( Graph, dist );/* V = 未被收錄頂點中dist最小者 */if ( V==ERROR ) /* 若這樣的V不存在 */break; /* 算法結束 *//* 將V及相應的邊<parent[V], V>收錄進MST */E->V1 = parent[V];E->V2 = V;E->Weight = dist[V];InsertEdge( MST, E );TotalWeight += dist[V];dist[V] = 0;VCount++;for( W=0; W<Graph->Nv; W++ ) /* 對圖中的每個頂點W */if ( dist[W]!=0 && Graph->G[V][W]<INFINITY ) {/* 若W是V的鄰接點并且未被收錄 */if ( Graph->G[V][W] < dist[W] ) {/* 若收錄V使得dist[W]變小 */dist[W] = Graph->G[V][W]; /* 更新dist[W] */parent[W] = V; /* 更新樹 */}}} /* while結束*/if ( VCount < Graph->Nv ) /* MST中收的頂點不到|V|個 */TotalWeight = ERROR;return TotalWeight; /* 算法執行完畢,返回最小權重和或錯誤標記 */ }kruskal算法:
/* 鄰接表存儲 - Kruskal最小生成樹算法 *//*-------------------- 頂點并查集定義 --------------------*/ typedef Vertex ElementType; /* 默認元素可以用非負整數表示 */ typedef Vertex SetName; /* 默認用根結點的下標作為集合名稱 */ typedef ElementType SetType[MaxVertexNum]; /* 假設集合元素下標從0開始 */void InitializeVSet( SetType S, int N ) { /* 初始化并查集 */ElementType X;for ( X=0; X<N; X++ ) S[X] = -1; }void Union( SetType S, SetName Root1, SetName Root2 ) { /* 這里默認Root1和Root2是不同集合的根結點 *//* 保證小集合并入大集合 */if ( S[Root2] < S[Root1] ) { /* 如果集合2比較大 */S[Root2] += S[Root1]; /* 集合1并入集合2 */S[Root1] = Root2;}else { /* 如果集合1比較大 */S[Root1] += S[Root2]; /* 集合2并入集合1 */S[Root2] = Root1;} }SetName Find( SetType S, ElementType X ) { /* 默認集合元素全部初始化為-1 */if ( S[X] < 0 ) /* 找到集合的根 */return X;elsereturn S[X] = Find( S, S[X] ); /* 路徑壓縮 */ }bool CheckCycle( SetType VSet, Vertex V1, Vertex V2 ) { /* 檢查連接V1和V2的邊是否在現有的最小生成樹子集中構成回路 */Vertex Root1, Root2;Root1 = Find( VSet, V1 ); /* 得到V1所屬的連通集名稱 */Root2 = Find( VSet, V2 ); /* 得到V2所屬的連通集名稱 */if( Root1==Root2 ) /* 若V1和V2已經連通,則該邊不能要 */return false;else { /* 否則該邊可以被收集,同時將V1和V2并入同一連通集 */Union( VSet, Root1, Root2 );return true;} } /*-------------------- 并查集定義結束 --------------------*//*-------------------- 邊的最小堆定義 --------------------*/ void PercDown( Edge ESet, int p, int N ) { /* 改編代碼4.24的PercDown( MaxHeap H, int p ) *//* 將N個元素的邊數組中以ESet[p]為根的子堆調整為關于Weight的最小堆 */int Parent, Child;struct ENode X;X = ESet[p]; /* 取出根結點存放的值 */for( Parent=p; (Parent*2+1)<N; Parent=Child ) {Child = Parent * 2 + 1;if( (Child!=N-1) && (ESet[Child].Weight>ESet[Child+1].Weight) )Child++; /* Child指向左右子結點的較小者 */if( X.Weight <= ESet[Child].Weight ) break; /* 找到了合適位置 */else /* 下濾X */ESet[Parent] = ESet[Child];}ESet[Parent] = X; }void InitializeESet( LGraph Graph, Edge ESet ) { /* 將圖的邊存入數組ESet,并且初始化為最小堆 */Vertex V;PtrToAdjVNode W;int ECount;/* 將圖的邊存入數組ESet */ECount = 0;for ( V=0; V<Graph->Nv; V++ )for ( W=Graph->G[V].FirstEdge; W; W=W->Next )if ( V < W->AdjV ) { /* 避免重復錄入無向圖的邊,只收V1<V2的邊 */ESet[ECount].V1 = V;ESet[ECount].V2 = W->AdjV;ESet[ECount++].Weight = W->Weight;}/* 初始化為最小堆 */for ( ECount=Graph->Ne/2; ECount>=0; ECount-- )PercDown( ESet, ECount, Graph->Ne ); }int GetEdge( Edge ESet, int CurrentSize ) { /* 給定當前堆的大小CurrentSize,將當前最小邊位置彈出并調整堆 *//* 將最小邊與當前堆的最后一個位置的邊交換 */Swap( &ESet[0], &ESet[CurrentSize-1]);/* 將剩下的邊繼續調整成最小堆 */PercDown( ESet, 0, CurrentSize-1 );return CurrentSize-1; /* 返回最小邊所在位置 */ } /*-------------------- 最小堆定義結束 --------------------*/int Kruskal( LGraph Graph, LGraph MST ) { /* 將最小生成樹保存為鄰接表存儲的圖MST,返回最小權重和 */WeightType TotalWeight;int ECount, NextEdge;SetType VSet; /* 頂點數組 */Edge ESet; /* 邊數組 */InitializeVSet( VSet, Graph->Nv ); /* 初始化頂點并查集 */ESet = (Edge)malloc( sizeof(struct ENode)*Graph->Ne );InitializeESet( Graph, ESet ); /* 初始化邊的最小堆 *//* 創建包含所有頂點但沒有邊的圖。注意用鄰接表版本 */MST = CreateGraph(Graph->Nv);TotalWeight = 0; /* 初始化權重和 */ECount = 0; /* 初始化收錄的邊數 */NextEdge = Graph->Ne; /* 原始邊集的規模 */while ( ECount < Graph->Nv-1 ) { /* 當收集的邊不足以構成樹時 */NextEdge = GetEdge( ESet, NextEdge ); /* 從邊集中得到最小邊的位置 */if (NextEdge < 0) /* 邊集已空 */break;/* 如果該邊的加入不構成回路,即兩端結點不屬于同一連通集 */if ( CheckCycle( VSet, ESet[NextEdge].V1, ESet[NextEdge].V2 )==true ) {/* 將該邊插入MST */InsertEdge( MST, ESet+NextEdge );TotalWeight += ESet[NextEdge].Weight; /* 累計權重 */ECount++; /* 生成樹中邊數加1 */}}if ( ECount < Graph->Nv-1 )TotalWeight = -1; /* 設置錯誤標記,表示生成樹不存在 */return TotalWeight; }總結
以上是生活随笔為你收集整理的prim算法和kruskal算法(C语言)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dijkstra算法和floyd算法(C
- 下一篇: 吃参苓白术体重变化是减肥了吗其功效和作用