1. 程式人生 > >資料結構——Prim演算法

資料結構——Prim演算法

Prim演算法(加點法)

  • Prim為求圖最小生成樹的演算法
  • 本文章採用鄰接矩陣的儲存方式

具體思路如下

  • 1.首先以鄰接矩陣方式輸入圖
  • 2.進入演算法函式
  • 3.設定closedge陣列輔助
  • 4.先將一個start頂點加入生成樹頂點集合中
  • 5.用start頂點的邊關係將closedge陣列初始化
  • 6.找出當前closedge沒有進入生成樹的頂點中lowcost最小值記為min,對應的頂點記為m
  • 7.將m頂點加入到生成樹頂點集合中
  • 8.列印剛加入的頂點與權值最小邊的資訊
  • 9.用m頂點的資訊更新closedge陣列的資訊,如果發現更小的權值邊出現,則替換原有資訊
  • 10.重複6-9直到找出n-1條邊是結束

具體程式碼如下

/*prim演算法(加點法),適合稠密圖*/

#include<stdio.h>
#include<stdlib.h>

#define MAXVEX      20             /*最大頂點個數*/ 
#define INFINITY    32767          /*表示無窮,可自定義*/

#define Elem        int
#define FALSE       0
#define OK          1
#define TRUE        1

typedef char VertexType;

typedef struct{
	int arcs[MAXVEX][MAXVEX];            //鄰接矩陣,邊的資訊
	VertexType vexs[MAXVEX];        //頂點資訊 
	int vexnum;      //頂點數目 
	int arcnum;      //邊(弧)數目 
	
}AdjMatrix; 

typedef struct{    //陣列元素的下標對應圖G的頂點序號 
	int adjvex;   /*記錄該頂點和頂點集合中相連權值最小的頂點序號*/
	int lowcost;  /*記錄最小的權值*/ 
}Closedge;   

//根據名稱得到指定頂點在頂點集合中的下標
int getIndexOfVexs(char vex,AdjMatrix *MG)
{
	for(int i=1;i<=MG->vexnum;i++)
	{
		if(MG->vexs[i]==vex) return i;
	}
	return 0;
}

//用鄰接矩陣建立圖 
void Create(AdjMatrix *MG){
	int v1,v2;
	char c1,c2;

	printf("請輸入頂點數目: ");         //輸入頂點數 
	scanf("%d",&MG->vexnum);
	printf("請輸入邊的數目: ");         //輸入邊數 
	scanf("%d",&MG->arcnum);
	getchar();
	
    //輸入各頂點資訊 
	for(int i=1;i<=MG->vexnum;i++)
	{
		printf("請輸入第%d個頂點(char): ",i);    //請輸入各頂點資訊   
		scanf("%c",&MG->vexs[i]);
		getchar();
	}
	
	//初始化鄰接矩陣
	for(int i=1;i<=MG->vexnum;i++)
		for (int j=1;j<=MG->vexnum;j++)
			MG->arcs[i][j]=INFINITY;               /*如果是網則賦值INFINITY */ 
			
	//輸入邊的資訊,建立鄰接矩陣
	for(int k=1;k<=MG->arcnum;k++)
	{
		printf("請輸入第%d個邊連線的兩個頂點及權值v1(char) v2(char) weight(int): ",k);  //請輸入有關係的兩個頂點 
		int weight=INFINITY;
		scanf("%c %c %d",&c1,&c2,&weight);
		v1=getIndexOfVexs(c1,MG);
		v2=getIndexOfVexs(c2,MG);
		MG->arcs[v1][v2]=weight; 
		MG->arcs[v2][v1]=weight;   //無向圖為對稱矩陣
		getchar();
	}
}

//列印圖的資訊 
void Printf(AdjMatrix MG)
{
	printf("頂點數目為: %d\n",MG.vexnum);
	printf("邊的數目為: %d\n",MG.arcnum);
	printf("頂點: ");
	for(int i=1;i<=MG.vexnum;i++)
		printf("%c",MG.vexs[i]);
		
	printf("\n鄰接矩陣為: \n");
	for(int i=1;i<=MG.vexnum;i++)
	{
		for(int j=1;j<=MG.vexnum;j++){
			if(MG.arcs[i][j]==INFINITY) printf("#");
			else printf("%d",MG.arcs[i][j]);
		}
			
		printf("\n");
	}
}

/****************最小生成樹(Prim演算法)***************/ 
void Prim(AdjMatrix G,int start){
	Closedge closedge[MAXVEX];
	
	closedge[start].lowcost=0;  /*標誌頂點加入到生成樹集合中*/
	
	//初始化剩下的所有頂點對應的closedge陣列
	for(int i=1;i<=G.vexnum;i++){
		if(i!=start){
			closedge[i].adjvex=start;
			closedge[i].lowcost=G.arcs[start][i];
		}
	} 
	printf("\n最小生成樹的生成過程:"); 
	//從邊集中選出n-1條符合條件的邊 
	for(int e=1;e<=G.vexnum-1;e++){
		int m;             //記錄頂點 
		int min=INFINITY;  //記錄最小權值 
		//找出當前closedge沒有進入生成樹的頂點中lowcost最小值對應的頂點
		for(int k=1;k<=G.vexnum;k++){       
			if((closedge[k].lowcost!=0)&&closedge[k].lowcost<min){
				min=closedge[k].lowcost;
				m=k;
			}
		}
		
		printf("\n(%c,%c)  %d",G.vexs[closedge[m].adjvex],G.vexs[m],min);
		closedge[m].lowcost=0;     /*標誌頂點m進入生成樹集合*/
		
		//用新的生成樹頂點m,更新closedge陣列
		for(int i=1;i<=G.vexnum;i++){
			if((closedge[i].lowcost!=0)&&G.arcs[m][i]<closedge[i].lowcost){
				//如果發現有更小的權值邊出現,則替換原有資訊
				closedge[i].lowcost=G.arcs[m][i];
				closedge[i].adjvex=m; 
			}
		} 
	} 
} 


int main(){
	AdjMatrix MG,T;
	Create(&MG); 
	Prim(MG,1);
	return 0;
}