图之prim算法

最小生成树是数据结构中图的一种重要应用,它的要求是从一个带权无向完全图中选择n-1条边并使这个图仍然连通(也即得到了一棵生成树),

同时还要考虑使树的权最小。 prim算法就是一种最小生成树算法。


普里姆算法的基本思想:

从连通网N={V,E}中的某一顶点U0出发,选择与它关联的具有最小权值的边(U0,v),将其顶点加入到生成树的顶点集合U中。以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u,v),把它的顶点加入到集合U中。如此继续下去,直到网中的所有顶点都加入到生成树顶点集合U中为止。


下面举例说明下prim算法:








c语言实现如下:(使用邻接矩阵存储)

#include <stdio.h>
#include <malloc.h>
#define VERTEXNUM 6

void createGraph(int (*edge)[VERTEXNUM], int start, int end, int value);
void displayGraph(int (*edge)[VERTEXNUM]);
void prim(int (*edge)[VERTEXNUM], int (**tree)[VERTEXNUM], int startVertex, int* vertexStatusArr);

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;
                }
        }
	//存放顶点的遍历状态,0:未遍历,1:已遍历 
        int* vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM);
        for(i=0;i<VERTEXNUM;i++){
                vertexStatusArr[i] = 0;
        }

        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);
	//最小生成树
        int (*tree)[VERTEXNUM] = NULL;
        prim(edge, &tree, 0, vertexStatusArr);
        printf("after generate tree:\n");
        displayGraph(tree);

        free(edge);
        free(tree);
        return 0;
}
//创建图
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 prim(int (*edge)[VERTEXNUM], int (**tree)[VERTEXNUM], int startVertex, int* vertexStatusArr){
	//申请存储树的内存
        *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;
                }
        }
	//从顶点0开始,则顶点0就是已访问的
        vertexStatusArr[0] = 1;
        int least, start, end, vNum = 1;
	//如果还顶点还没有访问完
        while(vNum < VERTEXNUM){
                least = 9999;
                for(i=0;i<VERTEXNUM;i++){
			//选择已经访问过的点
                        if(vertexStatusArr[i] == 1){
                                for(j=0;j<VERTEXNUM;j++){
					//选择一个没有访问过的点
                                        if(vertexStatusArr[j] == 0){
						//选出一条value最小的边
                                                if(edge[i][j] != 0 && edge[i][j] < least){
                                                        least = edge[i][j];
                                                        start = i;
                                                        end = j;
                                                }
                                        }
                                }
                        }
                }
                vNum++;
		//将点设置为访问过
                vertexStatusArr[end] = 1;
		//将边加到树中
                createGraph(*tree,start,end,least);
        }
}



c语言实现如下:(使用邻接表存储)

#include <stdio.h>
#include <malloc.h>
#define VERTEXNUM 6
//存放顶点的邻接表元素
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 prim(st_edge** edge, st_edge*** tree, int startVertex, int* vertexStatusArr);

int main(void){
	//动态创建存放边的指针数组  
        st_edge** edge = (st_edge**)malloc(sizeof(st_edge*)*VERTEXNUM);
        int i;
        for(i=0;i<VERTEXNUM;i++){
                edge[i] = NULL;
        }
	//存放顶点的遍历状态,0:未遍历,1:已遍历  
        int* vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM);
        for(i=0;i<VERTEXNUM;i++){
                vertexStatusArr[i] = 0;
        }

        printf("after init:\n");
        displayGraph(edge);
	//创建图
	//从顶点0到顶点1的边,值为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);

        st_edge** tree = NULL;
	//从edge从中生成最小树tree,从顶点0开始
        prim(edge, &tree, 0, vertexStatusArr);
        printf("after generate tree:\n");
        displayGraph(tree);

        delGraph(edge);
        edge = NULL;

        delGraph(tree);
        tree = NULL;

        free(vertexStatusArr);
        vertexStatusArr = NULL;
        return 0;
}
//创建图
void createGraph(st_edge** edge, int start, int end, int value){
        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){
        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){
        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);
}
//prim算法
void prim(st_edge** edge, st_edge*** tree, int startVertex, int* vertexStatusArr){
	//为最小生成树申请内存
        *tree = (st_edge**)malloc(sizeof(st_edge*)*VERTEXNUM);
        int i,j;
        for(i=0;i<VERTEXNUM;i++){
                (*tree)[i] = NULL;
        }
	//从顶点0开始,则顶点0就是已访问的
        vertexStatusArr[0] = 1;
        st_edge* p;
        int least, start, end, vNum = 1;
	//如果还顶点还没有访问完
        while(vNum < VERTEXNUM){
                least = 9999;
                for(i=0;i<VERTEXNUM;i++){
			//选择已经访问过的点
                        if(vertexStatusArr[i] == 1){
                                for(j=0;j<VERTEXNUM;j++){
					//选择一个没有访问过的点
                                        if(vertexStatusArr[j] == 0){
                                                p = *(edge+i);
						//选出一条value最小的边
                                                while(p != NULL){
                                                        if(p->value < least && p->vertex == j){
                                                                least = p->value;
                                                                start = i;
                                                                end = j;
                                                        }
                                                        p = p->next;
                                                }
                                        }
                                }
                        }
                }
                vNum++;
		//将点设置为访问过
                vertexStatusArr[end] = 1;
		//将边加到树中
                createGraph(*tree,start,end,least);
        }
}

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值