kruskal演算法是一種最小產生樹演算法。基本思想如下:
設有一個有n個頂點的連通網N={V,E},最初先構造一個只有n個頂點,沒有邊的非連通圖T={V, E},圖中每個頂點自成一個連通分量。當在E中選到一條具有最小權值的邊時,若該邊的兩個頂點落在不同的連通分量上,則將此邊加入到T中;否則將此邊捨去,重新選擇一條權值最小的邊。如此重複下去,直到所有頂點在同一個連通分量上為止。
下面舉例說明kruskal演算法:
c語言實現如下:(使用鄰接矩陣儲存)
#include <stdio.h>#include <malloc.h>#define VERTEXNUM 6#define TRUE 1#define FALSE 0void createGraph(int (*edge)[VERTEXNUM], int start, int end, int value);void displayGraph(int (*edge)[VERTEXNUM]);void kruskal(int (*edge)[VERTEXNUM], int (**tree)[VERTEXNUM]);void selectEdge(int (*edge)[VERTEXNUM], int (*tree)[VERTEXNUM], int* start, int* end, int* value);int isInSeparate(int (*tree)[VERTEXNUM], int start, int end);void isInSeparateCore(int (*tree)[VERTEXNUM], int vertex, int end, int* vertexStatusArr, int* result);int isNotInTree(int (*tree)[VERTEXNUM], int start, int end);int isTree(int (*tree)[VERTEXNUM]);void isTreeCore(int (*tree)[VERTEXNUM], int vertex, int* vertexStatusArr, int* vertexNum);int main(void){//動態建立存放邊的二維數組 int (*edge)[VERTEXNUM] = (int (*)[VERTEXNUM])malloc(sizeof(int)*VERTEXNUM*VERTEXNUM); int i,j; for(i=0;i<VERTEXNUM;i++){ for(j=0;j<VERTEXNUM;j++){ edge[i][j] = 0; } }//列印圖 printf("after init:\n"); displayGraph(edge);//建立圖(從頂點0到1有一條權值為6的邊,從頂點1到0有一條權值為6的邊,依次類推) createGraph(edge,0,1,6); createGraph(edge,0,3,5); createGraph(edge,0,2,1); createGraph(edge,1,2,5); createGraph(edge,1,4,3); createGraph(edge,2,4,6); createGraph(edge,2,3,5); createGraph(edge,2,5,4); createGraph(edge,3,5,2); createGraph(edge,4,5,6);//列印圖 printf("after create:\n"); displayGraph(edge);//最小產生樹 int (*tree)[VERTEXNUM] = NULL; kruskal(edge, &tree); printf("after generate tree:\n"); displayGraph(tree);//釋放佔用的資源 free(edge); free(tree); return 0;}//建立圖,從start頂點到end頂點,權值為value;從end頂點到start頂點,權值為value;void createGraph(int (*edge)[VERTEXNUM], int start, int end, int value){ edge[start][end] = value; edge[end][start] = value;}//列印圖void displayGraph(int (*edge)[VERTEXNUM]){ int i,j; for(i=0;i<VERTEXNUM;i++){ for(j=0;j<VERTEXNUM;j++){ printf("%d ",edge[i][j]); } printf("\n"); }}//最小產生樹 void kruskal(int (*edge)[VERTEXNUM], int (**tree)[VERTEXNUM]){//申請最小產生樹佔用的資源 *tree = (int (*)[VERTEXNUM])malloc(sizeof(int)*VERTEXNUM*VERTEXNUM); int i,j; for(i=0;i<VERTEXNUM;i++){ for(j=0; j<VERTEXNUM; j++){ (*tree)[i][j] = 0; } } int start,end,value;//如果目前為止產生的還不是樹 while(!isTree(*tree)){ start = end = -1; value = 999;//選擇合適的邊 selectEdge(edge, *tree, &start, &end, &value); if(start != -1 && end != -1 && value != 999){//將邊儲存到tree中 createGraph(*tree, start, end, value); } }}//選擇合適的邊void selectEdge(int (*edge)[VERTEXNUM], int (*tree)[VERTEXNUM], int* start, int* end, int* value){ if(edge == NULL || tree == NULL || start == NULL || end == NULL || value == NULL){ printf("parameter error.\n"); return; } int i,j;//訪問所有的邊,只需要訪問一部分就可以了,另外一部分是相同的 for(i=0; i<VERTEXNUM-1; i++){ for(j=i+1; j<VERTEXNUM; j++){//如果權值最小,並且不在產生的tree中,並且在不同的連通分量中,則選擇該邊 if(edge[i][j] != 0 && edge[i][j] < *value && isNotInTree(tree, i, j) && isInSeparate(tree, i, j)){ *start = i; *end = j; *value = edge[i][j]; } } }}//判斷start和end頂點是否在不同的連通分量中 int isInSeparate(int (*tree)[VERTEXNUM], int start, int end){ if(tree == NULL){ printf("parameter error.\n"); return FALSE; } int i,j; int result = 0; int* vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM); for(i=0;i<VERTEXNUM;i++){ vertexStatusArr[i] = 0; } isInSeparateCore(tree, start, end, vertexStatusArr, &result); free(vertexStatusArr); if(result == 1){ return FALSE; }else{ return TRUE; }}void isInSeparateCore(int (*tree)[VERTEXNUM], int vertex, int end, int* vertexStatusArr, int* result){ if(*result == 1){ return; } int i; for(i=0; i<VERTEXNUM; i++){ if(tree[vertex][i] != 0 && vertexStatusArr[i] == 0){ vertexStatusArr[i] = 1; if(i == end){ *result = 1; return; } isInSeparateCore(tree, i, end, vertexStatusArr, result); } }}//判斷start和end是否已經在tree中 int isNotInTree(int (*tree)[VERTEXNUM], int start, int end){ if(tree == NULL){ printf("parameter error.\n"); return FALSE; } if(tree[start][end] == 0 && tree[end][start] == 0){ return TRUE; } return FALSE;}//判斷tree是否是樹(從一個頂點從發,是否能夠遍曆到所有的點) int isTree(int (*tree)[VERTEXNUM]){ if(tree == NULL){ printf("tree is not exist.\n"); return FALSE; } int i; int vertexNum = 0; int* vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM); for(i=0;i<VERTEXNUM;i++){ vertexStatusArr[i] = 0; } isTreeCore(tree, 0, vertexStatusArr, &vertexNum); free(vertexStatusArr); if(vertexNum != VERTEXNUM){ return FALSE; }else{ return TRUE; }}void isTreeCore(int (*tree)[VERTEXNUM], int vertex, int* vertexStatusArr, int* vertexNum){ int i; for(i=0; i<VERTEXNUM; i++){ if(tree[vertex][i] != 0 && vertexStatusArr[i] == 0){ vertexStatusArr[i] = 1; (*vertexNum)++; isTreeCore(tree, i, vertexStatusArr, vertexNum); } }}
c語言實現如下:(使用鄰接表格儲存體)
#include <stdio.h>#include <malloc.h>#define VERTEXNUM 6#define TRUE 1#define FALSE 0//存放頂點的鄰接表元素typedef struct edge{ int vertex; int value; struct edge* next;}st_edge;void createGraph(st_edge** edge, int start, int end, int value);void displayGraph(st_edge** edge);void delGraph(st_edge** edge);void kruskal(st_edge** edge, st_edge*** tree);void selectEdge(st_edge** edge, st_edge** tree, int* start, int* end, int* value);void saveEdge(st_edge** tree, int start, int end, int value);int isInSeparate(st_edge** tree, int start, int end);void isInSeparateCore(st_edge** tree, st_edge* node, int end, int* vertexStatusArr, int* result);int isNotInTree(st_edge** tree, int start, int end);int isTree(st_edge** tree);void isTreeCore(st_edge** tree, st_edge* node, int* vertexStatusArr, int* vertexNum);int main(void){//動態建立存放邊的指標數組 st_edge** edge = (st_edge**)malloc(sizeof(st_edge*)*VERTEXNUM); int i; for(i=0;i<VERTEXNUM;i++){ edge[i] = NULL; }//列印圖 printf("after init:\n"); displayGraph(edge);//建立圖 createGraph(edge,0,1,6); createGraph(edge,0,3,5); createGraph(edge,0,2,1); createGraph(edge,1,2,5); createGraph(edge,1,4,3); createGraph(edge,2,4,6); createGraph(edge,2,3,5); createGraph(edge,2,5,4); createGraph(edge,3,5,2); createGraph(edge,4,5,6);//列印圖 printf("after create:\n"); displayGraph(edge); st_edge** tree = NULL;//最小產生樹 kruskal(edge, &tree);//列印圖 printf("after generate tree:\n"); displayGraph(tree);//釋放佔用的資源 if(edge != NULL){ delGraph(edge); edge = NULL; } if(tree != NULL){ delGraph(tree); tree = NULL; } return 0;}//建立圖,從start頂點到end頂點,權值為value;從end頂點到start頂點,權值為value;void createGraph(st_edge** edge, int start, int end, int value){ if(edge == NULL){ printf("no space for graph.\n"); return; } st_edge* newedge1 = (st_edge*)malloc(sizeof(st_edge)); newedge1->vertex = end; newedge1->value = value; newedge1->next = NULL; st_edge** edge1 = edge + start; while(*edge1 != NULL){ edge1 = &((*edge1)->next); } *edge1 = newedge1; st_edge* newedge2 = (st_edge*)malloc(sizeof(st_edge)); newedge2->vertex = start; newedge2->value = value; newedge2->next = NULL; st_edge** edge2 = edge + end; while(*edge2 != NULL){ edge2 = &((*edge2)->next); } *edge2 = newedge2;}//列印圖void displayGraph(st_edge** edge){ if(edge == NULL){ printf("graph is not exist.\n"); return; } int i; st_edge* p; for(i=0;i<VERTEXNUM;i++){ printf("%d:",i); p = *(edge+i); while(p != NULL){ printf("%d(%d) ",p->vertex,p->value); p = p->next; } printf("\n"); }}//刪除圖void delGraph(st_edge** edge){ if(edge == NULL){ printf("graph is not exist.\n"); return; } int i; st_edge* p; st_edge* del; for(i=0;i<VERTEXNUM;i++){ p = *(edge+i); while(p != NULL){ del = p; p = p->next; free(del); } edge[i] = NULL; } free(edge);}//最小產生樹void kruskal(st_edge** edge, st_edge*** tree){//申請最小產生樹佔用的資源 *tree = (st_edge**)malloc(sizeof(st_edge*)*VERTEXNUM); int i; for(i=0;i<VERTEXNUM;i++){ (*tree)[i] = NULL; } int start,end,value;//如果目前為止產生的還不是樹 while(!isTree(*tree)){ start = end = -1; value = 999;//選擇合適的邊 selectEdge(edge, *tree, &start, &end, &value); if(start != -1 && end != -1 && value != 999){//將邊儲存到tree中 createGraph(*tree, start, end, value); } }}//選擇合適的邊void selectEdge(st_edge** edge, st_edge** tree, int* start, int* end, int* value){ if(edge == NULL || tree == NULL || start == NULL || end == NULL || value == NULL){ printf("parameter error.\n"); return; } int i; st_edge* p = NULL;//遍曆所有的邊 for(i=0; i<VERTEXNUM; i++){ p = edge[i]; while(p != NULL){//如果權值最小,並且不在產生的tree中,並且在不同的連通分量中,則選擇該邊 if(p->value < *value && isNotInTree(tree, i, p->vertex) && isInSeparate(tree, i, p->vertex)){ *start = i; *end = p->vertex; *value = p->value; } p = p->next; } }}//判斷start和end頂點是否在不同的連通分量中int isInSeparate(st_edge** tree, int start, int end){ if(tree == NULL){ printf("parameter error.\n"); return FALSE; } int i; st_edge* startNode = tree[start]; int result = 0; int* vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM); for(i=0;i<VERTEXNUM;i++){ vertexStatusArr[i] = 0; } isInSeparateCore(tree, startNode, end, vertexStatusArr, &result);free(vertexStatusArr); if(result == 1){ return FALSE; }else{ return TRUE; }}void isInSeparateCore(st_edge** tree, st_edge* node, int end, int* vertexStatusArr, int* result){ if(*result == 1){ return; } while(node != NULL){ if(vertexStatusArr[node->vertex] == 0){ vertexStatusArr[node->vertex] = 1; if(node->vertex == end){ *result = 1; return; } isInSeparateCore(tree, tree[node->vertex], end, vertexStatusArr, result); } node = node->next; }}//判斷start和end是否已經在tree中int isNotInTree(st_edge** tree, int start, int end){ if(tree == NULL){ printf("parameter error.\n"); return FALSE; } int i; st_edge* p; p = tree[start]; while(p != NULL){ if(p->vertex == end){ return FALSE; } p = p->next; } return TRUE;}//判斷tree是否是樹(從一個頂點從發,是否能夠遍曆到所有的點)int isTree(st_edge** tree){ if(tree == NULL){ printf("tree is not exist.\n"); return FALSE; } int i; int vertexNum = 0; st_edge* startNode = tree[0]; int* vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM); for(i=0;i<VERTEXNUM;i++){ vertexStatusArr[i] = 0; } isTreeCore(tree, startNode, vertexStatusArr, &vertexNum); free(vertexStatusArr); if(vertexNum != VERTEXNUM){ return FALSE; }else{ return TRUE; }}void isTreeCore(st_edge** tree, st_edge* node, int* vertexStatusArr, int* vertexNum){ if(tree == NULL || vertexStatusArr == NULL || vertexNum == NULL){ printf("parameter error!\n"); return; } while(node != NULL){ if(vertexStatusArr[node->vertex] == 0){ vertexStatusArr[node->vertex] = 1; (*vertexNum)++; isTreeCore(tree, tree[node->vertex], vertexStatusArr, vertexNum); } node = node->next; }}