zoukankan      html  css  js  c++  java
  • Quick Union

    -----------------siwuxie095

       

       

       

       

       

       

       

       

    Quick Union

       

       

    这里介绍并查集的另外一种实现思路:Quick Union

     

    这种实现思路通常是并查集的常规实现思路,而且它的时间效率非常高

       

       

       

    具体表示:将每一个元素,都看做是一个节点

       

    不过这个节点和树中的节点稍有不同,树中节点的指针是指向自己的孩子,

    而并查集中节点的指针却是指向自己的父亲

       

    所以在并查集中,就有可能存在这样的一种情况:元素 3 有一个指针指向

    元素 2,即 2 是父节点,3 是子节点,这就代表了 2 3 互相连接

       

    另外,对于元素 2 来说,如果它本身已经是根了的话,它的指针只要指向

    自己就好了,如下:

       

       

       

       

    在上面的基础上,如果有元素 1 想和 2 3 连接,就应该将 1 指向父亲

    的指针指向 2 3 组成的这棵树的根节点,也就是 2,如下:

       

       

       

       

    在上面的基础上,再加另外一个集合 567

       

       

       

       

    如果想让元素 5 和元素 2 连接在一起,只需要让 5 相应的指针指向 2 即可

       

       

       

       

    另外,如果不是想让元素 5 和元素 2 连接在一起,而是想让元素 7

    元素 3 连接在一起,那么最终所形成的树,依然是上图所示的样子

       

    这是因为 7 所在的树的根是 53 所在的树的根是 2,所以依然是将 5

    2 连接在一起,即让 5 的指针指向 2

       

       

       

       

       

    具体在数据表示上,虽然之前使用的一直是指针这个词,但由于每个

    元素只要单独存储一个变量,即 父亲具体是哪个元素即可

       

    所以在这里,依然使用数组来表示

       

       

       

    称这个数组为 parent,parent[i] 就表示元素 i 所指向的父亲元素

       

    初始化时,parent[i] = i,即 每个元素的父亲元素都指向自己

       

       

       

       

     

    程序:Quick Union 的实现

       

    UnionFind.h:

       

    #ifndef UNIONFIND_H

    #define UNIONFIND_H

       

    #include <cassert>

    using namespace std;

       

       

       

    //并查集:Quick Union

    namespace UF

    {

       

    class UnionFind

    {

       

    private:

    int *parent;

    int count;

       

    public:

    UnionFind(int count)

    {

    parent = new int[count];

    this->count = count;

    //在初始情况下,并查集里的元素,两两之间互不连接

    for (int i = 0; i < count; i++)

    {

    parent[i] = i;

    }

    }

       

       

    ~UnionFind()

    {

    delete []parent;

    }

       

       

    int find(int p)

    {

    assert(p >= 0 && p < count);

    //不断通过p来追溯它的父亲,直到p等于自己的父亲,

    // p 节点已经成为了根节点,直接 return 即可

    //(即 返回的是p所在集合的根节点)

    while (p != parent[p])

    {

    p = parent[p];

    }

       

    return p;

    }

       

    //pq二者是否对应同样的根,来判断它们是否连在一起

    //pq的根节点如果相同,则相连)

    bool isConnected(int p, int q)

    {

    return find(p) == find(q);

    }

       

       

    void unionElements(int p, int q)

    {

       

    int pRoot = find(p);

    int qRoot = find(q);

       

    if (pRoot == qRoot)

    {

    return;

    }

       

    //互换亦可

    parent[pRoot] = qRoot;

    }

    };

    }

       

       

    #endif

       

       

       

    UnionFindTestHelper.h:

       

    #ifndef UNIONFINDTESTHELPER_H

    #define UNIONFINDTESTHELPER_H

       

    #include "UnionFind.h"

    #include <iostream>

    #include <ctime>

    using namespace std;

       

       

       

    namespace UnionFindTestHelper

    {

       

    void testUF(int n)

    {

    //设置随机种子

    srand(time(NULL));

    UF::UnionFind uf = UF::UnionFind(n);

       

    time_t startTime = clock();

       

    //先进行n次的并,即 Union 操作

    for (int i = 0; i < n; i++)

    {

    int a = rand() % n;

    int b = rand() % n;

    uf.unionElements(a, b);

    }

       

    //再进行n次的查,即 Find 操作

    for (int i = 0; i < n; i++)

    {

    int a = rand() % n;

    int b = rand() % n;

    uf.isConnected(a, b);

    }

       

    time_t endTime = clock();

       

    //打印2*n个操作耗费的时间

    cout << "UF, " << 2 * n << " ops, " << double(endTime - startTime) / CLOCKS_PER_SEC

    << " s" << endl;

    }

    }

       

       

    #endif

       

       

       

    main.cpp:

       

    #include "UnionFindTestHelper.h"

    #include <iostream>

    using namespace std;

       

       

       

    int main()

    {

    //规模是十万

    int n = 100000;

       

    UnionFindTestHelper::testUF(n);

       

    system("pause");

    return 0;

    }

       

       

    运行一览:

       

       

       

       

       

       

       

       

       

       

    【made by siwuxie095】

  • 相关阅读:
    android studio解决微信登录,百度地图等调试问题
    Android studio初入的各种坑
    react native环境配置及各种坑
    单例模式序列化后反序列化单例失效的问题
    react native 初识react native
    Fragment 点击事件的穿透和重叠bug
    转载:android——eclipse如何去除Ctrl+shift+R组合键查找到的.class文件
    分布式队列Celery
    vue-生命周期
    vue-实现倒计时功能
  • 原文地址:https://www.cnblogs.com/siwuxie095/p/7001819.html
Copyright © 2011-2022 走看看