本文共 2465 字,大约阅读时间需要 8 分钟。
数据结构(2021春季)报告
使用前置列表(forward_list)合并两个无重复元素的集合L_a和L_b。将其排序后,再合并为L_c。分析时间和空间复杂度。
要在前置列表中合并L_a和L_b,我编写了一个支持类似于std::forward_list的名称空间tvj的forward_list。由于L_a和L_b已经排序,L_c的元素应选择当前未合并最小的L_a和L_b中的元素。另外,需要检查是否存在重复元素,以确保不添加重复的元素。为此,我在调试模式下使用了merge函数,如果这两个列表未排序,将会先排序它们。不过在发布模式中,这一步被跳过了。
在我的GitHub仓库TVJ_Forward_List(链接如下)中可以找到与merge功能相关的函数定义。当前版本为v1.1,于2021年3月20日发布。
templatebool forward_list(elem>&&elem) ::sorted(bool is_ascending){ if (size_ < 2) return true; for (auto iter = cbegin(); iter + 1 != cend(); ++iter) { if (*iter == *(iter + 1)) continue; if ((*iter < *(iter+1)) ^ is_ascending) return false; } return true;}
templatevoid forward_list(elem>&&elem)::merge(const forward_list& list_, bool is_ascending){ if (list_.empty()) return; // 以下代码已被优化 // 与当前对象和待合并列表复制 // 检查排序状态并进行排序(调试模式) auto first_1 = this->head; auto end_1 = this->tail; auto first_2 = list_.head; auto end_2 = list_.tail; auto i = first_1->succ; auto j = first_2->succ; auto h = this->head; bool label = true; size_t new_size = 0; while (i && i != end_1 && j && j != end_2) { if (i->data == j->data) { h = h->succ = i; i = i->succ; j = j->succ; label = true; } else if ((i->data < j->data) ^ !is_ascending) { h = h->succ = i; i = i->succ; label = true; } else { h = h->succ = j; j = j->succ; } new_size++; } // 处理剩余的元素 while (i && i != end_1) { h = h->succ = i; i = i->succ; new_size++; } while (j && j != end_2) { h = h->succ = j; j = j->succ; new_size++; } // 设置尾部 tail = h->succ; size_ = new_size;}
测试结果表明,list1和list3已经成功合并。下图展示了在Visual Studio 2019和Qt 6.0.0环境下的输出。
设n1为当前列表的长度,n2为待合并列表的长度。
所有操作均不使用额外的临时空间,因此空间复杂度为O(1)。
合并操作本质上并不难,但实现前置列表则非常具有挑战性。编写如此复杂的数据结构需要投入众多时间和精力。在完成这项任务的过程中,我深入理解了内联类和异常生成式等C++特性,以及对STL代码的深刻洞察。特别是sort函数的实现,对我后续的数据结构学习起到了激励作用。通过这次任务,我不仅加深了对前置列表的理解,还为探索更多数据结构的奥秘奠定了基础。
本报告使用LaTeX编写。更多信息,请访问我的CSDN博客或GitHub profiles页面。
转载地址:http://gpogz.baihongyu.com/