• 算法之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:
    ");
            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:
    ");
            displayGraph(edge);
    	//最小生成树
            int (*tree)[VERTEXNUM] = NULL;
            prim(edge, &tree, 0, vertexStatusArr);
            printf("after generate tree:
    ");
            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("
    ");
            }
    }
    
    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:
    ");
            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:
    ");
            displayGraph(edge);
    
            st_edge** tree = NULL;
    	//从edge从中生成最小树tree,从顶点0开始
            prim(edge, &tree, 0, vertexStatusArr);
            printf("after generate tree:
    ");
            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("
    ");
            }
    }
    //释放邻接表占用的内存
    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);
            }
    }
  • 相关阅读:
    small case change m and n
    关于闭包
    如何让IE兼容css3属性?
    全屏滚动插件
    bind()&call()&apply()的区别?
    nodejs和npm的关系
    数据库面试题整理
    微机原理复习整理
    软件工程复习整理
    leetcode字符串系列
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3172293.html
Copyright © 2020-2023  润新知