数据结构实验——并查集合并时高度高的树的根做为新的根+find用折叠规则来实现并查集实验

并查集合并时高度高的树的根做为新的根 实验

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 &copy);		     // 复制构造函数
	UFSets &operator =(const UFSets &copy);	// 赋值运算符
};

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文件夹中

创作不易~麻烦点个赞~~谢谢大家~~~ 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值