数据结构(三)—— 树(10):集合及运算

数据结构系列内容的学习目录 → \rightarrow 浙大版数据结构学习系列内容汇总

10. 集合及运算

10.1 集合的表示

  集合运算: ,判定一个元素是否属于某一集合。
  并查集: 集合某元素属于什么集合。并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。
  并查集问题中集合存储如何实现?
    ⋄ \diamond 可以用树结构表示集合,树的每个结点代表一个集合元素。

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

在这里插入图片描述
  采用数组存储形式:

在这里插入图片描述
  负数表示根结点;非负数表示双亲结点的下标。

在这里插入图片描述
  数组中每个元素的类型描述为:

typedef struct {
    ElementType Data;
    int Parent;
} SetType;

10.2 集合运算

  (1)查找某个元素所在的集合(用根结点表示)

int Find(SetType S[], ElementType X)
{   //在数组S中查找值为X的元素所属的集合
    //Maxsize是全局变量,为数组S的最大长度
    int i;
    for (i=0 ; i < Maxsize && S[i].Data != X; i++);  //当S[i].Data = X时,循环结束,i为X的位置下标
    if(i >= Maxsize)  return -1;  //未找到X,返回-1 
    for (; S[i].Parent >= 0; i = S[i].Parent);  //如果i < Maxsize,寻找父结点,直到S[i].Parent < 0为止(根结点的Parent为-1)
    return i;  //找到X所属集合,返回树根结点在数组S中的下标
}

  (2)集合的并运算
      ⋄ \diamond 分别找到X1和X2两个元素所在集合树的根结点;
      ⋄ \diamond 如果它们不同根,则将其中一个根结点的父结点指针设置成另一个根结点的数组下标。

void Union(SetType S[ ], ElementType X1, ElementType X2)
{
    int Root1, Root2;
    Root1 = Find(S, X1);
    Root2 = ind(S, X2);
    if (Root1 != Root2)  //当x1和x2不属于同一子集时,才需要合并
       S[Root2].Parent = Root1;  
}

  为了改善合并以后的查找性能,可以采用小的集合合并到相对大的集合中。(修改Union函数)

void Union(SetType S, SetName Root1, SetName Root2)
{   //这里默认Root1和Root2是不同集合的根结点
    //保证小集合并入大集合
    if ( S[Root2] < S[Root1] ) {  //如果集合2比较大
        S[Root2] += S[Root1];     //集合1并入集合2
        S[Root1] = Root2;
    }
    else {                         //如果集合1比较大
        S[Root1] += S[Root2];     //集合2并入集合1
        S[Root2] = Root1;
    }
}

10.3 并查集的实现

  数组存储形式实现并查集的代码如下所示。

#include<iostream>
using namespace std;
#define MaxSize 1000
typedef int ElementType;
typedef struct {
	ElementType Data; // 存值
	int Parent;  // 指向父结点 
}SetType;

// 查找 
int Find(SetType S[], ElementType X) 
{
	int i;
	for (i = 0; i < MaxSize && S[i].Data != X; i++);  // 找到数组中该值对应的下标 
	if (MaxSize <= i) // 如果没有找到,返回 -1 
		return -1;
	for (; S[i].Parent >= 0; i = S[i].Parent); 	// 找到该结点的根结点 
	return i; // 返回根结点在数组S中的下标 
}

// 并 
void Union(SetType S[], ElementType X1, ElementType X2) 
{
	int root1 = Find(S, X1);  // 找到 X1 的根结点下标 
	int root2 = Find(S, X2);  // 找到 X2 的根结点下标 
	// 如果根结点的下标不同,说明不是一个集合
	if (root1 != root2) 
	{
		S[root1].Parent = root2;   // 把X1挂到X2的集合 
	}
}

int main() 
{
	SetType S[MaxSize];
	// 初始化数组,父结点全部指向-1 
	for (int i = 0; i < MaxSize; i++) 
	{
		S[i].Data = i + 1;
		S[i].Parent = -1;
	}
	cout << Find(S, 5) << endl;
	Union(S, 3, 5);
	cout << Find(S, 4) << endl;
	cout << Find(S, 3) << endl;
	Union(S, 1, 3);
	Union(S, 2, 4);
	Union(S, 8, 6);
	cout << Find(S, 6) << endl;
	cout << Find(S, 8) << endl;
	system("pause");
	return 0;
}

  代码运行结果如下图所示。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值