Prim算法和Kruskal算法
生活随笔
收集整理的這篇文章主要介紹了
Prim算法和Kruskal算法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ?Prim算法和Kruskal算法都能從連通圖找出最小生成樹。區別在于Prim算法是以某個頂點出發挨個找,而Kruskal是先排序邊,每次選出最短距離的邊再找。
? ? ? 一、Prim(普里姆算法)算法:
? ? ? ? Prim算法實現的是找出一個有權重連通圖中的最小生成樹,即:具有最小權重且連接到所有結點的樹。(強調的是樹,樹是沒有回路的)。
? ? Prim算法是這樣來做的:?
? ? 首先以一個結點作為最小生成樹的初始結點,然后以迭代的方式找出與最小生成樹中各結點權重最小邊,并加入到最小生成樹中。加入之后如果產生回路則跳過這條邊,選擇下一個結點。當所有結點都加入到最小生成樹中之后,就找出了連通圖中的最小生成樹了。
?
? ? Prim算法最小生成樹查找過程:
?
?
C語言實現:
#include <stdio.h> #include <stdlib.h> #define maxint 1073741824 int main() {FILE *input=fopen("input.txt","r"),*out=fopen("output.txt","w");int n,m,i,j,x,y,w;fscanf(input,"%d %d",&n,&m);int map[n][n],E[m][3],tree[m],Mst[n][n];/*Mst表示最小生成樹的鄰接矩陣,map是原圖,E是邊集,其中E[0]和E[1]是邊的兩個頂點,E[2]是邊的權值,tree是用于判斷原圖的點是否在最小生成樹中*/memset(tree,0,sizeof(tree));for(i=0; i<n; i++){for(j=0; j<n; j++){ map[i][j]=maxint;Mst[i][j]=maxint;}E[i][0]=E[i][1]=maxint;}for(i=0; i<m; i++){fscanf(input,"%d %d %d",&x,&y,&w);if(w<map[x][y]){map[x][y]=w;map[y][x]=w;}}int min=maxint,next=0,now=0,k=0;tree[0]=1;for(i=0; i<n; i++){for(j=0; j<n; j++){if(map[now][j]!=maxint && tree[j]==0){E[k][0]=now;E[k][2]=map[now][j];E[k++][1]=j;}}for(j=0; j<k; j++){if(E[j][2]<min && tree[E[j][1]]==0){min=E[j][2];x=E[j][0];y=E[j][1];next=y;}}tree[next]=1;now=next;Mst[x][y]=map[x][y];Mst[y][x]=map[y][x];min=maxint;}for(i=0; i<n; i++){for(j=0; j<n; j++){if(Mst[i][j]==maxint) //判斷兩點是否連通fprintf(out,"00 "); //美化輸出,不必多加探究else{fprintf(out,"%d ",Mst[i][j]); //輸出生成樹的鄰接矩陣,要輸出樹的自己可以根據鄰接矩陣的數據進行加工}}fprintf(out,"\n");}fclose(input);fclose(out);return 0; } // 程序未考慮不是連通圖的情況,修改很簡單,判斷生成樹的節點數量是否等于原圖的節點數量//如果小于(不會有大于)則本圖不是連通圖//其實prim和迪杰斯特拉算法核心有相似之處
? ? 二、Kruskal(克魯斯卡爾)算法:
? ? Kruskal算法與Prim算法的不同之處在于,Kruskal在找最小生成樹結點之前,需要對所有權重邊做從小到大排序。將排序好的權重邊依次加入到最小生成樹中,如果加入時產生回路就跳過這條邊,加入下一條邊。當所有結點都加入到最小生成樹中之后,就找出了最小生成樹。
?
C語言實現:
/* Kruskal.cCopyright (c) 2002, 2006 by ctu_85All Rights Reserved.I am sorry to say that the situation of unconnected graph is not concerned */ #include "stdio.h" #define maxver 10 #define maxright 100 int G[maxver][maxver],record=0,touched[maxver][maxver]; int circle=0; int FindCircle(int,int,int,int); int main() {int path[maxver][2],used[maxver][maxver]; int i,j,k,t,min=maxright,exsit=0;int v1,v2,num,temp,status=0;restart:printf("Please enter the number of vertex(s) in the graph:\n");scanf("%d",&num);if(num>maxver||num<0){printf("Error!Please reinput!\n");goto restart;}for(j=0;j<num;j++)for(k=0;k<num;k++){if(j==k){G[j][k]=maxright;used[j][k]=1;touched[j][k]=0;}elseif(j<k){re:printf("Please input the right between vertex %d and vertex %d,if no edge exists please input -1:\n",j+1,k+1);scanf("%d",&temp);if(temp>=maxright||temp<-1){printf("Invalid input!\n");goto re;}if(temp==-1)temp=maxright;G[j][k]=G[k][j]=temp;used[j][k]=used[k][j]=0;touched[j][k]=touched[k][j]=0;}}for(j=0;j<num;j++){path[j][0]=0;path[j][1]=0;}for(j=0;j<num;j++){status=0;for(k=0;k<num;k++)if(G[j][k]<maxright){status=1;break;}if(status==0)break;}for(i=0;i<num-1&&status;i++){for(j=0;j<num;j++)for(k=0;k<num;k++)if(G[j][k]<min&&!used[j][k]){v1=j;v2=k;min=G[j][k];}if(!used[v1][v2]){used[v1][v2]=1;used[v2][v1]=1;touched[v1][v2]=1;touched[v2][v1]=1;path[0]=v1;path[1]=v2;for(t=0;t<record;t++)FindCircle(path[t][0],path[t][0],num,path[t][0]);if(circle){/*if a circle exsits,roll back*/circle=0;i--;exsit=0;touched[v1][v2]=0;touched[v2][v1]=0;min=maxright;}else{record++;min=maxright;}}}if(!status)printf("We cannot deal with it because the graph is not connected!\n");else{for(i=0;i<num-1;i++)printf("Path %d:vertex %d to vertex %d\n",i+1,path[0]+1,path[1]+1);}return 1; } int FindCircle(int start,int begin,int times,int pre) { /* to judge whether a circle is produced*/int i;for(i=0;i<times;i++)if(touched[begin]==1){if(i==start&&pre!=start){circle=1;return 1;break;}elseif(pre!=i)FindCircle(start,i,times,begin);elsecontinue;}return 1; }
?無疑,Kruskal算法在效率上要比Prim算法快,因為Kruskal只需要對權重邊做一次排序,而Prim算法則需要做多次排序。盡管Prim算法每次做的算法涉及的權重邊不一定會涵蓋連通圖中的所有邊,但是隨著所使用的排序算法的效率的提高,Kruskal算法和Prim算法之間的差異將會清晰的顯性出來。
? ?
轉載于:https://www.cnblogs.com/tham/p/6827367.html
總結
以上是生活随笔為你收集整理的Prim算法和Kruskal算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Freemarker自定义标签
- 下一篇: Android 关于ListView中按