【并查集】并查集实现原理以及应用

实现原理

一种树型数据结构,用于处理不相交集合(Disjoint Sets)的合并以及查询;一开始让所有元素独立成树,也就是只有根节点的树;然后根据需要将关联的元素(树)进行合并;合并的方式仅仅是将一棵树最原始的节点的父亲索引指向另一棵树;

初始化
初始化father:各个节点独立成树,并且其father[i]=-1,
father[i]
0 1 2 3 4 5 6 7 8 9
-1 -1 -1 -1 -1-1-1-1 -1

每个集合里面存放的都是自己的父节点,一直找,直到一个节点的值为负数,表示该节点为这个集合的根节点。根节点的绝对值,表示该集合有多少个元素

FindIdx查找该节点的根

因为每个节点的值为这个节点的父节点,所以以节点的值为下标,一直向上查找,直到一个节点的值为负数,那么找到了根节点。即:该集合的代表。

合并Union
找到两个节点的根节点,将他们的值相加存放到根节点1,根节点2的值为节点1的下标。这样将两个集合合并成以根节点1的集合中。

代码实现

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;

// 0   1   2   3   4   5    6
// -1  -1  -1  -1  -1  -1   -1 
class UnionFindSet
{
public:
    UnionFindSet(size_t size)
    {
        s.resize(size, -1);
    }

    size_t FindIdx(int x)//找该位置的根节点的下标
    {
        int root = x;
        while (s[root] >= 0)
            root = s[root];
        return root;
    }
    void Union(int x1, int x2)//合并两个
    {
        int root1 = FindIdx(x1);
        int root2 = FindIdx(x2);
        if (root1 != root2)
        {
            s[root1] += s[root2];
            s[root2] = root1;
        }
    }

    bool IsSameSet(int x1, int x2)//判断两个集合是否相等
    {
        return FindIdx(x1) == FindIdx(x2);
    }

    size_t UnionSize()//求有几个集合 0 不是一个集合
    {
        size_t count = 0;
        for (size_t i = 0; i < s.size(); ++i)
        {
            if (s[i] < 0)
                count++;
        }
        return count - 1;
    }

    void PrintSet()
    {
        for (size_t i = 0; i < s.size(); ++i)
            cout << i << "  ";
        cout << endl;
        for (size_t i = 0; i < s.size(); ++i)
        {
            if (s[i] < 0)
                cout << s[i] << " ";
            else
                cout << s[i] << "  ";
        }
        cout << endl;
    }
private:
    vector<int> s;
};

void Test()
{
    UnionFindSet un(8);
    un.Union(1, 3); // -1 
    un.Union(3, 7);
    un.Union(2, 4);
    un.Union(4, 5);
    un.Union(5, 6);

    un.PrintSet();
    cout<< un.UnionSize()<<endl;
}

初始化
// 0 1 2 3 4 5 6 7 8
// -1 -1 -1 -1 -1 -1 -1 -1 -1

(1)un.Union(1, 3);
查找1的根节点为 本身,查找 3的根节点为本身,然后合并,

1的值 = -1 + -1 = -2。//改集合有两个元素。
3的值 = 1;//3的父节点为节点1
// 0 1 2 3 4 5 6 7 8
// -1 -2 -1 1 -1 -1 -1 -1 -1

(2)un.Union(3, 7);
3的根节点为1,而1是该集合的代表,
7集合的代表为本身;
合并,
1的值为 = -2 + -1 = -3;//该集合有三个元素
7的值为 = 1。//节点1

应用

优化——路径压缩

思想
每次查找的时候,如果路径较长,则修改信息,以便下次查找的时候速度更快。

实现
第一步,找到根结点。
第二步,修改查找路径上的所有节点,将它们都指向根结点

这里写图片描述

图的最小生成树克鲁斯卡尔算法

图的最小生成树

猜你喜欢

转载自blog.csdn.net/wenqiang1208/article/details/77241022
今日推荐