數據結構課上講的最小生成樹思路還要代碼和我之前寫過的ACM版的是一樣的,這里都是兩種算法普里姆(Prim)算法和克魯茲卡爾(Kruskal)算法。
https://www.cnblogs.com/wkfvawl/p/9140591.html
普利姆算法
struct { int adjvex; ///保存鄰接頂點下標的數組 int lowcost;///記錄當前生成樹到剩余頂點的最小權值 } closedge[n]; int sum=0;///最小生成樹的權值 int Minimum(int closedge[], MGraph G)///求依附於生成樹上頂點中所有邊代價最下的邊 { int j,p=1, min=999;///最大權值65535? for(j=0; j<G.vexnum; j++) { if (closedge[j].lowcost!=0&&closedge[j].lowcost<min) { ///不在生成樹中的頂點而且權值最小 min=closedge[j].lowcost;///更新 p=j; } } sum=sum+min;///將該邊的權值加入到最小生成樹的總權值中 return p; /*返回最小代價的邊所依附的生成樹外的頂點p*/ }/* Minimum*/ void MiniSpanTree_PRIM(MGraph G, int n,char u) { /*用Prim算法從第u個頂點出發構造網G的最小生成樹T,並輸出T的各條邊, closedge [n] 記錄從頂點集U到V-U的代價最小的邊,n為圖中頂點數*/ int i,j,k; k=LocateVex(G,u); /*求頂點u在鄰接矩陣存儲的圖中的位置*/ for(j=0; j<G.vexnum; ++j) /* 輔助數組初始化*/ { if(j!=k) { closedge[j].adjvex=u; closedge[j].lowcost=G.arcs[k][j].adj; } } closedge[k].lowcost=0; /*初始,U={u}*/ printf("最小代價生成樹的各條邊為:\n"); for(i=1; i<G.vexnum; ++i) /*選擇其余G.vexnum-1個頂點*/ { k=Minimum(closedge,G); /*求出T的下個頂點,第k個頂點*/ printf("%c-%c)\n",closedge[k].adjvex,G.vexs[k]);///打印權值最小的邊 /* 輸出生成樹的邊及權值*/ closedge[k].lowcost=0; /*第k個頂點並入U集*/ for(j=0; j<G.vexnum; ++j) { if(closedge[j].lowcost!=0&&G.arcs[k][j].adj<closedge[j].lowcost)/// { ///如果新加入樹的頂點k使得權值變小 /* 新頂點並入U集后重新選擇最小邊*/ closedge[j].adjvex=G.vexs[k]);///修改這條邊鄰接的頂點,表示這條邊是從選出的頂點k指過來的 closedge[j].lowcost=G.arcs[k][j].adj;///更新更小的權值 } } } }
說明
1.這個代碼多一個adjvex數組,主要是為了打印最小生成樹的邊服務的,它用來保存鄰接頂點的下標。
2.lowcost數組記錄當前生成樹到其余頂點的最小權值。lowcost[i]=0表示i號頂點在生成樹中了,換句話說,這個lowcost數組既有了dist數組的功能,又有了vist數組的功能。
3.adjvex數組和lowcost數組是同步更新的。一旦有新的點加入到集合中,若找到權值最小的邊,同時更新adjvex數組和lowcost。
4.數組結構課更看重求解最小生成樹的過程,因而需要去打印組成邊,而ACM比賽更看重那個結果,也就最小生成樹的權值,這里我又加上了sum,代表最小生成樹的權值。
克魯斯卡爾算法
typedef struct { int a,b;///邊的兩個結點 int weight;///邊的權值 } Edge; ///邊結構體 int Find(int *parent,int x) { while(parent[x]!=0)///循環向上尋找下標為x頂點的根 { x=parent[x]; } return x;///循環結束時找到了根的下標 } int parent[MAXVEX];///定義生成樹的父節點(並查集) Edge edges[MAXVEX]; ///定義邊集數組 void MiniSpanTree_Kruskal(MGraph G) { int i,n,m; sort(edges);///按權值從小到大對邊排序 for (i= 0; i <G.vexnum; i++) { parent[i]=0;///初始化各個頂點單獨形成一個集合 } for (i=0;i<G.arcnum;i++) { n = Find(parent, edges[i].a);///n是這條邊第一個頂點的根節點所在的下標 m = Find(parent, edges[i].b);///n是這條邊第二個頂點的根節點所在的下標 if (n!=m) ///根節點下標不同,就說不在一棵樹上,不會形成環 { parent[n] = m;///合並 printf("(%d,%d) %d ", edges[i].a, edges[i].b, edges[i].weight); } } }
這個就和之前的寫法基本一致了,並查集加排序