算法和数据结构(9)集合归并---树的使用

算法题目

  1. 集合类

    1. 并集

      题目:有10台电脑,编号如下:{1,2,3,4,5,6,7,8,9,10},已知下列电脑间完成了连接,

      1和2,2和4,3和5,4和7,5和8,6和9,6和10 ;

      如1和2,2和4连接,则认为1和4也连接上了,

      求2和7之间,5和9之间是否连接?

      c-check检查,
      i–input 输入
      在这里插入图片描述在这里插入图片描述
      思想:

  2. 将这10台电脑看成10个集合,{1},{2},{3},{4}…{9},{10}

  3. 谁和谁连接了,则认为是谁和谁,进行并集;

  4. 查询x和y是否连接,则看x,y是否同个集合;

考虑:

  1. 集合如何表示;考虑树的思想,利于查找和并集
  2. 树采用如何数据类型?链表还是数组进行构建?考虑到需要查找,故用数组表示树利用查找,同时题目所述,给定了数组长度,不需要拓展数组长度。非常适合;
  3. 数组中,自定node对象,对象包含data(电脑编号),parent(父结点的index,-1表示该结点为根结点)
  4. 并运算,改变其数组中的node对象的值,即可完成题目要求;具体代码如下
public class ComputerConnect {
    private Node[] computers;

    public ComputerConnect(int[] pcs) {
        this.computers = new Node[pcs.length];
        for (int i = 0; i < pcs.length; i++) {
            computers[i]=new Node(pcs[i],-1);
        }
    }

    class Node{
        int data;
        int parent;

        public Node() {
        }

        public Node(int data, int parent) {
            this.data = data;
            this.parent = parent;
        }
    }

    public int find(int pcNum){
        int i;
        // 寻找该computers数组内的data是否有该pc,若有则i为其index;
        for (i = 0; i < computers.length && computers[i].data== pcNum; i++) ;
        //若满足没有在数组中找到该pc的编号,则返回-1;
        if (i>=computers.length) return -1;
        //找到其根结点;
        for (;computers[i].parent>=0;i=computers[i].parent);
        //返回其根结点的索引
        return i;
    }

    public void union(int pcNum1, int pcNum2){
        int root1 = find(pcNum1);
        int root2 = find(pcNum1);
        if (root1!=root2) computers[root2].parent = root1;
    }
}

优化

忘记改进点所述,回归上面代码本身 ;

执行

​ union(2,1)

​ union(3,1)

​ union(4,1)

​ union(5,1)后
在这里插入图片描述
树会越来越高,拖慢的查找的效率;

改进点:

不断的union可能导致树太高,导致查找过慢,故可以将小树并到大树上,迎来新的问题,如何区分大小树?

可以修改parent的值,如-1表示其有一个子结点,-6表示共有6个子结点;

随后修改union方法即可;

按秩归并

此方法称为按秩归并,根据高度或者规模大小,归并在一起,

同时此题,计算机编号都为数字类型,可以作为设计为索引,不需要Node的data域,或者设计解码算法,换算为索引类型可以简化find方法中

for (i = 0; i < computers.length && computers[i].data== pcNum; i++) ;

此段的循环量 ;

路径压缩

核心思想:修改find代码,当找一个结点,把该结点提升到第二层树的位置;图示:

    public int find(int pcNum){
        int i;
        for (i = 0; i < computers.length && computers[i].data== pcNum; i++) ;
        if (i>=computers.length) return -1;
        for (;computers[i].parent>=0;i=computers[i].parent);
      	computers[temp].perent = i;
        return i;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值