数据结构实验四在线等价类排序输出

  1. 使用模拟指针实现本实验。
  2. 输入一个1-9的正整数n,代表要创建n个元素,例如输入5,则代表创建一个1,2,3,4,5组成的元素表。
  3. 再输入一个大于0正整数r,代表后面要输入r个等价关系。
  4. 分行输入r个等价关系,格式如(1,2)。
  5. 分行输出所有等价类,一个等价类的元素由小到大依次输出。例如等价类(1,3,5,2,4),输出时排序输出(1,2,3,4,5)。
  6. 如果输出不是由小到大顺序输出,解决办法很多,可以创建一个n*n的数组,一行存放一个等价类,将所有等价类放入数组,对数组每一行元素进行排序,输出数组所有元素。
#include <iostream>
using namespace std;
//模拟指针的定义
//模拟指针可以理解为:在一个模拟空间中,
//存在一个指针数组,数组中的每个元素为指针类型,
//并且每个指针具有数据域和链接域(指向下一个数组中的指针)。


struct equivNode
{
	int equivClass;//元素类标识符,不是类,只是一个标识符
	int size;      //类的元素个数
	int next;      //类中指向下一个元素的指针

};
class BingCha {
	//构造函数
public:
	BingCha(int numberOfElements)
	{
		n = numberOfElements;
		node = new equivNode[n + 1];//豪气,第0个不用

		for (int e = 0; e <= n; e++)//初始化
		{
			node[e].equivClass = e;//现在是自己和自己混
			node[e].next = 0;//因为第0类不用(原来不是豪气呀)链表中没有下一个节点就可以用0表示
			node[e].size = 1;//因为现在一个类的元素个数是1

		}

	}
	void unite(int class1, int class2)
	{
		int n1 = node[class1].equivClass;
		int n2 = node[class2].equivClass;
		//cout << n1 << " " << n2;

		if (n1 == n2)
		{
			return;
		}

		if (n1 > n2)//交换n1和n2的值,让n2成为较大的那个标识符
		{
			int temp = n2;
			n2 = n1;
			n1 = temp;

		}
		//改变class2的equivClass值
		int k;
		for (k = n2; node[k].next != 0; k = node[k].next)
		{
			node[k].equivClass = n1;
		}
		node[k].equivClass = n1;//漏网之鱼

		node[n1].size += node[n2].size;

		//下面为表中元素排序的过程
		int temp;
		if (!node[n1].next)//如果n1后面没有接值
		{
			node[n1].next = n2;
			return;
		}
		while (node[n1].next && n2)//如果n1后面有值,无论是否是n2,移动直到n1后面没有值
		{
			if (node[n1].next < n2)
			{
				n1 = node[n1].next;
			}
			else {
				temp = node[n2].next;//表示原来第二个表后面还有没有剩余元素
				node[n2].next = node[n1].next;
				node[n1].next = n2;
				n2 = temp;//此时n2存放的是原来n2的下一个值
				n1 = node[n1].next;//此时n1存放的是原来n2的值
			}
		}

		if (n2)
		{
			node[n1].next = n2;
		}


	}

	//相比于上面的硬核这个显得舒服多了
	int find(int theElement)
	{
		//查找包含元素theElement的类
		return node[theElement].equivClass;
	}
	void print()
	{
		for (int i = 1; i <= n; i++)
		{

			if (node[i].equivClass == i)
			{
				int index = i;


				cout << "(" << i;
				while (node[index].next)
				{
					cout << "," << node[index].next;
					index = node[index].next;
				}
				cout << ")" << endl;
			}
		}
	}
	void printAgain(int m) {
		if (m > n) {
			cout << 0 << endl;
		}
		else {
			int f = find(m);
			cout << "(" << f;
			while (node[f].next) {
				cout << "," << node[f].next;
				f = node[f].next;
			}
			cout << ")" << endl;
		}
	}
private:
	//节点的数组,一个类的在一个“链表”里,不同的类在不同的“数组”元素中,应该是这样吧
	equivNode* node;
	int n;//元素的个数
};

int main()
{

	cout << "Input" << endl;
	int n;
	cin >> n;
	BingCha bing(n);//初始化
	int m;
	cin >> m;
	string s;
	int a, b;
	for (int i = 0; i < m; i++)
	{
		cin >> s;
		a = s[1] - '0';
		b = s[3] - '0';

		bing.unite(a, b);
	}

	int q;
	cin >> q;
	cout << "Output" << endl;
	bing.printAgain(q);
	cout << "End" << endl;

	return 0;
}

这是一段在csdn上cv的代码,关于我在抄袭的过程中学到了什么:

简单捋一下思路:创造n个的链表,其中包含三个元素,等价类的标识符,链表长度,指针next,首先将n个元素分别放置在相应的等价类中,接下来读入输入的数对,进行等价类的合并。假如输入的数字是(x,y),首先要确定标识符的顺序,假定n1与n2是代表两个等价类的标识符,则用n1来表示较小的那一个,接下来的工作是将第二个等价类中的元素依次插入第一个等价类中,该过程中使用一个指针,假设为k,指向n2中第一个元素,n1中也将数组指针指向不大于n2中所指元素的数字,然后进行插入操作,插入过程中第二个链表会出现断连,此时需要用temp存储一下n2中元素的下一位,插入一个元素后,将指针k和数组指针均往后移动一位,移动插入过程中,若第一个链表的next为空,则将n1中第一个元素指向n2中此时所指的元素,若第二个链表的next为空,则使n2的元素的next指向n1中所指元素的next,即可实现等价类的排序合并。

while中条件的意思是如果n1后面还有元素,且n2中还有元素没有插入,则仍需要进行插入排序,

if中条件的意思是如果n1中没有元素了,但是n2中还有元素,则直接将n2中元素接在n1后面即可。

设置标识符的意义就在于给出一个元素,就可以直接知道这个元素的等价类,且等价类的标识符使用的是最小元素的值,这样输出的时候就可以避免重复输出,只输出本元素在本等价类这样的等价类即可。

最后还需要提及的一个小点是读入输入的数对时需要提取数字,此时用到了string。

浅谈一下课本上对在线等价类输出的想法:用到了递归

首先关于n个数字建立n个栈,和一个含有n个元素的一个bool类型的初始化为false数组,还有一个存储未被处理(没有完全被找到等价的的元素)的栈unprocessedList,假设输入的数字是a和b,那么将b存入第a个栈,将a存入第b个栈,表示一种等价关系。取n个元素中第一个元素开始循环,当unprocessedList不为空时,将这个元素压入栈,取出赋给j,取出第j个栈的第一个元素,若这个元素没有被输出,则输出这个元素,并且将这个元素压入栈,表示这个元素的等价类还没有被查找,然后接着取这个栈里的元素进行循环,即可输出所有的等价类,有一种顺着一个瓜摸到所在藤的所有瓜的感觉。但是这个方法并没有实现排序,若想在此基础上进行排序,则可利用上面的循环。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值