STL原始碼 RB Tree insert操作

2021-07-05 08:45:07 字數 2885 閱讀 6354

看stl原始碼剖析時,真正的插入函式__insert(base_ptr x, base_ptr y, const value& v)時,發現引數x幾乎沒什麼用,查了一些資料,發現x是在呼叫另乙個insert過載函式時發揮作用的,於是整理了一下insert函式。

stl關聯容器map/multimp,set/multiset,都是使用了紅黑樹的底層結構。insert有兩個過載函式,乙個insert(const value&),乙個是insert_unique(iterator, const value&),後者是帶hint的插入。《c++標準程式庫》中說道:若被安插元素位置恰好緊貼於提示位置之後,那麼時間複雜度就會從「對數」變為「攤還常數」。當hint恰當時,可大大加快速度。

對於map和set,insert函式會呼叫rb-tree中的insert_unique版本,對於multimap和multiset,則呼叫rb-tree中的insert_equal版本。由於insert_equal較insert_unique簡單一些,所以這裡只分析insert_unique.

template

typename rb_tree::iterator

rb_tree::insert_unique(iterator position,

const val& v)

}

以上**思路如下:

pos為leftmost(提示位置為begin)

v < leftmost:直接插在leftmost的左兒子處即可。此時第乙個引數不為空。

否則直接呼叫insert_unique無hint版本

pos為header(提示位置為end)

rightmost < v:插到rightmost的右兒子處,即:呼叫insert(0,rightmost,v)

否則直接呼叫insert_unique無hint版本

pos既不是begin,也不是end, before = pos - 1

before < v < pos

before 右子樹為空

⇒ before是pos左子樹中的最大值(before一定沒有右兒子),則插入點為before的右兒子處

before有右兒子

⇒ pos是before的右子樹中最小值(pos一定沒有左兒子),則插入點為pos的左兒子處

否則直接呼叫insert_unique無hint版本

不帶hint的insert_unique函式如下:

// 安插新值;節點鍵值不允許重複,若重複則安插無效。

// 注意,傳回值是個pair,第一元素是個 rb-tree 迭代器,指向新增節點,

// 第二元素表示安插成功與否。

template

pair

rb_tree::insert_unique(const value& v)

// 離開 while 迴圈之後,y 所指即安插點之父節點(此時的它必為葉節點)

iterator j = iterator(y); // 令迭代器j指向安插點之父節點 y

if (comp) // 如果離開 while 迴圈時 comp 為真(表示遇「大」,將安插於左側)

if (j == begin()) // 如果安插點之父節點為最左節點

return pairbool>(__insert(x, y, v), true);

// 以上,x 為安插點,y 為安插點之父節點,v 為新值。

else

// 否則(安插點之父節點不為最左節點)

--j; // 調整 j,回頭準備測試...

if (key_compare(key(j.node), keyofvalue()(v)))

// 小於新值(表示遇「小」,將安插於右側)

return pairbool>(__insert(x, y, v), true);

// 進行至此,表示新值一定與樹中鍵值重複,那麼就不該插入新值。

return pairbool>(j, false);

}

以上iterator j的作用為:若待插入的key與某個結點相同(設為p),則在while迴圈中,某一次x = p後,大於等於向右走,則下一次x = p.right,由於v的值一定小於p的右子樹中任何乙個值,所以進入p的右子樹後,x一定是一直向左走直到節點y(y的左兒子為空)。則y為p的右子樹最小值,iterator(p) = iterator(y) - 1,p即為**中的j。若v與j的值不同,則可以執行插入操作,否則返回j和false。

實際完成插入的函式為__insert(hint, parent, v),當hint不為0時,直接插在左兒子處,**如下:

template 

typename rb_tree

::iterator

rb_tree

::__insert(base_ptr x_, base_ptr y_, const value& v)

else

if (y == leftmost()) // 如果y為最左節點

leftmost() = z; // 維護leftmost(),使它永遠指向最左節點

} else

parent(z) = y; // 設定新節點的父節點

left(z) =

0;

right(z) =

0;

__rb_tree_rebalance(z, header

->

parent); // 引數一為新增節點,引數二為 root

++node_count; // 節點數累加

return iterator(z); // 傳回乙個迭代器,指向新增節點

}

STL 原始碼閱讀

1 這裡可以看出來,容器將迭代器作為類成員。vectora iteratorite a.begin 容器的成員函式可以返回迭代器,所以迭代器是容器的成員物件。2 個人理解,迭代器是對指標的封裝和提公升,盡可能遮蔽資料結構的底層細節,對外提供統一的操作介面,這些介面跟普通指標的功能類似,比如自增或自減...

STL原始碼簡述

stl是standard template library的簡稱,中文名標準模板庫,惠普實驗室開發的一系列軟體的統稱。從根本上說,stl是一些 容器 的集合,這些 容器 有list,vector,set,map等,stl也是演算法和其他一些元件的集合。這裡的 容器 和演算法的集合指的是世界上很多聰明...

STL原始碼剖析

這兩天略讀完了 stl原始碼剖析 之所以是略讀,就是只看大體,不講具現 這個詞在 深度探析c 物件模型 中比較多 已經看過好幾本c 的書了,感覺c 本身設計的博大精深,而c 編譯器就更是乙個神奇的東西,換句話說,你永遠不知道c 編譯器揹著你做了哪些出乎你意料的事 不扯遠了 我主要是想看stl容器的具...