SGI STL紅黑樹中迭代器的邊界值分析

2021-06-26 12:00:16 字數 2735 閱讀 8956

一段程式最容易出錯的就是在判斷或者是情況分類的邊界地方,所以,應該對於許多判斷或者是情況分類的邊界要格外的注意。下面,就分析下stl中紅黑樹的迭代器的各種邊界情況。(注意:分析中stl使用的版本是sgi stl,由於不同的版本的stl具體實現細節不一樣,所以可能會有出入)。

begin()函式獲取的是乙個容器的首迭代器,指向容器中的第乙個元素(這裡的第乙個不一定是指儲存順序(物理)上的第乙個,一般是指邏輯上的第乙個,在紅黑樹中是指樹中的最左節點)。那麼對於首個迭代器進行自減會怎樣?

最左節點不是根節點,就是根節點有左子樹。那麼第乙個迭代器,指向一定是左子樹的最左節點。--begin() ,會呼叫的decrement()函式,該函式如下:

void decrement()

else

node = y;}}

因為第乙個迭代器是執行最左節點,所以其沒有左子樹,node->parent->parent也不等於node,所以他會回溯,找到第乙個node 不是其父節點的左節點,那麼他的父節點就是其結果。由於最左節點上溯不可能會有節點不是其父節點的左節點,那麼while的最後乙個迴圈時,node指向根節點,y指向header節點,此時node != y->left,(y->left指向就是最左節點),那麼迴圈結束node = y,即指向了header節點,也是end().

最左節點就是根節點,這就說明根節點沒有左子樹。此時--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()。

iterator it = rb_tree.begin();

it == --it;

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函式吧,如下:

void increment()

else

if (node->right != y)

node = y;}}

這種情況,就是根節點還有右子樹。這種情況下,對指向最右節點的迭代器自增,會呼叫上面increment函式。應該是指向最右節點,所以node->right == 0,所以只能上溯,找到其現行的節點不是其父節點的右節點。最右節點上溯,不可能會有現行的節點不是其父節點的右節點,while的最後一次迴圈時,node指向根節點,y指向頭結點(即end()指向的節點),這時,node != y->right(儲存的是最右節點),跳出迴圈。在判斷node->right != y,現在node是根節點,其有右節點不是頭結點,所以判斷結果為真,node=y,最後node為y,即頭結點,也就是end()返回的迭代器指向的節點,亦是last節點,指向最右的節點的迭代器自增,得到last迭代器,這是正確的。

如下圖

此時,指向最右的迭代器自增,呼叫increment函式,node->right == 0,進入while迴圈。y開始是node的parent,即頭結點,node == y->right(最右節點,此情況下即根節點),迴圈條件成立,進入迴圈。然後node = y,node變為頭結點,y=y->parent(頭結點的parent即根節點),y變為根節點。此時判斷迴圈條件,y->right,即根節點的右子節點,這種情況下的根右子節點為空,node為頭結點不為空,迴圈條件不成立,跳出迴圈。接下來是

if (node->right != y)

node = y;

此時node是頭結點,其右節點就是樹的最右節點,這種情況下就是根節點,y就是根節點,那麼if判斷條件不成立,返回的時候node就是頭結點,即end()返回迭代器指向的節點。此時迭代器就是last迭代器。對指向最右節點的迭代器自增,得到last迭代器,亦end()返回的迭代器,這是正確的。

本文中討論了各種邊界情況,

其中發現在sgi stl的紅黑樹中的乙個有趣情況,對於迭代器first = begin(),其指向的節點是根節點的時候,(最左節點是根節點),對first自減得到的還是first。對於一些非邊界的迭代器的自增和自減,不是這裡討論的範圍。

紅黑樹下 紅黑樹的實現

1.實現紅黑樹的基本思想 實際上,紅黑樹是有固定的平衡過程的 遇到什麼樣的節點分布,我們就對應怎麼去調整。只要按照這些固定的調整規則來操作,就能將乙個非平衡的紅黑樹調整成平衡的。首先,我們需要再來看一下紅黑樹的定義 在插入 刪除節點的過程中,第 三 四點要求可能會被破壞,所以 平衡調整 實際上就是把...

紅黑樹下 紅黑樹的實現

1.實現紅黑樹的基本思想 實際上,紅黑樹是有固定的平衡過程的 遇到什麼樣的節點分布,我們就對應怎麼去調整。只要按照這些固定的調整規則來操作,就能將乙個非平衡的紅黑樹調整成平衡的。首先,我們需要再來看一下紅黑樹的定義 在插入 刪除節點的過程中,第 三 四點要求可能會被破壞,所以 平衡調整 實際上就是把...

紅黑樹筆記 紅黑樹的插入操作

紅黑樹的插入操作可以在o logn 的時間內完成。開始插入節點的時候和二叉查詢樹一樣,只需要最後將插入的節點著成紅色,為了保證紅黑樹的性質,需要通過rb insertfixup函式來調整該節點,對其重新著色並旋轉。下面先呼叫rb insert 函式將乙個節點插入到紅黑樹中,同樣先上偽 rb inse...