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 0
void 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;
}
}