計算最小生成樹的一種方法就是使其連續的一步一步的長成。在每一步都要把一個結點當做根來往上加邊。在算法的任一時刻都可以看到一組已經添加到樹上的頂點,而其餘頂點尚未加到這棵樹上。就找尚未加到這個樹上的頂點到已經加到樹上的頂點的最小的權值。
以v1作爲起始點,這時v4與v1的權值最小,那麼就把v1和v4連上;
然後在其他沒有被連在樹上的頂點中找到了v2裏v1權值是2,v3離v4權值是2,這兩個最小,那麼就再把v2和v3加入到樹中;
接下來在剩下沒有加到樹中的有v5,v6,v7,可以看到v7離已經被到樹中的v4的權值是4,這是最小的,那就把v7連進去;
這時候剩v5和v6,v6離已經被到樹中的v7的權值是1,這是最小的,所以把這條連進去;
最後v5與個點中權值最小的是v5和v7爲6,連進去。
結果就是這樣。
上代碼:
#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 7
#define INFINITY 65535 //代表無窮大
typedef struct
{
char vex[MAXVEX];
int arc[MAXVEX][MAXVEX];
int vertex,edge; //頂點數量和邊的數量
}Graph;
//創建鄰接矩陣
void createGra(Graph *g)
{
int i,j;
printf("請輸入頂點數量和邊的數量:\n");
scanf("%d %d",&g->vertex,&g->edge);
printf("輸入頂點元素\n");
for(i=0;i<g->vertex;i++)
{
getchar();
scanf("%c",&g->vex[i]);
}
//建立矩陣
printf("如果有連線就輸入其權值,i與j相等的時候是0,否則是無窮大:\n");
for(i=0;i<g->vertex;i++)
{
for(j=0;j<g->vertex;j++)
{
scanf("%d",&g->arc[i][j]);
}
}
}
//輸出鄰接矩陣
void print(Graph g)
{
int i,j;
for(i=0;i<g.vertex;i++)
{
for(j=0;j<g.vertex;j++)
{
printf("%8d ",g.arc[i][j]);
}
printf("\n");
}
printf("\n");
}
//prim算法
void prim(Graph g)
{
int i,j,k,sum=0;
int min;
int adjvex[MAXVEX]; //保存相關頂點
int lowcost[MAXVEX]; //保存已經連接了的頂點的權值
//初始化,從下標是0的頂點開始
for(i=0;i<g.vertex;i++)
{
adjvex[i]=0;
lowcost[i]=g.arc[0][i]; //存第一個頂點的所有的權值
}
for(i=0;i<g.vertex;i++)
{
min = INFINITY;
j=1;
k=0;
while(j<g.vertex)
{
if(lowcost[j]!=0 && lowcost[j]<min)
{
min=lowcost[j]; //找到與頂點相連的最小的權值下標
k=j;
}
j++;
}
if(min!=INFINITY) //一開始沒有加這個if 但是結果發現多出來一個(0,0),權值多出65535,調試發現是最後一次循環又把min初始化然後輸出了
{
printf("(%d,%d) ",adjvex[k],k);
lowcost[k]=0; //表明k下標已經是遍歷過了的,接下來遍歷就不會找到k和i邊了
printf("權值爲:%d",min);
sum=sum+min;
}
for(j=1;j<g.vertex;j++)
{
if(lowcost[j]!=0 && g.arc[k][j]<lowcost[j])
{
lowcost[j]=g.arc[k][j]; //找到已經遍歷了的頂點和沒有遍歷的的頂點的權值較小的存到了lowcost中,
adjvex[j]=k; //作爲等會打印的上一個頂點
}
}
}
printf("\n最小權值和爲%d\n",sum);
}
int main()
{
Graph g;
createGra(&g);
print(g);
prim(g);
return 0;
}
學習《數據結構與算法分析》的筆記。