zoukankan      html  css  js  c++  java
  • Quick Find

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

       

       

       

       

       

       

       

       

    Quick Find

       

       

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

       

       

       

    对于一组数据,并查集主要支持两个操作:

       

    1union( p , q ),即 ,将 p 和 q 两个元素合并在一起,也就是所谓的连接

       

    2find( p ),即 ,查找 p 元素具体在哪个集合中

       

       

       

    有了这两个操作,使用并查集也可以轻易地回答这样一个问题:

       

    isConnected( p , q ),传入 p 和 q 两个元素,判断两个元素是否相连接

       

       

       

    并查集的基本数据表示

       

    对于如上需求,最简单的数据表示方式就是数组,其中:数组的索引

    用来表示元素

       

    如果有 0-9,共 10 个元素,这些元素之间连接关系的表示方法如下:

       

    「即 给每一个元素都赋上一个值」

       

    1

       

       

       

    0-4 对应的值都是 0,而 5-9 对应的值都是 1。表示 0-4 这 5 个

    元素之间是互相连接的,而 5-9 这 5 个元素之间是互相连接的

       

       

       

    2

       

       

       

    02468 对应的值都是 0,而 13579 对应的值都

    1。表示 5 个偶数和 5 个奇数是分别互相连接的

       

       

       

    不妨给这个数组起一个名字,叫做 id,即 所有连接在一起的元素,

    它们都具有相同的 id

       

       

       

       

       

    程序:Quick Find 的实现

       

    UnionFind.h:

       

    #ifndef UNIONFIND_H

    #define UNIONFIND_H

       

    #include <iostream>

    #include <cassert>

    using namespace std;

       

       

       

    //并查集:Quick Find

    namespace UF

    {

       

    class UnionFind

    {

       

    private:

    int *id;

    int count;

       

    public:

    UnionFind(int count)

    {

    this->count = count;

    id = new int[count];

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

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

    {

    id[i] = i;

    }

    }

       

       

    ~UnionFind()

    {

    delete []id;

    }

       

       

    //找到每一个元素所集合的id:直接访问id相应的值即可

    //称这种实现为 Quick Find,也就是Find操作非常快,

    //只需要使用O(1)的时间复杂度就够了

    int find(int p)

    {

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

    return id[p];

    }

       

       

    //回答两个元素是否相互连接的问题:id相同则相互连接

    bool isConnected(int p, int q)

    {

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

    }

       

       

    //Quick Find下的Union操作的时间复杂度 O(n)

    //(因为unionC++中是关键字,所以不能把函

    //数名起成union

    void unionElements(int p, int q)

    {

       

    int pID = find(p);

    int qID = find(q);

       

    if (pID == qID)

    {

    return;

    }

       

    //Union操作是将两个元素所在集合全部并在一起,而不是只将 p 元素

    //并到 q 元素所在集合,或只将 q 元素并到 p 元素所在集合

    //

    //这样,本来两个元素所在集合的所有元素,两两之间就互相连接了

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

    {

    //或者反向亦可

    if (id[i] == pID)

    {

    id[i] = qID;

    }

    }

       

    }

    };

    }

       

       

    #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;

    }

    }

       

       

    //由于单个Union操作的时间复杂度是O(n)级别的,所以执行nUnion操作,

    //时间复杂度就是O(n^2)级别的

    //

    //而在查看是否连接isConnected()的复杂度是O(1),执行n个操作,就是O(n)

    //

    //不过整体上,此次测试的复杂度是O(n^2)级别的

    //

    // Quick Find,它查找(Find)的速度非常快,可是在执行并(Union)这个

    //操作的时候,效率却不尽人意

       

    #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系统启动过程分析
    android的logcat 用法整理
    git 使用详解(10) 远程分支
    android的logcat 用法整理
    android Binder工作流程
    android Binder工作流程
    git log 小结
    linux patch 命令小结
    windows 中 \r\n 区别于 类unix中的\n 疑问 迎刃而解
    Mysql Error Code : 1436 Thread stack overrun
  • 原文地址:https://www.cnblogs.com/siwuxie095/p/7001732.html
Copyright © 2011-2022 走看看