C++实现并查集
C++实现并查集
视频讲解参考王道考研
链接如下
【王道计算机考研 数据结构】 https://www.bilibili.com/video/BV1b7411N798/?p=55&share_source=copy_web&vd_source=734d9fe130776e8ae82b2b5371a5f5b8
一、并查集
集合功能只实现“并”,没有“交”和“补”
再实现“查”
我这里
两个数组,一个保存元素,一个是int保存前驱(上一个结点的数组下标)
用数组保存树,如果前驱为负数,认为是头结点,且前驱的绝对值代表本子集元素个数
如果两个元素的头结点相同,认为在一个集合中
这是王道考研讲的方法,“并”的实现比较容易,只需要头结点的前驱改变即可
二、代码如下
1.实现代码
代码如下(示例):
#pragma once
#include<iostream>
using namespace std;
//一个最多能处理的数量
#define MAX_ELEMENT_NUMBER 32
//我的并查集
template<typename elemtype>
class My_Disjoint_set
{
protected:
elemtype elements[MAX_ELEMENT_NUMBER];//保存的所有元素
int path[MAX_ELEMENT_NUMBER];//元素对应的前驱
int number = 0;//保存的元素个数
public:
void My_out();
/*功能:向并查集中插入一个元素
* 输入:要插入的元素
* 返回:
* 其它:
*/
void My_insert(elemtype e);
/*功能:查找位置x的元素所属集合(对应的根节点位置)
* 输入:
* x:要查找的元素的位置(数组下标)
* 返回:根节点数组下标
* 其它:
*/
int My_find(int x);
/*功能:查找位置x的元素所属集合(对应的根节点位置)
* 输入:
* x:要查找的元素的位置(数组下标)
* 返回:根节点数组下标
* 其它:会进行压缩路径
*/
int My_find_c(int x);
/*功能:合并两个元素对应的集合
* 输入:
* a:要合并的元素的位置(数组下标)
* b:要合并的元素的位置(数组下标)
* 返回:
* 其它:
*/
void My_union(int a, int b);
/*功能:查看两个元素是否属于一个集合(根节点是否相同)
* 输入:
* a:第一个元素的位置(数组下标)
* b:第二个元素的位置(数组下标)
* 返回:
* 其它:
*/
bool same_set(int a, int b);
};
template<typename elemtype>
void My_Disjoint_set<elemtype>::My_out()
{
for (int i = 0; i < this->number; i++)
cout << this->elements[i] << ' ' << this->path[i]<< endl;
cout << endl;
}
/*功能:向并查集中插入一个元素
* 输入:要插入的元素
* 返回:
* 其它:
*/
template<typename elemtype>
void My_Disjoint_set<elemtype>::My_insert(elemtype e)
{
if (MAX_ELEMENT_NUMBER >= number + 1)
{
this->elements[this->number] = e;
this->path[this->number] = -1;
this->number++;
}
}
/*功能:查找位置x的元素所属集合(对应的根节点位置)
* 输入:
* x:要查找的元素的位置(数组下标)
* 返回:根节点数组下标
* 其它:
*/
template<typename elemtype>
int My_Disjoint_set<elemtype>::My_find(int x)
{
//循环寻找x的根
while (path[x] >= 0)//根结点对应的path小于0
{
x = path[x];
}
return x;
}
/*功能:查找位置x的元素所属集合(对应的根节点位置)
* 输入:
* x:要查找的元素的位置(数组下标)
* 返回:根节点数组下标
* 其它:会压缩路径
*/
template<typename elemtype>
int My_Disjoint_set<elemtype>::My_find_c(int x)
{
int root = My_find(x);
while (x != root)
{
int t = path[x];
path[x] = root;
x = t;
}
return root;
}
/*功能:合并两个元素对应的集合
* 输入:
* a:要合并的元素的位置(数组下标)
* b:要合并的元素的位置(数组下标)
* 返回:
* 其它:
*/
template<typename elemtype>
void My_Disjoint_set<elemtype>::My_union(int a, int b)
{
int root_a = My_find(a);
int root_b = My_find(b);
//从属于不同集合(根节点不同)才合并
if (root_a != root_b)
{
//看看那个树结点少,把小树合并到大树
if (abs(path[root_a]) > abs(path[root_b]))
{
path[root_a] += path[root_b];//累加结点总数
path[root_b] = root_a;//合并
}
else
{
path[root_b] += path[root_a];//累加结点总数
path[root_a] = root_b;//合并
}
}
}
/*功能:查看两个元素是否属于一个集合(根节点是否相同)
* 输入:
* a:第一个元素的位置(数组下标)
* b:第二个元素的位置(数组下标)
* 返回:
* 其它:
*/
template<typename elemtype>
bool My_Disjoint_set<elemtype>::same_set(int a, int b)
{
int root_a = My_find(a);
int root_b = My_find(b);
if (root_a == root_b)
return true;
else
return false;
}
2.测试案例
代码如下(示例):
#include<iostream>
using namespace std;
#include "My_Disjoint_set.cpp"
#include <string>
void test_1()
{
My_Disjoint_set<int> dis_set1;
dis_set1.My_insert(0);
dis_set1.My_insert(1);
dis_set1.My_insert(2);
dis_set1.My_insert(3);
dis_set1.My_insert(4);
dis_set1.My_insert(5);
dis_set1.My_out();
dis_set1.My_union(1, 2);
dis_set1.My_union(1, 2);
dis_set1.My_union(2, 3);
dis_set1.My_out();
}
void test_2()
{
My_Disjoint_set<string> dis_2;
dis_2.My_insert("v0");
dis_2.My_insert("v1");
dis_2.My_insert("v2");
dis_2.My_insert("v3");
dis_2.My_insert("v4");
dis_2.My_insert("v5");
dis_2.My_insert("v6");
dis_2.My_insert("v7");
dis_2.My_insert("v8");
dis_2.My_insert("v9");
dis_2.My_union(0, 1);
dis_2.My_union(2, 3);
dis_2.My_union(4, 5);
dis_2.My_union(6, 7);
dis_2.My_union(8, 9);
dis_2.My_union(4, 7);
dis_2.My_union(4, 9);
dis_2.My_union(1, 2);
dis_2.My_union(3, 5);
dis_2.My_union(4, 6);
dis_2.My_out();
cout << dis_2.My_find_c(0) << endl;
dis_2.My_out();
}
int main(void)
{
/*test_1();*/
test_2();
return 0;
}