并查集合并时高度高的树的根做为新的根 实验
1.1 实验内容
并查集合并时将高度较高的树的根节点作为新树的根节点生成新树,合并后可以减少新树的高度,提高find时的效率。
1.2文件结构说明
开发环境版本 | VisualStudio 2022 | 工程文件名 | c6-ufsets.sln |
头文件个数 | 3个 | 源程序文件个数 | 1个 |
文件名 | 文件类型 | 功能简介 | 备注 |
UFSets.h | 头文件 | 并查集类模板头文件,包括数据成员及成员函数的声明与定义 | |
elemnode.h | 头文件 | 并查集元素结点类模板头文件,包括数据成员及成员函数的声明与定义 | 数据域+双亲域 |
Assistance.h | 头文件 | 辅助软件包 | |
text.cpp | 源文件 | 测试文件 |
1.3 实现技术
1、在并查集UFSets中声明函数HeightUnion(ElemType a, ElemType b),以高度高的树的根作为新的根。
// 并查集
template <class ElemType>
class UFSets
{
protected:
// 并查集的数据成员:
ElemNode <ElemType> *sets; // 存储结点的双亲
int size; // 结点个数
int *rank; //存储树的层数
// 辅助函数
//int Find(ElemType e) const; // 查找元素e所在等价类的根
int CollapsingFind(ElemType e) const;// 查找元素e所在等价类的根
public:
// 并查集的函数成员:
UFSets(ElemType es[], int n); // 构造sz个单结点树(等价类)
virtual ~UFSets(); // 析构函数
ElemType GetElem(int p)const; // 取指定元素在数组中的下标
int GetOrder(ElemType e)const; // 根据指定下标取元素值
void Union(ElemType a, ElemType b); // 合并a与b所在的等价类
void HeightUnion(ElemType a, ElemType b);//高度高的树的根作为新的根
bool Differ(ElemType a, ElemType b); // 判断元素a、b是否在同一个等价类
UFSets(const UFSets ©); // 复制构造函数
UFSets &operator =(const UFSets ©); // 赋值运算符
};
2、在模板外定义了以高度高的树作为新的根的函数HeightUnion
调用CollapsingFind()函数查找a、b所在的等价类的根,如果根所在结点的序号不相等,如果rank[r2]大于rank[r1],就将r2设为r1的双亲域,否则将r1设为r2的双亲域。
template <class ElemType>
void UFSets<ElemType>::HeightUnion(ElemType a, ElemType b)
//操作结果:根据高度,高度高的树的根做为新的根
{
int r1 = CollapsingFind(a); // 查找a所在等价类的根
int r2 = CollapsingFind(b); // 查找b所在等价类的根
if (r1 != r2 && r1 != -1) {
int temp = sets[r1].parent + sets[r2].parent;
if (rank[r1] <= rank[r2])
{
sets[r1].parent = r2;
sets[r2].parent = temp;
}
else
{
sets[r2].parent = r1;
sets[r1].parent = temp;
}
}
}
3、测试代码
int main(void)
{
try // 用try封装可能出现异常的代码
{
const int n = 10;
char c[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
int a[] = { 'a', 'g', 'i', 'c', 'a', 'h', 'f', 'f' };
int b[] = { 'b', 'd', 'j', 'b', 'c', 'i', 'e', 'd' };
UFSets<char> e(c, n);
int i;
for (i = 0; i < 8; i++)
e.Union(a[i], b[i]); // 合并等价类
bool out[n]; // 已输出的结点值为true,否则值为false
for (i = 0; i < n; i++)
out[i] = false;
int p = 0; // 当前结点
while (p < n) { // 对没有输出的当前结点,输出其等价类
cout << "{" << e.GetElem(p);
out[p] = true;
for (i = p + 1; i < n; i++) { // 输出等价类
if (!e.Differ(e.GetElem(p), e.GetElem(i))) { // p与i在同一个等价类中
cout << "," << e.GetElem(i);
out[i] = true;
}
}
cout << "}" << endl;
while (p < n && out[p]) p++;
}
}
catch (Error err) // 捕捉并处理异常
{
err.Show(); // 显示异常信息
}
system("PAUSE"); // 调用库函数system()
return 0; // 返回值0, 返回操作系统
}
1.4 测试情况
测试数据:
char c[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
int a[] = { 'a', 'g', 'i', 'c', 'a', 'h', 'f', 'f' };
int b[] = { 'b', 'd', 'j', 'b', 'c', 'i', 'e', 'd' };
测试结果:
find用折叠规则来实现并查集 实验
1.1 实验内容
使用折叠规则完成一次查找,所需时间比Find( )函数有所增加,但它能改进树的性能,减少以后查找操作所需的时间。
1.2文件结构说明
开发环境版本 | Visual Studio 2022 | 工程文件名 | c6-ufsets.sln |
头文件个数 | 3个 | 源程序文件个数 | 1个 |
文件名 | 文件类型 | 功能简介 | 备注 |
UFSets.h | 头文件 | 并查集类模板头文件,包括数据成员及成员函数的声明与定义 | |
elemnode.h | 头文件 | 并查集元素结点类模板头文件,包括数据成员及成员函数的声明与定义 | 数据域+双亲域 |
Assistance.h | 头文件 | 辅助软件包 | |
text.cpp | 源文件 | 测试文件 |
1.3 实现技术
1、在并查集UFSets中声明函数CollapsingFind(ElemType e) const并在类外定义函数:
设j是以i为根的树中的一个结点,则对于从j到根i的路径上的每一个结点p,如果p的双亲(sets[p].parent)不等于i,则把i设置为p的双亲(sets[p].parent = i)。
template <class ElemType>
int UFSets<ElemType>::CollapsingFind(ElemType e) const
// 操作结果:带压缩路径功能,查找元素e所在树的根
{
int i, k, p = 0;
while (p < size && sets[p].data != e)
p++;
if (p == size)
return -1; // 集合中不存在元素e
for(i = p ; sets[i].parent >= 0; i= sets[i].parent) ; //查找p的根结点的序号i
while (sets[p].parent!=i && i!= p ) {//从p开始向上逐层压缩
k = sets[p].parent ;
sets[p].parent = i;
p = k;
}
return i;
}
完整代码可看资源区,在实验一的c6-ufsets文件夹中
创作不易~麻烦点个赞~~谢谢大家~~~