树与等价问题的Java实现

这篇博客介绍如何使用Java实现树与等价类问题,通过双亲表示法存储集合,实现查找、合并等集合操作。具体包括构造单个元素集合、判定所属集合和合并集合,以及详细展示了如何根据等价关系划分等价类的算法和Java代码实现。
摘要由CSDN通过智能技术生成
核心: 1:  根据给定等价关系划分等价类. 
         2: 用树来实现集合和集合操作.
         3:为了便于实现集合操作, 树采用 " 双亲表示法存储 "; 


确定等价类的算法:(这里可以搜索详细的算法描述)
    1:构造单个元素集合;
    2:重复读入偶对,判定所属集合,进行合并;


划分等价类的三个集合 操作:
    1: 构造只含单个成员的集合.
    2:判定某个单元素所在集合.
    3:归并两个互不相交的集合为一个集合.

//树的表示. 一个集合就是一棵树;
1
2
3
4
5
6
7
8
//树的表示: 双亲表示法
class  ParentTree{
     Object data;  //数据
     
     ParentTree parent;  //该节点的父亲
}
 
    


以此为例来进行说明和程序演示:
    假设集合S= {x | 1<= x <=8  } R是 S上的一个等价关系:
    R = {(1,2),(3,4),(5,6),(7,8),(1,3),(5,7),(1,5)};

    如题: 如果函数div_equalClass() 调用 find_mfset() 和 merge_mfset() 确定等价类,结果生成的树如下:



Java代码实现如下:
import java.util.ArrayList;
 
//树与等价问题; MFset表示集合,它由n个子集合构成.
//以此为例来进行说明和程序演示:
   //假设集合S= {x | 1<= x <=8 } R是 S上的一个等价关系:
    //R = {(1,2),(3,4),(5,6),(7,8),(1,3),(5,7),(1,5)};
 
public class MFset {
    //n个子集合,一个集合就是一棵树
    private int n;
    private ParentTree[] mfSet;
     
    public MFset(Object[] Xi){
        this.n = Xi.length;
        mfSet = new ParentTree[n+1];
         
        initial(Xi);
    }
     
    //初始化操作,构造一个由n个子集Si...Sn(每个子集只含单个成员Xi)构成的集合S。
    private void initial(Object[] Xi){
        for(int i=0;i<Xi.length;i++){
            mfSet[i+1] = new ParentTree(Xi[i]);//构造一个只含单个成员Xi的集合
        }
    }
     
    //查找函数,确定x所属集合Si
    public ParentTree find_mfset(Object x){
        ParentTree si = null;
         
        //找到存储x的节点
        for(ParentTree ele : mfSet){
            if(ele!=null && ele.toString().equals(x.toString())){
                si = ele; break;
            }
        }
         
        if(si == null) return si;//x不存在
         
        while(si.parent != null){
            si = si.parent;
        }
         
        return si;
    }
     
    //查找函数 增强版,确定x所属集合Si,压缩路径:并将从i至根路径上的所有节点都变成根的孩子节点
    public ParentTree fix_mfset(Object x){
        ParentTree si = null;
         
        //找到存储x的节点
        for(ParentTree ele : mfSet){
            if(ele!=null && ele.toString().equals(x.toString())){
                si = ele; break;
            }
        }
        if(si == null) return si;//x不存在
         
        ArrayList<ParentTree> path = new ArrayList<>();//存储搜索路径 
        while(si.parent != null){
            path.add(si);
            si = si.parent;
        }
         
        for(ParentTree ele : path)//将从i至根路径上的所有节点都变成根的孩子节点
            ele.parent = si;
         
        return si;
    }
     
    //合并函数,将子集合Si和Sj中的一个并入另一个中,Si和Sj为子树根节点。
    public void merge_mfset(ParentTree Si,ParentTree Sj){
        if(Si == null || Sj==null)return;
        Sj.parent = Si;
    }
     
    //合并函数增强版, 并之前判断子集中所含成员的数目,然后令成员少的子树并入到含成员多的子树 
     // 因此需要修改存储结构,令根节点的parent域存储子集中所含成员数目的负值。初始为-1
    // 另一种方法: 增加一个存储数目的域count
     //
    public void mix_mfset(ParentTree Si,ParentTree Sj){
        //Si和Sj为子树根节点。
        if(Si == null || Sj==null)return;
         
        if(Si.count > Sj.count){
            Si.count += Sj.count;
            Sj.parent = Si;
        }
        else{
            Sj.count += Si.count;
            Si.parent = Sj;
        }
    }
     
    //根据等价关系划分等价类,即   2:重复读入偶对,判定所属集合,进行合并;
    public  void div_equalClass(NumPair[] numPairs){
        for(int i=0;i<numPairs.length;i++){
            ParentTree S1 = fix_mfset(numPairs[i].x);//增强版查找函数
            ParentTree S2 = fix_mfset(numPairs[i].y);
             
            /*ParentTree S1 = find_mfset(numPairs[i].x);//原版查找函数
            ParentTree S2 = find_mfset(numPairs[i].y);*/
             
            if(S1 != S2){
                merge_mfset(S1,S2);//合并普通版
                //mix_mfset(S1,S2);//合并增强版
            }
        }
    }
     
    public static void main(String[] args){
        //演示集合{1,2,3,4,5,6,7,8}
        Integer[] S = new Integer[8];
        for(int i=0;i<8;i++)
            S[i] = new Integer(i+1);
         
        MFset example = new MFset(S);//
        //等价关系 R = {(1,2),(3,4),(5,6),(7,8),(1,3),(5,7),(1,5)};
         
        //确定等价类
        NumPair[] numPairs = new NumPair[]{new NumPair(1, 2),new NumPair(3, 4),new NumPair(5, 6),new NumPair(7,8)
        ,new NumPair(1,3),new NumPair(5, 7),new NumPair(1, 5),new NumPair(8,9)};
         
        example.div_equalClass(numPairs);//确定等价类
         
    }
}  
 
//数对
class NumPair{
    Object x;
    Object y;
     
    public NumPair(Object x,Object y){
        this.x = x; this.y = y;
    }
}
 
//树的表示: 双亲表示法
class ParentTree{
    Object data ; //数据
    int count = -1;//该树的元素数目
     
    ParentTree parent = null; //该节点的父亲
     
    public ParentTree(){};
     
    public ParentTree(Object data){
        this.data = data;
    }
     
    public String toString(){
        return ""+data;
    }
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值