生成树与最小生成树

旧巷老猫 提交于 2020-10-29 03:35:08

生成树

      生成树是对图遍历访问的一条无回路的遍历路径称为图的生成树,生成树不是唯一的,深度优先和广度优先的访问路径就是一棵生成树.深度优先搜索与广度优先搜索的生成树分别称为***,

最小生成树

      最小生成树是对带有权值的图,生成树路径中权值总和最小的路径,称为最小生成树.求最小生成树的算法有 prim(普里姆)算法 和 kruskal(克鲁斯卡尔)算法:

 prim算法:
        假设图G=(V,E)是有n个顶点的连通图. T=(U,TE)是G的最小生成树,初值为空.首先从V中任选一个顶点放入U.(标记1:)然后从E中取一条边放入TE,这条边要满足:其中一个顶点在U中,一个在U之外(没在U中)。(这样的边不止一条)。这条边是权值最小的那条.然后把不在U的顶点放入U(这条边的另一端)。jump 标记1. 直到V中所有点都在U中, 这时TE中有n-1条边.最小生成树算法结束.算法时间复杂度是O(n2)

 

代码示例:

package stuct;


import java.util.LinkedList;
import java.util.List;

public class Graph2 {

    int m = Integer.MAX_VALUE;

    public static void main(String[] args) {
        Graph2 main = new Graph2();
        main.prim(main.matrix(),0);
        
        //打印结果
//        边 (0, 2)value=2
//        边 (2, 1)value=1
//        边 (2, 4)value=3
//        边 (4, 3)value=2
    }

    /**
     * 
     * @Title: matrix  
     * @Description: TODO 图的邻接矩阵表示
     * @param     设定文件  
     * @return void    返回类型  
     * @throws
     */
    public  Graph matrix() {

        //顶点集合
        int[] nodes = {0,1,2,3,4};

        //无向图的临接矩阵存储,对称矩阵,这个矩阵描述了图的边集合
        //边表, 不带权,i表示行标, j表示列标.第i行表示第i个定点(i对应nodes顶点的key值和下标),
        //第i个顶点指向的顶点key 作为j的下标, 赋值1,表示有连接
        //对于带权边的表示:用权值替换1,用MAX_VALUE替换0,主对角线置0, 表示指向自己, 不了,没啥用,还是置max算了
        int[][] table = {
                {m, 4, 2, m, m},//第0号定点指向了第1号顶点和第3号顶点
                {4, m, 1, 3, 4},
                {2, 1, m, 6, 3},
                {m, 3, 6, m, 2},
                {m, 4, 3, 2, m},
        };

        //图的包装类
        Graph g = new Graph(nodes,table);
        return g;
    }

    public void prim(Graph g,int begin) {
//        Graph g1 = (Graph) g.clone();
        int len = g.nodes.length;
        //顶点数组, 记录g的顶点,  初始顶点是 begin
        int [] v = new int[len];
        //指示v的下标
        int l = 0;
        //初始化
        for(int i = 0; i < v.length; i++) {
            v[i] = -1;
        }

        //边集合,记录v中顶点指向其他顶点的边
        List<side> e = new LinkedList<side>();

        v[l++] = begin;
        while(l<len) {
            //清除指向v中元素的边数据,  避免重复添加
            for(int i = 0; i < len; i++) {
                //删除第b[l-1]列
                g.table[i][v[l-1]] = m;
            }

            //把v[l-1]指向v以外的顶点的边加入边集合
            for(int i = 0; i < len; i++) {
                if(g.table[v[l-1]][i] != m) {
                    //有连接, 把边加入集合
                    e.add(new side(v[l-1],i,g.table[v[l-1]][i]));

                }
            }
            
            //找到最小边
            side s = getMinSide(e);
            //将此边的v之外的顶点加入v
            v[l++] = s.u;
            //在边集合中删除 s
            e.remove(s);
            
            //
            System.out.println(s);

        }
    }
    private side getMinSide(List<side> e) {

        side s = null;
        for(side sd : e) {
            if(s == null) {
                s = sd;
                continue;
            }
            if(sd.value < s.value) {
                s = sd;
            }

        }
        return s;
    }
}

    class side{
        public int v;
        public int u;
        public int value;//权值
        public side() {
        }
        public side(int v, int u, int value) {
            super();
            this.v = v;
            this.u = u;
            this.value = value;
        }
        @Override
        public String toString() {
            return "边 ("+ v + ", " + u + ")"+ "value=" + value;
        }
    }
    class Graph{
        public int[] nodes;//顶点的名称.比如第key号顶点,不可重复
        public int[][] table;//权值

        public Graph(int[] nodes, int[][] table) {

            this.nodes = nodes;
            this.table = table;
        }


    }

 kruskal算法

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!