2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 红黑树边界问题

红黑树边界问题

时间:2022-02-26 00:24:07

相关推荐

红黑树边界问题

SGI STL红黑树中迭代器的边界值分析

前言

一段程序最容易出错的就是在判断或者是情况分类的边界地方,所以,应该对于许多判断或者是情况分类的边界要格外的注意。下面,就分析下STL中红黑树的迭代器的各种边界情况。(注意:分析中STL使用的版本是SGI STL,由于不同的版本的STL具体实现细节不一样,所以可能会有出入)。

一、begin()获取第一个迭代器的自减

begin()函数获取的是一个容器的首迭代器,指向容器中的第一个元素(这里的第一个不一定是指储存顺序(物理)上的第一个,一般是指逻辑上的第一个,在红黑树中是指树中的最左节点)。那么对于首个迭代器进行自减会怎样?

(1)首迭代器指向(即最左节点)不是根节点

最左节点不是根节点,就是根节点有左子树。那么第一个迭代器,指向一定是左子树的最左节点。--begin() ,会调用的decrement()函数,该函数如下:

1 void decrement()2 {3if (node->color == __rb_tree_red &&4 node->parent->parent == node)5 node = node->right;6else if (node->left != 0) {7 base_ptr y = node->left;8 while (y->right != 0)9 y = y->right;10 node = y;11}12else {13 base_ptr y = node->parent;14 while (node == y->left) {15 node = y;16 y = y->parent;17 }18 node = y;19}20 }

因为第一个迭代器是执行最左节点,所以其没有左子树,node->parent->parent也不等于node,所以他会回溯,找到第一个node 不是其父节点的左节点,那么他的父节点就是其结果。由于最左节点上溯不可能会有节点不是其父节点的左节点,那么while的最后一个循环时,node指向根节点,y指向header节点,此时node != y->left,(y->left指向就是最左节点),那么循环结束node = y,即指向了header节点,也是end().

(2)首迭代器指向(最左节点)是根节点

最左节点就是根节点,这就说明根节点没有左子树。此时--begin(),同样也是调用的decrement()函数,此时node->parent->parent != node,同时最左节点也没有左子树。那么函数会进入while循环,第一次y指向头结点(header指向的节点),node即是根节点,也是最左节点,循环条件满足,node == y->left(即最左节点),进入循环,node = y,node现在是头结点了,y = y->parent,指向根节点了,(头结点的parent是根节点,这是实现的技巧)。此时y->left,即根节点的左子节点,根没有左子树,所以为0,此时循环条件不满足,跳出循环,再node = y。即node又变为根节点了。即对于根没有左子树的红黑树,对--begin(),其结果还是begin()。

1 iterator it = rb_tree.begin();2 it == --it;

二、end()获取last迭代器的自减

last = end(); last指向的是头结点(也这是红黑树实现中的技巧,header和end()都指向头结点)。此时--last,会调用decrement函数,此时node即是头结点,node->color == __rb_tree_red &&node->parent->parent == node,为真。(头节点的颜色规定为红,而且头节点的parent是根节点,根节点的parent又是头结点,所以node->parent->parent==node)。这时候node = node->right。头结点的右节点,指向的红黑树的最右节点,最大的节点。此时--last,指向最大节点是正确的。

三、指向最右节点迭代器自增

无论什么样的情况,自增都是调用的increment()函数,那么就先上increment函数吧,如下:

1 void increment()2 {3if (node->right != 0) {4 node = node->right;5 while (node->left != 0)6 node = node->left;7}8else {9 base_ptr y = node->parent;10 while (node == y->right) {11 node = y;12 y = y->parent;13 }14 if (node->right != y)15 node = y;16}17 }

(1)最右节点不是根节点

这种情况,就是根节点还有右子树。这种情况下,对指向最右节点的迭代器自增,会调用上面increment函数。应该是指向最右节点,所以node->right == 0,所以只能上溯,找到其现行的节点不是其父节点的右节点。最右节点上溯,不可能会有现行的节点不是其父节点的右节点,while的最后一次循环时,node指向根节点,y指向头结点(即end()指向的节点),这时,node != y->right(存储的是最右节点),跳出循环。在判断node->right != y,现在node是根节点,其有右节点不是头结点,所以判断结果为真,node=y,最后node为y,即头结点,也就是end()返回的迭代器指向的节点,亦是last节点,指向最右的节点的迭代器自增,得到last迭代器,这是正确的。

(2)最右节点是根节点

如下图

此时,指向最右的迭代器自增,调用increment函数,node->right == 0,进入while循环。y开始是node的parent,即头结点,node == y->right(最右节点,此情况下即根节点),循环条件成立,进入循环。然后node = y,node变为头结点,y=y->parent(头结点的parent即根节点),y变为根节点。此时判断循环条件,y->right,即根节点的右子节点,这种情况下的根右子节点为空,node为头结点不为空,循环条件不成立,跳出循环。接下来是

1 if (node->right != y)2 node = y;

此时node是头结点,其右节点就是树的最右节点,这种情况下就是根节点,y就是根节点,那么if判断条件不成立,返回的时候node就是头结点,即end()返回迭代器指向的节点。此时迭代器就是last迭代器。对指向最右节点的迭代器自增,得到last迭代器,亦end()返回的迭代器,这是正确的。

结语

本文中讨论了各种边界情况,其中发现在SGI STL的红黑树中的一个有趣情况,对于迭代器first = begin(),其指向的节点是根节点的时候,(最左节点是根节点),对first自减得到的还是first。对于一些非边界的迭代器的自增和自减,不是这里讨论的范围

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。