图之kruskal算法

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


  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值