并查集及 编程练习

并查集概念:

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。能够实现较快的合并和判断元素所在集合的操作,

应用很多,如其判定一个无向图是否有环,求无向图的连通分量个数等。比如典型应用:实现Kruskar算法求最小生成树。

并查集的主要操作 :

下面举例说明并查集的常用的三种操作:

1、make_set() 把每一个元素初始化为一个集合

初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变)。

2、find_set(x) 查找一个元素所在的集合

查找一个元素所在的集合,其精髓是找到这个元素所在集合的祖先!这个才是并查集判断和合并的最终依据。

判断两个元素是否属于同一集合,只要看他们所在集合的祖先是否相同即可。

合并两个集合,也是使一个集合的祖先成为另一个集合的祖先.(祖先节点即下标与其值相等 即 father[i]=i)
3、merge_set(x,y) 合并x,y所在的两个集合
合并两个不相交集合操作很简单:
利用find_set找到其中两个集合的祖先,将一个集合的祖先指向另一个集合的祖先。

其中2中写并查集时涉及到的路径压缩,最好用递归,一方面代码的可读性非常好,另一方面,可以更直观的理解路径压缩时在回溯时完成的巧妙。

编程练习

下面以HDOJ上的题目为例编程实现。

hdoj  1232

http://acm.hdu.edu.cn/showproblem.php?pid=1232

畅通工程,实际上就是求这个图的连通分量的问题,如果有 n 个,那么最少还需要 n-1 根线将它们连接起来。求连通分量的话,

可以使用深度优先或是广度优先遍历的方法,遍历一遍,有多少个起点,就是有多少个连通分量;

也可以用并查集的思路,连通的节点放在在一起(即有同一个祖先节点),最后数一数有多少“集合”就 o好了。并查集 不用占很多

内存空间,理论上高效些。最后  连通量个数-1就是要修的最少的路了。

直接看代码吧:

#include 
#include 

#define N 1001

int father[N];//* father[x]表示x的父节点*/
int mark[N];//* mark[x]表示x是否在集合中*/

void make_set()//1初始化
{
    int i;
    for(i=1; i


HDOJ 1272

http://acm.hdu.edu.cn/showproblem.php?pid=1272

根据题意,只要判断下面两个条件即可。
1. 判断是否成环(回路);
2. 判断是否只有一棵树(只有一个连通图);

这个题目 利用并查集可以容易解决,要是利用图论的方法,那就麻烦很多了。


下面是实现代码:

#include
#include 
#define M 100001

int father[M];/* father[x]表示x的父节点*/
int vis[M]; // vis[x] 表示节点x是否在集合中
void make_set()//1初始化
{
    memset(vis, 0, sizeof(vis));
    int i;
    for(i=1; i1)//多个连通分支
                {
                    flag = 0;
                    break;
                }
            }
        }
        if(flag)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}




上面的int find_set(int x) 查找父节点采用的是一采用递归的方式压缩路径, 但是,递归压缩路径可能会造成溢出栈,或者对于求带环路的(如欧拉回路易出问题),下面我们说一下非递归方式进行的路径压缩:

int find_s(int x)
{
    int k, j, r;
    r = x;
    while(r != father[r])     //查找跟节点
        r = father[r];      //找到跟节点,用r记录下
    k = x;
    while(k != r)             //非递归路径压缩操作
    {
        j = father[k];         //用j暂存parent[k]的父节点
        father[k] = r;        //parent[x]指向跟节点
        k = j;                    //k移到父节点
    }
    return r;         //返回根节点的值
}

此外并查集的题目 经典的还有并查集,已有牛人分析,参见 ,代码参见2。

参考资料:

http://zh.wikipedia.org/zh-cn/%E5%B9%B6%E6%9F%A5%E9%9B%86

《算法导论》

你可能感兴趣的:(编程练习ACM,数据结构,算法)