不相交集合的数据结构

来源:互联网 发布:2016淘宝分销刷信誉 编辑:程序博客网 时间:2024/05/17 09:06

不相交集合的数据结构

本来想着来实现基于贪婪思想的Kruskal算法—–最小生成树的算法之一。
却发现当我们合并集合时里面还涉及到一个判断“环”的问题,继而有了本篇博文:不相交集合的数据结构。
关于不相交集合的数据结构,这里作一个简单的介绍,更多的可看这里

  • 第一:我们假设我们有n个不相交的集合{Si},i=1~n;其中每个集合中都有一个“代表元素”(这个“代表元素”你可以理解为我们班级中的“班长”,对外“班长”就代表了我们整个班级);
  • 第二:不相交的集合的数据结构,要支持UNION(x,y)操作:将包含x和y的两个动态集合(Si和Sj)合并成一个新的集合,即完成两个集合的合并,然后为这个新的集合选取一个“代表元素”,虽然UNION的很多实现都是直接选取Si或者是Sj的“代表元素”继续作为合并后集合的“代表元素”,但是你也可以选择集合中的其他元素作为代表元素。
  • 第三 、不相交的集合的数据结构,支持FIND-SET(x)操作:返回x所在集合的代表元素。

不相交集合数据结构有一些应用,例如:确定无向图的连通分量,以及图中是否有环。
下面我们用java来实现判断一个图中是否有环,判断是否有环的思想可以看这里

第一步:我们定义了一个边的类,如下

package org.wrh.algorithmdemo;//边的类public class Edge {    /*     * 边的始点     * */    private int src;    /*     * 边的终点     * */    private int dest;    public Edge(int src, int dest) {        super();        this.src = src;        this.dest = dest;    }    public int getSrc() {        return src;    }    public void setSrc(int src) {        this.src = src;    }    public int getDest() {        return dest;    }    public void setDest(int dest) {        this.dest = dest;    }}

第二步:我们定义的一个图的类,如下

package org.wrh.algorithmdemo;import java.util.List;//图的类public class Graph {    /*     * 图中的顶点的个数     * */    private int vertices_number;    /*     * 图中的边的个数     * */    private int edges_number;    /*     * 图中边对象的引用集合     * */    private List<Edge> edge;    //下面为构造函数和属性的get、set方法    public Graph(int vertices_number, int edges_number) {        super();        this.vertices_number = vertices_number;        this.edges_number = edges_number;    }    public int getVertices_number() {        return vertices_number;    }    public void setVertices_number(int vertices_number) {        this.vertices_number = vertices_number;    }    public int getEdges_number() {        return edges_number;    }    public void setEdges_number(int edges_number) {        this.edges_number = edges_number;    }    public List<Edge> getEdge() {        return edge;    }    public void setEdge(List<Edge> edge) {        this.edge = edge;    }}

第三步:主函数类,如下

package org.wrh.algorithmdemo;import java.util.ArrayList;import java.util.List;public class DisjuntSetCircle {    public static void main(String[] args) {        /*         * 给定边的数量和顶点的数量         * */        int vertices_num=4;        int edges_num=4;        /*         * new一个Graph对象,         * */        Graph graph=new Graph(vertices_num,edges_num);        /*         * 新建edges_num个Edge对象,构造一个List对象         * */        List<Edge> edge=new ArrayList<Edge>();        edge.add(new Edge(0,1));        edge.add(new Edge(1,2));        edge.add(new Edge(2,3));        edge.add(new Edge(3,0));        /*         * 将边加载到图中         * */        graph.setEdge(edge);//这样就构成了一个4个顶点4条边的图        /*         *定义parent数组来记录每个顶点属于那个集合的"代表元素";         * 例如:我们的学生管理系统一般会记录我们的"班长"是谁一样         *          * */        int parent []=new int[vertices_num];        /*         * 首先我们将这些集合的代表元素初始化为 -1,表示他们都是单个元素的集合         * */        for(int i=0;i<parent.length;i++){            parent[i]=-1;        }        /*         * 下面来判断这个图中是否有环         * */        if(isCycle(graph,parent)){            System.out.println("此图有环");        }        else{            System.out.println("此图没有环");        }    }    private static boolean isCycle(Graph graph,int[] parent) {    /*     *获取边的数量     */        int num=graph.getEdge().size();        int src_represent;//用来表示边的起始点的"代表元素"        int dest_represent;//用来表示边的终点的"代表元素"        for(int i=0;i<num;i++){            int src=graph.getEdge().get(i).getSrc();//得到边的起始点            int dest=graph.getEdge().get(i).getDest();//得到边的终点            src_represent=find(parent,src);//得到起点所属集合的代表元素            dest_represent=find(parent,dest);//同上            if(src_represent==dest_represent){//说明,边的两个顶点已经出现在了集合中,加上此边之后,构成"环"                return true;            }            else{//否则,合并                union(parent,src_represent,dest_represent);            }        }        return false;    }    /*     * 合并两个不相交的集合     * */    private static void union(int[] parent, int src, int dest) {        /*         * 由于两者是两个集合的不同的"代表元素",因此将其中的的“代表元素”改为另外一个即可完成合并         * */        parent[src]=dest;    }    /*     * 用来寻找顶点X所在集合的"代表元素"     * */    private static int find(int[] parent, int x) {        /*         * 首先判断顶点x的"代表元素是不是等于-1",若等于-1,则说明,其自身就是"代表元素";         * 若不等于-1,则说明此点在某个集合中并且不是代表元素,我们需找到他的代表元素的标号,即我们需要向上查找         * */        if(parent[x]==-1){            return x;        }        return find(parent,parent[x]);    }}

上面的代码中注释写的比较详细,这里就不在解释,相信大家都能够看懂

总结

  • 这篇博文是关于“环”的检测的思想还是挺简单的,主要是为我们后面最小生成树算法的java实现做准备的,关于最小生成树的java实现,我最近将会完成。

关于”环”的检测的C语言实现和不相交集合的数据结构的知识可看这里,在此,对geeksforgeeks表示感谢,在这里,我学习到了很多知识。

1 1
原创粉丝点击