(7)数据结构--并查集

目录

一. 逻辑结构—“集合”

二. 存储结构

三. 集合相关操作

3.1 查

Find操作的优化(压缩路径)

3.2 并

Union操作的优化(小树合并到大树)

3.3 总结


一. 逻辑结构—“集合”

在集合下,两个元素之间的关系只有两种,即从属于同一个子集或从属于不同子集。

如下图:A与B输入同一个子集,A与C属于不同子集

可以联想到在森林中,森林是m(m≥0)棵互不相交的树的集合

进而联想,同一子集中的各个元素,组织成一棵树来表示(不同集合放到树里)

二. 存储结构

双亲表示法最适合并查集

原因其中并查集的两个操作:

查,一路向上找到其唯一对应的根节点(有几个根节点,就有几棵树,就有几个集合)

并,其中一个树的根结点指向另一个树的根结点

双亲表示法实现就很方便

图中L 中指向数组下标4,也就是E

E中指向数组下标为 1,也就是B

B指向数组下标为0,也就是A

A指向数组下标-1,为根结点

初始化并查集,将各个元素初始化为各自独立的子集。

#define SIZE 13
int UFSets[SIZE];    //集合元素数组
 
//初始化并查集
void Initial(int s[]){
    for(int i=0;i<SIZE;i++)
        s[i]=-1;
}

三. 集合相关操作

3.1 查

Find ——“查”操作:确定一个指定元素所属集合

// Find 操作,找 x 所属集合(返回 x 所属根结点)
int Find(int s[], int x) {
    while (s[x] >= 0)
        x = s[x];    // 循环寻找 x 的根
    return x;    // 返回根节点的下标
} 

//查11号元素L,指向4 
// 4号元素指向1,
// 1号元素指向0
// 0号元素指向-1,退出while  return 0;

最坏时间复杂度:O(n) ,与树的高度有关

Find操作的优化(压缩路径)

之前使用的Find操作是从指定节点出发,根据s[ ],向上找到所属根节点,这样向上的路径称为“查找路径”,而Find的优化操作就是要压缩这条路径,即“压缩路径”。具体操作就是先找到根节点,再将查找路径上所有结点都挂到根结点下

节点L的查找路径:

压缩路径就是将图中E,B全部挂到A节点下。这样,从L节点向上找根节点的路径就被压缩了。

代码如下

//Find"查"操作优化,先找到根节点再进行"压缩路径"
int Find(int S[],int x){
    int root = x;
    while(S[root]>=0)    root=S[root];  //循环找到根
    while(x!=root){ //压缩路径
        int t=S[x];    //t指向x的父节点
        S[x]=root;   //x直接挂到根节点下 
        x=t;
    }
    return root;    //返回根节点编号
}

每次 Find 操作,先找根,再“压缩路径”,可使树的高度不超过O((n))。(n)是一个增长很缓慢的函数,对于常见的n值,通常(n)≤4,因此优化后并查集的Find、Union操作时间开销都很低。

具体地,Find最坏时间复杂度为,将n个独立元素通过多次Union合并为一个集合的最坏时间复杂度为(n个元素需要合并n-1次)。

3.2 并

Union ——“并”操作:将两个不想交的集合合并为一个

//Union"并"操作,将两个集合合并为一个
//Root1,Root2为两个集合的根结点,如上图C指向A
void Union(int s[],int Root1,int Root2){
    //要求Root1与Root2是不同的集合
    if(Rootl==Root2)    return;
    //将根Root2连接到另一根Root1下面
    S[Root2]=Root1;
}
//时间复杂度:O(1)

Union操作的优化(小树合并到大树)

为了使“查”的效率更高,合并树时可以让小树合并到大树中,这样就不会增加树的高度了。

可以用根节点的绝对值表示树的结点总数。如下图

//Union"并"操作,小树合并到大树
void Union(int S[],int Rootl,int Root2){
    if(Rootl == Root2)    return;
    if(S[Root2]>S[Root1]){     //Root2结点数更少 ,谁大谁结点少 
        S[Root1]+= S[Root2];    //累加结点总数
        S[Root2]=Rootl;    //小树合并到大树
    } else {
        S[Root2]+= S[Root1];    //累加结点总数
        S[Root1]=Root2;    //小树合并到大树
    }
}
//改进的Union操作时间复杂度依旧是O(1)

 用该方法优化“Union”操作后,构造的树高不超过\left \lfloor log_{2}n \right \rfloor+1,那么Find操作的最坏时间复杂度也能到O(log_{2}n),将n个独立元素通过多次Union合并为一个集合的最坏时间复杂度为O(n*log2^n)

3.3 总结

用数组、双亲表示法来描述元素之间的集合关系。根节点为 -1,非根节点指向父节点下标。
Find (int S[], x) ——找到x所属集合Union(int S[], int x, int y) —— 将x、y所属集合合并

最坏时间复杂度:Find 操作 = 最坏树高 = O(n)
将n个独立元素通过多次Union合并为一个集合——

Union优化后:

用根节点的负值表示一棵树的结点总数,每次 Union 操作让小树合并到大树根节点下面。

最坏时间复杂度:Find 操作=最坏树高= 

将n个独立元素通过多次Union合并为一个集合——

在进一步 Find优化:

“压缩路径”的策略,每次 Find 操作先找到 x 所属根节点,再将查找路径上的所有结点都直接挂在根节点下面。

最坏时间复杂度:Find 操作=最坏树高= 𝑂(α(𝑛))
将n个独立元素通过多次Union合并为一个集合——O(n α(𝑛))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值