zoukankan      html  css  js  c++  java
  • 最小生成树的邻接矩阵实现

    求上面这个图的最小生成树

    参考文档 :http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html

    1.prim算法

      基本思想:假设G=(V,E)是连通的,TE是G上最小生成树中边的集合。算法从U={u0}(u0∈V)、TE={}开始。重复执行下列操作:

       在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE中,同时v0并入U,直到V=U为止。

       此时,TE中必有n-1条边,T=(V,TE)为G的最小生成树。

       Prim算法的核心:始终保持TE中的边集构成一棵生成树

    注意:prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。


    2、克鲁斯卡尔(Kruskal)算法(只与边相关)

    算法描述:克鲁斯卡尔算法需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系,可以证明其时间复杂度为O(eloge)。

    算法过程:

    1.将图各边按照权值进行排序

    2.将图遍历一次,找出权值最小的边,(条件:此次找出的边不能和已加入最小生成树集合的边构成环),若符合条件,则加入最小生成树的集合中。不符合条件则继续遍历图,寻找下一个最小权值的边。

    3.递归重复步骤1,直到找出n-1条边为止(设图有n个结点,则最小生成树的边数应为n-1条),算法结束。得到的就是此图的最小生成树。


    克鲁斯卡尔(Kruskal)算法因为只与边相关,则适合求稀疏图的最小生成树。而prime算法因为只与顶点有关,所以适合求稠密图的最小生成树。


    /*
     * 普里姆算法和克鲁斯卡尔算法求最小生成树
     * 采用邻接矩阵存储
     *
     */
    #include<stdio.h>
    
    #define MAX_VERTEX_NUM 20
    //图的定义
    typedef struct 
    {
    	int vertexNum;    //图的顶点个数
    	int edgeNum;      //图的边的数目
    	char vertex[MAX_VERTEX_NUM];  //图中顶点的内容
    	int arc[MAX_VERTEX_NUM][MAX_VERTEX_NUM];  //图中顶点间的连通性
    }Graph,*PGraph;
    
    //辅助数组元素
    typedef struct 
    {
    	int from;
    	int to;
    	int weight;
    	int flag;
    }ArrayNode; 
    
    //构造无向网
    void createdGraph(PGraph g)
    {
    	int i,j;
        g->vertexNum=6;
    	g->edgeNum=10;
        for(i=0;i<g->vertexNum;i++)
    		g->vertex[i]='A'+i;
    	for(i=0;i<g->vertexNum;i++)
    		for(j=0;j<g->vertexNum;j++)
                g->arc[i][j]=0;
    	g->arc[0][1]=6;
    	g->arc[0][2]=1;
    	g->arc[0][3]=5;
    	g->arc[1][0]=6;
    	g->arc[1][2]=5;
    	g->arc[1][4]=3;
    	g->arc[2][0]=1;
    	g->arc[2][1]=5;
    	g->arc[2][3]=5;
    	g->arc[2][4]=6;
    	g->arc[2][5]=4;
    	g->arc[3][0]=5;
    	g->arc[3][2]=5;
    	g->arc[3][5]=2;
    	g->arc[4][1]=3;
    	g->arc[4][2]=6;
    	g->arc[4][5]=6;
    	g->arc[5][2]=4;
    	g->arc[5][3]=2;
    	g->arc[5][4]=6;
    }
    
    //初始化最小生成树
    void initTree(PGraph tree)
    {
    	int i,j;
        tree->vertexNum=6;
    	tree->edgeNum=5;
    	for(i=0;i<tree->vertexNum;i++)
    		tree->vertex[i]='0';
    	for(i=0;i<tree->vertexNum;i++)
    		for(j=0;j<tree->vertexNum;j++)
                tree->arc[i][j]=0;
    }
    
    //普里姆算法求最小生成树
    void prim(PGraph g,PGraph tree)
    {
    	int i,j,k;
    	int index;  //指向权值最小的边
        ArrayNode  edgeArray[MAX_VERTEX_NUM*2]; //辅助数组 
    	int length=0; //数组长度
    	int n=1;  //统计数组已加入多少个顶点
    
    	//初始状态把第一个顶点加入树中
    	tree->vertex[0]='A';
    	printf("%-3c",tree->vertex[0]);
        i=0;
        while(1){
        	//寻找与顶点i相接且这条边的另一个顶点不在树中的边,存入edgeArray数组中
    		for(j=0;j<g->vertexNum;j++){
    			if(g->arc[i][j] > 0){
    				//判断这条边的另一个顶点在不在树中
    				for(k=0;k<tree->vertexNum;k++){
    					if(tree->vertex[k] == g->vertex[j])
    						break;
    				}
    				if(k == tree->vertexNum){
                        edgeArray[length].from=i;
    		            edgeArray[length].to=j;
    	    			edgeArray[length].weight=g->arc[i][j];
                        edgeArray[length].flag=0;
    		    		length++;
    				}
    			}
    		}
    		//从数组中选择权值最小的边
    		index=-1;
    		for(j=0;j<length;j++){
    			if(index == -1 && edgeArray[j].flag == 0)
    				index=j;
                if(edgeArray[j].flag==0 && edgeArray[j].weight < edgeArray[index].weight)
    				index=j;
    		}
    		//在树中加入一个顶点,且把这条权值最小的边加入树中
    		tree->vertex[edgeArray[index].to]='A'+edgeArray[index].to;
            edgeArray[index].flag=1;
    		tree->arc[edgeArray[index].from][edgeArray[index].to]=edgeArray[index].weight;
    		tree->arc[edgeArray[index].to][edgeArray[index].from]=edgeArray[index].weight;
    		//当这个顶点加入树中时,与这个顶点相邻的边不可加入树中
    		for(k=0;k<length;k++){
    			if(edgeArray[k].to == edgeArray[index].to)
    				edgeArray[k].flag=1;
    		}
    		i=edgeArray[index].to;
    		printf("%-3c",tree->vertex[i]);
    		n++;
    		//当有g->vertexNum个顶点时,最小生成树构造完成
    		if(n==g->vertexNum)
    			break;
    	}
    }
    
    //判断两个顶点是否连通(广度优先搜索)
    int connected(PGraph tree,int from,int to)
    {
    	int i,j,k;
    	int vertex[MAX_VERTEX_NUM];//看成队列
    	int front,rear;
    	if(from==to)
    		return 1;
    	front=rear=0;
    	//把第一个顶点存入数组
    	vertex[rear++]=from;
    	//遍历tree
    	while(front<=rear){
    		i=vertex[front];
            for(j=0;j<tree->vertexNum;j++)
    			if(tree->arc[i][j]>0){
    				if(j==to)
    					return 1;
    				//判断此顶点是否在队列中
    				for(k=0;k<rear;k++)
    					if(vertex[k] == j)
    						break;
    				if(k==rear)
         			    vertex[rear++]=j;
    			}
    		front++;
    	}
    	return 0;
    }
    
    //克鲁斯卡尔算法求最小生成树
    void kruskal(PGraph g,PGraph tree)
    {
        ArrayNode  edgeArray[MAX_VERTEX_NUM]; //辅助数组 
    	int length=0;
    	int i,j,k,index,n;
    
    	//顶点先加入树中
    	for(i=0;i<tree->vertexNum;i++)
    		tree->vertex[i]=i+'A';
    	//1.把所有的边有序(从小到大)的插入edgeArray数组中
    	for(i=0;i<g->vertexNum;i++)
    		for(j=0;j<g->vertexNum;j++){
    			if(i<j && g->arc[i][j]>0){
    				//寻找插入的位置index
    				for(k=0;k<length;k++){
                        if(edgeArray[k].weight > g->arc[i][j])
    						break;
    				}
    				index=k;
                    //移位
    				for(k=length;k>index;k--)
                        edgeArray[k]=edgeArray[k-1];
    				//插入
    				length++;
    				edgeArray[index].flag=0;
    				edgeArray[index].from=i;
    				edgeArray[index].to=j;
    				edgeArray[index].weight=g->arc[i][j];
    			}
    		}
    	//2.从小到大取出n-1条边构造最小生成树
    	n=0;
    	while(n < g->vertexNum-1){
    		//从小到大取一条符合要求的边
    		for(k=0;k<length;k++)
    			if(edgeArray[k].flag==0 && connected(tree,edgeArray[k].from,edgeArray[k].to)==0){
    				break;
    			}
    		//把这条边加入树中
    		tree->arc[edgeArray[k].from][edgeArray[k].to]=edgeArray[k].weight;
    		tree->arc[edgeArray[k].to][edgeArray[k].from]=edgeArray[k].weight;
            edgeArray[k].flag=1;
    		printf("%-3d",edgeArray[k].weight);
    		n++;
    	}
    }
    
    void main()
    {
    	Graph graph;
    	Graph tree;
    	createdGraph(&graph);
    	initTree(&tree);
    	printf("普里姆算法树中顶点加入的顺序:
    ");
    	prim(&graph,&tree);
    	printf("
    ");
    	initTree(&tree);
    	printf("克鲁斯卡尔算法树中边加入的顺序:
    ");
    	kruskal(&graph,&tree);
    	printf("
    ");
    }


  • 相关阅读:
    关于react框架的一些细节问题的思考
    shouldComponentUpdate不能直接比较object
    浅谈session,cookie,sessionStorage,localStorage的区别及应用场景
    dva相关文档
    vuex 源码:深入 vuex 之辅助函数 mapState
    第三课补充01——set类型 sorted类型命令操作详解,redis管道及事务
    第三课作业——set类型、sorted set类型的增删改查,redis的事务
    第二课补充01——redis-cli命令行详解、string类型、list类型、hash类型命令操作详解
    第二课作业——redis常用命令
    第五课——备份恢复
  • 原文地址:https://www.cnblogs.com/tham/p/6827369.html
Copyright © 2011-2022 走看看