简体   繁体   English

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

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

I have basic (no randomization, ordering etc) implementation of the BST. 我有BST的基本(无随机化,排序等)实现。 I want add iterators implementations and make the BST suitable for the ranged based for-loop. 我想添加迭代器实现并使BST适用于基于范围的for循环。 So I need begin(), end() member fucnctions and iterator incrementing. 因此,我需要begin(),end()成员函数和迭代器递增。

I understand what begin() should do -return the iterator to the bottom-left-most node, and this thread discusses different possibilites for traversing the BST (=incrementing the iterator) 我知道begin()应该做什么-将迭代器返回到最左下角的节点,并且该线程讨论了遍历BST的不同可能性(=增加迭代器)

But the end() is supposed to give the iterator to the one-past-the-last element. 但是end()应该将迭代器赋予最后一个元素。 And this is the actual question, that I don't understand, what is the meaning of that in the context of a BST? 这是我不理解的实际问题,在BST的背景下,这是什么意思?

The end iterator doesn't necessarily have to be one past the last element (that makes sense for vectors, but less so for trees eg.). 结束迭代器不必一定是最后一个元素之后的元素(对于矢量有意义,但对于树而言则不那么有意义)。 It has to just be an iterator that can clearly be identified as not a valid iterator used for indicating that the end of the data structure is reached. 它必须只是一个可以清楚地标识为不是用于指示已到达数据结构末尾的有效迭代器的迭代器。

Practically, this can be done in several ways, depending on how your iterator refers to what it's pointing to. 实际上,这可以通过多种方式完成,具体取决于迭代器如何引用其指向的内容。 If it uses a pointer to a tree node eg., then a null pointer can be used for the end iterator. 如果例如使用指向树节点的指针,则可以将空指针用作结束迭代器。

A very simple scheme that uses two extra pointers-worth of memory is to simply overlay a doubly-linked, circular list on top of the BST. 一个非常简单的使用两个额外指针的内存的方案是将一个双向链接的循环列表简单地覆盖在BST的顶部。 Your end() iterator then simply points to a sentinel node. 然后,您的end()迭代器仅指向一个前哨节点。 It also makes your iterator increment/decrement very simple. 这也使您的迭代器增加/减少非常简单。

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

etc. Note that using a sentinel like this means that the end iterator requires no special treatment. 注意,像这样使用哨兵意味着end迭代器不需要特殊处理。 You can decrement it and get exactly the correct behavior. 您可以减少它并获得完全正确的行为。

Despite my comment, Sander De Dycker has the right idea. 尽管有我的评论,桑德·戴克(Sander De Dycker)的想法正确。 I have another way to think about it. 我有另一种思考方式。

All containers that support iterators have a logical ordering. 所有支持迭代器的容器都具有逻辑顺序。 For vector the ordering is based on how the inserts were done - the index/subscript ordering. 对于vector ,排序基于插入的完成方式-索引/下标排序。 For map and set it's based on the key ordering. 对于mapset它基于键顺序。 For multimap and multiset it's a bit of both. 对于multimapmultiset ,两者都有一点。 For unordered_map etc the claim is very tenuous, but I can still argue about hash algorithms and collision handling. 对于unordered_map等,声明是非常脆弱的,但是我仍然可以讨论哈希算法和冲突处理。

In a logical ordering, you can refer to ordered elements, but sometimes it makes sense to refer to the boundaries between each element. 按照逻辑顺序,您可以引用有序元素,但是有时引用每个元素之间的边界是有意义的。 Logically (and in some cases even for the implementation) this works out fairly conveniently... 从逻辑上讲(在某些情况下甚至对于实现而言),这样做也很方便。

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

You decide where the zero "bound" goes independently of where the zero item goes, but you always get a simple addition/subtraction relationship. 您可以确定零“绑定”的去向与零项的去向无关,但是始终可以获得简单的加/减关系。 If the least bound is numbered the same as the least element, the last bound is numbered one more than the last element. 如果最小边界的编号与最小元素的编号相同,则最后一个边界的编号比最后一个元素的编号大一个。 Hence end as one past the final element. 因此end作为一个过去的最终元件。

In a binary tree implementation, each node can be considered to have two bounds - one either side of the element. 在二叉树实现中,每个节点都可以视为具有两个边界-元素的任一侧。 In this scheme, every bound except begin and end occurs twice. 在此方案中,除beginend之外的每个界限都发生两次。 You can represent bound 1 using the RHS of element 0 or the LHS or element 1. So in principle you can use a node pointer and a flag. 您可以使用元素0的RHS或LHS或元素1来表示边界1。因此,原则上可以使用节点指针和标志。 Rather than have two representations for most bounds, though, you'll probably choose the most convenient one where possible - the one where you're not just referring to the right bound but also referring to the element you want to see when you dereference. 但是,您可能会选择最方便的一种方法,而不是针对大多数范围使用两种方法,一种方法是不仅指的是右边界,而且还指的是在取消引用时要查看的元素。 That means the flag will only be set when referring to end , in which case you shouldn't support dereference anyway. 这意味着仅在引用end时设置标志,在这种情况下,您无论如何都不支持取消引用。

IOW following through this logic tells you that you don't really need to follow through this logic, though I think it's still a useful mental model. IOW遵循此逻辑可以告诉您,尽管我认为它仍然是一个有用的思维模型,但您实际上并不需要遵循此逻辑。 All you really need is an identifiable representation for end . 您真正需要的只是end的可识别表示。 Perhaps it's useful for that representation to include a pointer to the final pointer (as a starting point for eg decrementing that iterator). 对于该表示形式,包括指向最终指针的指针(作为例如减少该迭代器的起点)也许很有用。 Perhaps there are situations where it's convenient to have pseudo-iterators internally that recognize the two equivalent bounds as distinct. 也许在某些情况下,内部让伪迭代器将两个等效边界识别为不同是很方便的。

Similar but slightly different models and choices arise thinking about eg multiway trees where each node contains an array of elements. 考虑到例如多路树(multiway tree),其中每个节点包含一个元素数组,出现了相似但略有不同的模型和选择。

Basically I think it's useful to mentally recognise bound positions as distinct but related to item positions, but that mental model shouldn't constraint your implementation choices - it may inspire alternatives but it's just a mental model. 基本上,我认为从心理上将绑定的位置识别为与项目位置相关但与项目位置相关的位置很有用,但是该心理模型不应限制您的实现选择-可能会激发替代方法,但这只是一种心理模型。

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

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