繁体   English   中英

C ++:二进制搜索树end()迭代器

[英]C++: Binary search tree end() iterator

我有BST的基本(无随机化,排序等)实现。 我想添加迭代器实现并使BST适用于基于范围的for循环。 因此,我需要begin(),end()成员函数和迭代器递增。

我知道begin()应该做什么-将迭代器返回到最左下角的节点,并且该线程讨论了遍历BST的不同可能性(=增加迭代器)

但是end()应该将迭代器赋予最后一个元素。 这是我不理解的实际问题,在BST的背景下,这是什么意思?

结束迭代器不必一定是最后一个元素之后的元素(对于矢量有意义,但对于树而言则不那么有意义)。 它必须只是一个可以清楚地标识为不是用于指示已到达数据结构末尾的有效迭代器的迭代器。

实际上,这可以通过多种方式完成,具体取决于迭代器如何引用其指向的内容。 如果例如使用指向树节点的指针,则可以将空指针用作结束迭代器。

一个非常简单的使用两个额外指针的内存的方案是将一个双向链接的循环列表简单地覆盖在BST的顶部。 然后,您的end()迭代器仅指向一个前哨节点。 这也使您的迭代器增加/减少非常简单。

BST::iterator &
BST::iterator::operator++() {
  n = n->next;
  return *this;
}

注意,像这样使用哨兵意味着end迭代器不需要特殊处理。 您可以减少它并获得完全正确的行为。

尽管有我的评论,桑德·戴克(Sander De Dycker)的想法正确。 我有另一种思考方式。

所有支持迭代器的容器都具有逻辑顺序。 对于vector ,排序基于插入的完成方式-索引/下标排序。 对于mapset它基于键顺序。 对于multimapmultiset ,两者都有一点。 对于unordered_map等,声明是非常脆弱的,但是我仍然可以讨论哈希算法和冲突处理。

按照逻辑顺序,您可以引用有序元素,但是有时引用每个元素之间的边界是有意义的。 从逻辑上讲(在某些情况下甚至对于实现而言),这样做也很方便。

|     |     |     |     |     |     |     |     |
| +-+ | +-+ | +-+ | +-+ | +-+ | +-+ | +-+ | +-+ |
| |0| | |1| | |2| | |3| | |4| | |5| | |6| | |7| |
| +-+ | +-+ | +-+ | +-+ | +-+ | +-+ | +-+ | +-+ |
|     |     |     |     |     |     |     |     |
0     1     2     3     4     5     6     7     8

您可以确定零“绑定”的去向与零项的去向无关,但是始终可以获得简单的加/减关系。 如果最小边界的编号与最小元素的编号相同,则最后一个边界的编号比最后一个元素的编号大一个。 因此end作为一个过去的最终元件。

在二叉树实现中,每个节点都可以视为具有两个边界-元素的任一侧。 在此方案中,除beginend之外的每个界限都发生两次。 您可以使用元素0的RHS或LHS或元素1来表示边界1。因此,原则上可以使用节点指针和标志。 但是,您可能会选择最方便的一种方法,而不是针对大多数范围使用两种方法,一种方法是不仅指的是右边界,而且还指的是在取消引用时要查看的元素。 这意味着仅在引用end时设置标志,在这种情况下,您无论如何都不支持取消引用。

IOW遵循此逻辑可以告诉您,尽管我认为它仍然是一个有用的思维模型,但您实际上并不需要遵循此逻辑。 您真正需要的只是end的可识别表示。 对于该表示形式,包括指向最终指针的指针(作为例如减少该迭代器的起点)也许很有用。 也许在某些情况下,内部让伪迭代器将两个等效边界识别为不同是很方便的。

考虑到例如多路树(multiway tree),其中每个节点包含一个元素数组,出现了相似但略有不同的模型和选择。

基本上,我认为从心理上将绑定的位置识别为与项目位置相关但与项目位置相关的位置很有用,但是该心理模型不应限制您的实现选择-可能会激发替代方法,但这只是一种心理模型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM