-----------------siwuxie095
Quick Union
这里介绍并查集的另外一种实现思路:Quick Union
这种实现思路通常是并查集的常规实现思路,而且它的时间效率非常高
具体表示:将每一个元素,都看做是一个节点
不过这个节点和树中的节点稍有不同,树中节点的指针是指向自己的孩子,
而并查集中节点的指针却是指向自己的父亲
所以在并查集中,就有可能存在这样的一种情况:元素 3 有一个指针指向
元素 2,即 2 是父节点,3 是子节点,这就代表了 2 和 3 互相连接
另外,对于元素 2 来说,如果它本身已经是根了的话,它的指针只要指向
自己就好了,如下:
在上面的基础上,如果有元素 1 想和 2 或 3 连接,就应该将 1 指向父亲
的指针指向 2 和 3 组成的这棵树的根节点,也就是 2,如下:
在上面的基础上,再加另外一个集合 5、6、7
如果想让元素 5 和元素 2 连接在一起,只需要让 5 相应的指针指向 2 即可
另外,如果不是想让元素 5 和元素 2 连接在一起,而是想让元素 7 和
元素 3 连接在一起,那么最终所形成的树,依然是上图所示的样子
这是因为 7 所在的树的根是 5,3 所在的树的根是 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; }
//看p、q二者是否对应同样的根,来判断它们是否连在一起 //(p、q的根节点如果相同,则相连) 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】