集合操作问题

 本博客的代码的思想和图片参考:好大学慕课浙江大学陈越老师、何钦铭老师的《数据结构》

集合的操作

1 引子

集合运算: 交、并、补、差, 判定一个元素是否属于某一集合
p 并查集:集合并、 查某元素属于什么集合
p 并查集问题中集合存储如何实现?
Ø 可以用树结构表示集合,树的每个结点代表一个集合元素

 

例如,有三个整数集合
S1={1,2,4,7}
S2={3,5,8}
S3={6,9,10}

如何使用树来表示集合:

我们可以使用双亲表示法,使用孩子指向父亲:

 

 

 

 

当然我们也可以使用数组来进步表示:

 

2 集合的运算

2.1 表示集合的数据结构

 1 typedef int elementType;
 2 
 3  
 4 
 5 typedef struct node{
 6 
 7     elementType data;
 8 
 9     int parent;
10 
11 }coll,*pCollection;

 

 

2.2 查找

需求:给定一个元素,给定一个集合数组(多个集合可能在同一个数组中),查找该元素所属于的结合。要求返回集合的根元素的数组下标

int Find( SetType S[ ], ElementType X ) 

算法思想:

a.首先对数组进行变量,看是否能找元素X,找到,使用i来记录这个元素X的下标

若没有找到,直接返回-1

b.在根据s[i].parent查找i的父节点,在把父节点的下标给i,一直查询到父节点的的parent=-1为止,此时的父节点就是根元素,把集合根节点的数组下标进行返回

 

代码:

int find(coll s[],elementType element){

    int i;

    for(i=0;i<MAXSIZE&&s[i].data!=element;i++);

    if(i>=MAXSIZE){/*在数组中没有找到该元素*/

        return -1;

    }

    for(;s[i].parent>=0;i=s[i].parent);

    return i;

}

 

 

 

2.3 合并集合

需要:给定两个来自不同集合的元素,要求合并这两个集合

返回:返回合并以后的集合的根元素

void Union( SetType S[ ], ElementType X1, ElementType X2 ) 

算法思想:

a.首先使用find方法找到x1x2元素的根节点分别为root1root2

b.root2节点指向root1节点,即把root2.parent=indexOf(root1)

 

 

 

代码:

 1 void unionCollection(coll s[],elementType x1,elementType x2){
 2 
 3     int root1 = find(s,x1);
 4 
 5     int root2 = find(s,x2);
 6 
 7     if(roo1!=root2){
 8 
 9         s[root2].parent=root1;
10 
11     }
12 
13 }

 

 

2.4 思考

如果这样一直对集合进行合并,那么树的高度会一直增加,那么不利于树的查找,那么如何减少树的高度呢?

需求:我们让小的集合指向大的集合,那么我们如何判断集合的大小呢?

 

方法1:如果我们在集合的数据结构中添加一个size的属性,来表示集合的大小。这样是可以解决问题,但是我们发现,其实只有根节点需要size属性,其他元素是不需要size属性的,这样会造成空间的浪费。

 

方法2:我们使用-1表示集合的根元素,那么我们能否使用使用-x 表示集合的大小,这是一个好的方法。既避免了空间的浪费,也解决了上面的问题。我们只需要在union方法进行修改即可。

 

 

 

上述的代码在:collection.c可见。

 

转载于:https://www.cnblogs.com/yghjava/p/6751592.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值