不相交集合的数据结构

不相交集合的数据结构

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

时间: 2024-10-25 14:16:51

不相交集合的数据结构的相关文章

算法导论 第二十一章:不相交集合的数据结构

不相交集合(Disjoint-set )数据结构保持一组不相交的动态集合S={S(1),S(2),...,S(k)}.每个集合通过一个代表(representative)来识别,即集合中的某个成员.设x表示一个对象,不相交集合支持操作: MAKE-SET(x):建立一个新的结合,其唯一成员(也即代表)就是x.因为各集合是不相交的,故要求x没有在其他集合中出现过. UNION(x,y):将包含x和y的动态集合合并成一个新的集合(即这两个集合的并集).假定在这个操作之前两个集合是不相交的,操作之后,

算法导论——用于不相交集合的数据结构

不相交集合的操作 一些应用涉及将n个不同元素分成一组不相交的集合,常进行两种操作:寻找包含制定元素的唯一集合以及合并两个集合.操作进行以下定于: MAKE-SET(x)建立一个新的集合,仅含有x UNION(x,y)将包含x和y的两个集合合并成一个新的集合,删除原本的集合 FIND-SET(x)返回一个指向包含唯一x的集合的指针 无向图的连通分量就是一个例子. 对于如图所示的4个连通分量,先对每一个单独的点建立一个单独的集合,然后依次根据每条边合并对应的集合,最后形成4个不相交的集合 1 CON

计算机算法学习(1) - 不相交集合数据结构

不相交集合 故名思意就是一种含有多个不相交集合的数据结构.典型的应用是确定无向图中连通子图的个数.其基本操作包括: Make-Set(x):建立一个新的集合,集合的成员是x: Union(x,y): 将包含x和y的集合合并为一个集合: Find-Set(x): 返回指向包含x的集合的指针: 下面是一个例子,(a)是一个无向图,(b)是使用不相交集合来找连通子图的个数.做法是初始为各个顶点为一个集合,然后遍历各个边,把边的端点的集合进行合并,当处理完所有的边,能连通的顶点就在一个集合里了,这样就生

[算法系列之二十八]并查集(不相交集合)

一 概述 并查集(Disjoint set或者Union-find set)是一种树型的数据结构,常用于处理一些不相交集合(Disjoint Sets)的合并及查询问题. 有一个联合-查找算法(union-find algorithm)定义了两个操作用于此数据结构: Find:确定元素属于哪一个子集.它可以被用来确定两个元素是否属于同一子集. Union:将两个子集合并成同一个集合. 因为它支持这两种操作,一个不相交集也常被称为联合-查找数据结构(union-find data structur

并查集:不相交集合

并查集是一种树型的数据结构,其保持着用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.支持三种操作: Make-Set : 用于建立单元素集合. Find-Set:确定元素属于哪一个子集.它可以被用来确定两个元素是否属于同一子集. Union:将两个子集合并成同一个集合. 1.并查集的数组表示 //x表示元素,s[x]表示x所属集合 int s[N]; Make-Set(x){ s[x] = x; } Find-Set(x){ return s[x]; } //将y在所属集合

不相交集合ADT

不相交集合数据结构保持一组不相交的动态集合S={S1,S2,...,SK},每个集合通过一个代表来识别,代表即集合中的某个成员. 如果x表示一个对象,不相交集合支持以下操作: MAKE-SET(x):建立一个新的集合,其唯一成员为x.因为各集合是不想交的,故x没有在其它集合中出现. UNION(x,y):将包含x和包含y的集合合并为一个新的集合. FIND-SET(x):返回包含x的集合. 1.不相交集合的数组表示 在一个数组中保存每个元素所在集合的名称.这样Find操作就是简单的O(1)查找.

集合结合数据结构来看看

一.先来唠一唠?     上一篇泛型适宜本意还想继续往下写写,来一下协变与逆变,奈何不知道怎么该往下写,等等我思考一下,在继续写~接下来聊聊数据结构这一话题,想到数据结构就想起了那一年我在工院上课就睡觉的时光,真实暴遣天物呀,不扯开始话题,数据结构可能在我们工作的时候用的不算太多,但是实际上不管java或者C#都将这些封装到我们常用的类里面,就比如说集合就是数据结构的真实写照~ 二.数组先来扯一扯?     数组不算是集合,但是还是想用来他的东西来说明数据结构的一些东西,不算是偏题哈~我们都知道

算法导论 第二十一章:不相交集合森林

在不相交集合中的另一种更快的实现中,用有根树来表示集合.树中的每个成员指向其父节点,每棵树的根包含了代表(representative),并且是他自己的父节点.不相交森林即由多棵这样的树组成,如下图所示: [注:(b)是(a)UNION(e,g)的结果] 采用上述表示方法直观上并不比采用链表表示算法更快,但是可以通过"按秩合并"和"路径压缩"来提升效率. 按秩合并(union by rank): 对于每个节点,用秩表示节点高度的一个上界.在按秩合并中,具有较小秩的跟

给jdk写注释系列之jdk1.6容器(13)-总结篇之Java集合与数据结构

是的,这篇blogs是一个总结篇,最开始的时候我提到过,对于java容器或集合的学习也可以看做是对数据结构的学习与应用.在前面我们分析了很多的java容器,也接触了好多种常用的数据结构,今天我们就来总结下这些内容. 下面我们以数据结构的维度来总结下,在Java集合的实现过程中,底层到底使用了哪些常用的数据结构中,他们分别又有什么特点.      1. 数组(Array) 结构说明:在程序设计中,为了处理方便, 把具有相同类型的若干变量按有序的形式组织起来.这些按序排列的同类数据元素的集合称为数组