Prim法求最小生成樹
阿新 • • 發佈:2019-01-06
最小生成樹:對於一個帶權的無向連通圖,其每個生成樹所有邊上的權值之和可能不同,我們把所有邊上權值之和最小的生成樹稱為圖的最小生成樹。
普利姆法演算法:對於一個圖來說,要設立二個數組,一個數組用來記錄權值,陣列值來自開始頂點的權值,另一個數組
記錄每次加入的頂點,找到最小權值的頂點,加入到這個陣列。因為有新頂點的加入,所以可以更新權值陣列的值,
不斷加入頂點,不斷更新。就能找到最小生成樹。
圖例:
程式碼:
#include<stdio.h> #include<stdlib.h> #include <malloc.h> #include <string.h> #define MAX 20 #define INF 100 // 此處修改最大值 #define nLENGTH(a) (sizeof(a)/sizeof(a[0])) #define eLENGTH(a) ( sizeof(a) / sizeof(char) )/ ( sizeof(a[0]) / sizeof(char) ) typedef struct _graph { char vexs[MAX]; // 頂點集合 int vexnum; // 頂點數 int edgnum; // 邊數 int matrix[MAX][MAX]; // 鄰接矩陣 }Graph, *PGraph; // 邊的結構體 typedef struct _EdgeData { char start; // 邊的起點 char end; // 邊的終點 int weight; // 邊的權重 }EData; //指向節點的位置 int point_node(PGraph g,char c) { for(int i=0;i<g->vexnum;i++) { if(g->vexs[i]==c) { return i; } } return -1; } PGraph create_graph(int b[][3],char a[],int n,int e) { char c1,c2; //邊的2個頂點 PGraph g; //矩陣 g=(PGraph)malloc(sizeof(Graph)); //memset()第一個引數 是地址,第二個引數是開闢空間的初始值,第三個引數是開闢空間的大小 memset(g, 100, sizeof(Graph)); printf("頂點個數:\n");//頂點數 g->vexnum=n; printf("%d\n",g->vexnum); printf("邊個數:\n");//邊數 g->edgnum=e; printf("%d\n",g->edgnum); //初始化頂點 for(int j=0;j<g->vexnum;j++) { g->vexs[j]=a[j]; } for(int i=0;i<g->edgnum;i++) { int p1,p2; c1=char(b[i][0]); c2=char(b[i][1]); p1=point_node(g, c1); p2=point_node(g, c2); if (p1==-1 || p2==-1) { printf("input error: invalid edge!\n"); free(g); continue; } g->matrix[p1][p2]=b[i][2]; g->matrix[p2][p1]=b[i][2]; } return g; } //普利姆法求最小生成樹 void PrimTree(PGraph g,char a) //從start頂點開始求解 { int start=point_node(g,a);//得到頂點對應的號 int index=0; char prim[MAX]; //存放每次重新整理後得到的頂點 int weight[MAX]={0}; //存放每次重新整理頂點的權值 for(int i=0; i<g->vexnum;i++) { weight[i]=g->matrix[start][i]; //取得開始頂點的所有權值 } weight[start]=0; prim[index++]=a; for(i=0;i<g->vexnum;i++) { int k; //用來存放最小權值,可以找到它所對應的頂點 int min=INF; //找到最小權值的頂點,並新增入prim陣列 for(int j=0; j<g->vexnum;j++) { if(weight[j]!=0 && weight[j]<min) { min=weight[j]; k=j; } } printf("\n"); //找到k後,要把start,k 之間的權值設為0; weight[k]=0; prim[index++]=g->vexs[k]; //更新weight權值,把k頂點的權值加入到 for( j=0; j<g->vexnum;j++) { if(weight[j]!=0 && g->matrix[k][j]<weight[j]) { weight[j]=g->matrix[k][j]; //現在的 weight組 的值 即為頂點 start,k 的權值總和,下次 //尋找最小權值在這個組裡找 } } } //列印最小生成樹的順序 ; for(int m=0;m<g->vexnum;m++) { printf("%c\t",prim[m]); } } //測試 int main() { int i,j; PGraph gp; //測試用例 char a[]={'A', 'B', 'C', 'D', 'E', 'F', 'G'}; int b[][3]={ {'A', 'B',12}, {'A', 'F',16}, {'A', 'G',14}, {'B', 'F',7}, {'B', 'C',10}, {'C', 'F',6}, {'C', 'E',5}, {'C', 'D',3}, {'D', 'E',4}, {'E', 'F',2}, {'E', 'G',8}, {'F', 'G',9}}; //測試用例 int n=nLENGTH(a); int e=eLENGTH(b); gp=create_graph(b,a,n,e); //列印矩陣 for (i = 0; i < gp->vexnum; i++) { for (j = 0; j < gp->vexnum; j++) printf("%d ", gp->matrix[i][j]); printf("\n"); } //普利姆法求最小生成樹 PrimTree(gp,'A'); return 0; }