看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容器的具...