码迷,mamicode.com
首页 > 其他好文 > 详细

不相交集合的数据结构

时间:2015-06-06 09:12:20      阅读:123      评论:0      收藏:0      [点我收藏+]

标签:环的检测的java实   环的检测java实现   

不相交集合的数据结构

本来想着来实现基于贪婪思想的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表示感谢,在这里,我学习到了很多知识。

不相交集合的数据结构

标签:环的检测的java实   环的检测java实现   

原文地址:http://blog.csdn.net/u010412719/article/details/46383641

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!