紅黑樹並沒有我們想象的那麼難(下)
// sgi stl _Rb_tree 插入演算法 insert_equal() 實現. // 策略概述: insert_equal() 在紅黑樹找到自己的位置, // 然後交由 _M_insert() 來處理接下來的工作. // _M_insert() 會將節點插入紅黑樹中, 接著調整紅黑樹, // 維持性質. template <class _Key, class _Value, class _KeyOfValue, class _Compare, class _Alloc> typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::iterator _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc> ::insert_equal(const _Value& __v) { // 在紅黑樹中有頭結點和根節點的概念, 頭結點位於根節點之上, // 頭結點只為管理而存在, 根節點是真正儲存資料的地方. 頭結點和根節點互為父節點, // 是一種實現的技巧. _Link_type __y = _M_header; // 指向頭結點 _Link_type __x = _M_root(); // _M_header->_M_parent, 即指向根節點 // 尋找插入的位置 while (__x != 0) { __y = __x; // 小於當前節點要走左邊, 大於等於當前節點走右邊 __x = _M_key_compare(_KeyOfValue()(__v), _S_key(__x)) ? _S_left(__x) : _S_right(__x); } // __x 為需要插入的節點的位置, __y 為其父節點 return _M_insert(__x, __y, __v); } // sgi stl _Rb_tree 插入演算法 insert_unique() 實現. // 策略概述: insert_unique() 同樣也在紅黑樹中找到自己的位置; 我們知道, // 如果小於等於當前節點會往右走, 所以遇到一個相同鍵值的節點後, 會往右走一步, // 接下來一直往左走, 所以下面的實現會對往左走的情況做特殊的處理. template <class _Key, class _Value, class _KeyOfValue, class _Compare, class _Alloc> pair<typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::iterator, bool> _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc> ::insert_unique(const _Value& __v) { _Link_type __y = _M_header; // 指向頭結點 _Link_type __x = _M_root(); // 指向根節點, 可能為空 bool __comp = true; // 尋找插入的位置 while (__x != 0) { __y = __x; __comp = _M_key_compare(_KeyOfValue()(__v), _S_key(__x)); // 小於當前節點要走左邊, 大於等於當前節點走右邊 __x = __comp ? _S_left(__x) : _S_right(__x); } iterator __j = iterator(__y); // 在 __y 上建立迭代器 // 我認為下面判斷樹中是否有存在鍵值的情況有點繞, // 它充分利用了二叉搜尋樹的性質, 如此做很 hack, 但不易理解. // 要特別注意往左邊插入的情況. // HACKS: // 下面的 if 語句是比 __x 小走左邊的情況: 會發現, 如果插入一個已存在的鍵的話, // __y 最終會定位到已存在鍵的右子樹的最左子樹. // 譬如, 紅黑樹中已經存在一個鍵為 100 的節點, 其右孩子節點為 101, // 此時如果再插入鍵為 100 的節點, 因為 100<=100, 所以會往右走到達 101 節點, // 有 100<101, 繼而往左走, 會一直往左走.大家稍微畫一個例子就能理解. if (__comp) // 特殊情況, 如果 __j 指向了最左孩子, 那麼肯定要插入新節點. if (__j == begin()) return pair<iterator,bool>(_M_insert(__x, __y, __v), true); // 其他情況, 這個時候也是往左邊插入, 如果存在重複的鍵值, // 那麼 --__j 能定位到此重複的鍵的節點. else --__j; // HACKS: 這裡比較的是 __j 和 __v, 如果存在鍵值, 那麼 __j == __v, // 會跳過 if 語句. 否則執行插入. 也就是說如果存在重複的鍵, 那麼 __j // 的值肯定是等於 __v if (_M_key_compare(_S_key(__j._M_node), _KeyOfValue()(__v))) return pair<iterator,bool>(_M_insert(__x, __y, __v), true); // 此時 __y.value = __v, 不允許插入, 返回鍵值所在位置 return pair<iterator,bool>(__j, false); } // _M_insert() 是真正執行插入的地方. // 策略概述: 插入策略已經在上篇中詳述, 可以根據上篇文章的描述, // 和下面程式碼的註釋, 加深對紅黑樹插入演算法裡理解 template <class _Key, class _Value, class _KeyOfValue, class _Compare, class _Alloc> typename _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc>::iterator _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc> ::_M_insert(_Base_ptr __x_, _Base_ptr __y_, const _Value& __v) { _Link_type __x = (_Link_type) __x_; // 新節點插入的位置. // 關於 __x 的疑問: // 1. 它被放到下面的, 第一個 if 語句中, 我覺得是沒有必要的, // 因為從呼叫 _M_insert() 的函式來看, __x 總是為空. // 2. 既然 __x 是新節點插入的位置, 那麼為什麼不直接在 __x 上建立節點, // 還要在下面通過比較來決定新節點是左孩子還是右孩子; // 不如直接用指標的指標或者指標的引用來完成, 省去了下面的判斷. _Link_type __y = (_Link_type) __y_; // 新節點的父節點 _Link_type __z; // 新節點的位置 if (__y == _M_header || __x != 0 || _M_key_compare(_KeyOfValue()(__v), _S_key(__y))) { // 新節點應該為左孩子 __z = _M_create_node(__v); _S_left(__y) = __z; // also makes _M_leftmost() = __z // when __y == _M_header if (__y == _M_header) { _M_root() = __z; _M_rightmost() = __z; } else if (__y == _M_leftmost()) _M_leftmost() = __z; // maintain _M_leftmost() pointing to min node } // 新節點應該為右孩子 else { __z = _M_create_node(__v); _S_right(__y) = __z; if (__y == _M_rightmost()) _M_rightmost() = __z; // maintain _M_rightmost() pointing to max node } _S_parent(__z) = __y; _S_left(__z) = 0; _S_right(__z) = 0; // 重新調整 _Rb_tree_rebalance(__z, _M_header->_M_parent); // 更新紅黑樹節點數 ++_M_node_count; // 返回迭代器型別 return iterator(__z); } // 插入新節點後, 可能會破壞紅黑樹性質, _Rb_tree_rebalance() 負責維持性質. // 其中: // __x 新插入的節點 // __root 根節點 // 策略概述: 紅黑樹插入重新調整的策略已經在上篇中講述, // 可以結合上篇文章和這裡的程式碼註釋, // 理解紅黑樹的插入演算法. inline void _Rb_tree_rebalance(_Rb_tree_node_base* __x, _Rb_tree_node_base*& __root) { // 將新插入的節點染成紅色 __x->_M_color = _S_rb_tree_red; while (__x != __root && __x->_M_parent->_M_color == _S_rb_tree_red) { // __x 的父節點也是紅色的情況. 提示: 如果是黑色節點, 不會破壞紅黑樹性質. if (__x->_M_parent == __x->_M_parent->_M_parent->_M_left) { // 叔父節點 _Rb_tree_node_base* __y = __x->_M_parent->_M_parent->_M_right; if (__y && __y->_M_color == _S_rb_tree_red) { // 第 1 種情況, N,P,U 都紅(G 肯定黑). // 策略: G->紅, N,P->黑. 此時, G 紅, 如果 G 的父親也是紅, 性質又被破壞了, // HACK: 可以將 GPUN 看成一個新的紅色 N 節點, 如此遞迴調整下去; // 特俗的, 如果碰巧將根節點染成了紅色, 可以在演算法的最後強制 root->紅. __x->_M_parent->_M_color = _S_rb_tree_black; __y->_M_color = _S_rb_tree_black; __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red; __x = __x->_M_parent->_M_parent; } else { if (__x == __x->_M_parent->_M_right) { // 第 2 種情況, P 為紅, N 為 P 右孩子, U 為黑或缺少. // 策略: 旋轉變換, 從而進入下一種情況: __x = __x->_M_parent; _Rb_tree_rotate_left(__x, __root); } // 第 3 種情況, 可能由第二種變化而來, 但不是一定: P 為紅, N 為紅. // 策略: 旋轉, 交換 P,G 顏色, 調整後, 因為 P 為黑色, 所以不怕 // P 的父節點是紅色的情況. over __x->_M_parent->_M_color = _S_rb_tree_black; __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red; _Rb_tree_rotate_right(__x->_M_parent->_M_parent, __root); } } else { // 下面的程式碼是映象得出的, 腦補吧. _Rb_tree_node_base* __y = __x->_M_parent->_M_parent->_M_left; if (__y && __y->_M_color == _S_rb_tree_red) { __x->_M_parent->_M_color = _S_rb_tree_black; __y->_M_color = _S_rb_tree_black; __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red; __x = __x->_M_parent->_M_parent; } else { if (__x == __x->_M_parent->_M_left) { __x = __x->_M_parent; _Rb_tree_rotate_right(__x, __root); } __x->_M_parent->_M_color = _S_rb_tree_black; __x->_M_parent->_M_parent->_M_color = _S_rb_tree_red; _Rb_tree_rotate_left(__x->_M_parent->_M_parent, __root); } } } __root->_M_color = _S_rb_tree_black; } // 刪除演算法, 直接呼叫底層的刪除實現 _Rb_tree_rebalance_for_erase(). template <class _Key, class _Value, class _KeyOfValue, class _Compare, class _Alloc> inline void _Rb_tree<_Key,_Value,_KeyOfValue,_Compare,_Alloc> ::erase(iterator __position) { _Link_type __y = (_Link_type) _Rb_tree_rebalance_for_erase(__position._M_node, _M_header->_M_parent, _M_header->_M_left, _M_header->_M_right); destroy_node(__y); --_M_node_count; } // 刪除節點底層實現, 刪除可能會破壞紅黑樹性質, // _Rb_tree_rebalance() // 負責維持性質. 其中: // __z 需要刪除的節點 // __root 根節點 // __leftmost 紅黑樹內部資料, 即最左子樹 // __rightmost 紅黑樹內部資料, 即最右子樹 // 策略概述: _Rb_tree_rebalance_for_erase() 會根據 // 刪除節點的位置在紅黑樹中找到頂替刪除節點的節點, // 即無非是刪除節點左子樹的最大節點或右子樹中的最小節點, // 此處用的是有一種策略. 接著, 會調整紅黑樹以維持性質. // 調整的演算法已經在上篇文章中詳述, 可以根據上篇文章的描述 // 和此篇的程式碼註釋, 加深對紅黑樹刪除演算法的理解. inline _Rb_tree_node_base* _Rb_tree_rebalance_for_erase(_Rb_tree_node_base* __z, _Rb_tree_node_base*& __root, _Rb_tree_node_base*& __leftmost, _Rb_tree_node_base*& __rightmost) { // __z 是要刪除的節點 // __y 最終會指向要刪除的節點 _Rb_tree_node_base* __y = __z; // N 節點 _Rb_tree_node_base* __x = 0; // 記錄 N 節點的父節點 _Rb_tree_node_base* __x_parent = 0; // 只有一個孩子或者沒有孩子的情況 if (__y->_M_left == 0) // __z has at most one non-null child. y == z. __x = __y->_M_right; // __x might be null. else if (__y->_M_right == 0) // __z has exactly one non-null child. y == z. __x = __y->_M_left; // __x is not null. // 有兩個非空孩子 else { // __z has two non-null children. Set __y to __y = __y->_M_right; // __z's successor. __x might be null. // __y 取右孩子中的最小節點, __x 記錄他的右孩子(可能存在右孩子) while (__y->_M_left != 0) __y = __y->_M_left; __x = __y->_M_right; } // __y != __z 說明有兩個非空孩子的情況, // 此時的刪除策略就和文中提到的普通二叉搜尋樹刪除策略一樣: // __y 記錄了 __z 右子樹中最小的節點 // __x 記錄了 __y 的右孩子 // 用 __y 頂替 __z 的位置, __x 頂替 __y 的位置, 最後用 __y 指向 __z, // 從而 __y 指向了要刪除的節點 if (__y != __z) { // relink y in place of z. y is z's successor // 將 __z 的記錄轉移至 __y 節點 __z->_M_left->_M_parent = __y; __y->_M_left = __z->_M_left; // 如果 __y 不是 __z 的右孩子, __z->_M_right 有左孩子 if (__y != __z->_M_right) { __x_parent = __y->_M_parent; // 如果 __y 有右孩子 __x, 必須有那個 __x 替換 __y 的位置 if (__x) // 替換 __y 的位置 __x->_M_parent = __y->_M_parent; __y->_M_parent->_M_left = __x; // __y must be a child of _M_left __y->_M_right = __z->_M_right; __z->_M_right->_M_parent = __y; } // __y == __z->_M_right else __x_parent = __y; // 如果 __z 是根節點 if (__root == __z) __root = __y; // __z 是左孩子 else if (__z->_M_parent->_M_left == __z) __z->_M_parent->_M_left = __y; // __z 是右孩子 else __z->_M_parent->_M_right = __y; __y->_M_parent = __z->_M_parent; // 交換需要刪除節點 __z 和 替換節點 __y 的顏色 __STD::swap(__y->_M_color, __z->_M_color); __y = __z; // __y now points to node to be actually deleted } // __y == __z 說明至多一個孩子 else { // __y == __z __x_parent = __y->_M_parent; if (__x) __x->_M_parent = __y->_M_parent; // 將 __z 的父親指向 __x if (__root == __z) __root = __x; else if (__z->_M_parent->_M_left == __z) __z->_M_parent->_M_left = __x; else __z->_M_parent->_M_right = __x; // __leftmost 和 __rightmost 是紅黑樹的內部資料, 因為 __z 可能是 // __leftmost 或者 __rightmost, 因此需要更新. if (__leftmost == __z) if (__z->_M_right == 0) // __z->_M_left must be null also // __z 左右孩子都為空, 沒有孩子 __leftmost = __z->_M_parent; // makes __leftmost == _M_header if __z == __root else __leftmost = _Rb_tree_node_base::_S_minimum(__x); if (__rightmost == __z) if (__z->_M_left == 0) // __z->_M_right must be null also __rightmost = __z->_M_parent; // makes __rightmost == _M_header if __z == __root else // __x == __z->_M_left __rightmost = _Rb_tree_node_base::_S_maximum(__x); // __y 同樣已經指向要刪除的節點 } // __y 指向要刪除的節點 // __x 即為 N 節點 // __x_parent 指向 __x 的父親, 即 N 節點的父親 if (__y->_M_color != _S_rb_tree_red) { // __y 的顏色為黑色的時候, 會破壞紅黑樹性質 while (__x != __root && (__x == 0 || __x->_M_color == _S_rb_tree_black)) // __x 不為紅色, 即為空或者為黑. 提示: 如果 __x 是紅色, 直接將 __x 替換成黑色 if (__x == __x_parent->_M_left) { // 如果 __x 是左孩子 _Rb_tree_node_base* __w = __x_parent->_M_right; // 兄弟節點 if (__w->_M_color == _S_rb_tree_red) { //第 2 情況, S 紅, 根據紅黑樹性質P,SL,SR 一定黑. // 策略: 旋轉, 交換 P,S 顏色. __w->_M_color = _S_rb_tree_black; __x_parent->_M_color = _S_rb_tree_red; // 交換顏色 _Rb_tree_rotate_left(__x_parent, __root); // 旋轉 __w = __x_parent->_M_right; // 調整關係 } if ((__w->_M_left == 0 || __w->_M_left->_M_color == _S_rb_tree_black) && (__w->_M_right == 0 || __w->_M_right->_M_color == _S_rb_tree_black)) { // 提示: 這是 第 1 情況和第 2.1 情況的合併, 因為處理的過程是一樣的. // 但他們的情況還是要分門別類的. 已經在文章中詳細支出, // 似乎大多數的博文中沒有提到這一點. // 第 1 情況, N,P,S,SR,SL 都黑. // 策略: S->紅. 通過 PN,PS 的黑色節點數量相同了, 但會比其他路徑多一個, // 解決的方法是在 P 上從情況 0 開始繼續調整. // 為什麼要這樣呢? HACKS: 因為既然 PN,PS // 路徑上的黑節點數量相同而且比其他路徑會少一個黑節點, // 那何不將其整體看成了一個 N 節點! 這是遞迴原理. // 第 2.1 情況, S,SL,SR 都黑. // 策略: P->黑. S->紅, 因為通過 N 的路徑多了一個黑節點, // 通過 S 的黑節點個數不變, 所以維持了性質 5. over // 可能大家會有疑問, 不對啊, 2.1 的情況, // 策略是交換父節點和兄弟節點的顏色, 此時怎麼沒有對父節點的顏色賦值呢? // HACKS: 這就是合併情況的好處, 因為就算此時父節點是紅色, // 而且也將兄弟節點顏色改為紅色, 你也可以將 PS,PN 看成一個紅色的 N 節點, // 這樣在下一個迴圈當中, 這個 N 節點也會變成黑色. 因為此函式最後有一句話: // if (__x) __x->_M_color = _S_rb_tree_black; // 合併情況, 節省程式碼量 // 當然是可以分開寫的 // 兄弟節點染成紅色 __w->_M_color = _S_rb_tree_red; // 調整關係 __x = __x_parent; __x_parent = __x_parent->_M_parent; } else { if (__w->_M_right == 0 || __w->_M_right->_M_color == _S_rb_tree_black) { // 第 2.2.1 情況, S,SR 黑, SL 紅. // 策略: 旋轉, 變換 SL,S 顏色. if (__w->_M_left) __w->_M_left->_M_color = _S_rb_tree_black; __w->_M_color = _S_rb_tree_red; _Rb_tree_rotate_right(__w, __root); // 調整關係 __w = __x_parent->_M_right; } // 第 2.2.2 情況, S 黑, SR 紅. // 策略: 旋轉, 交換 S,P 顏色, SR->黑色, 重新獲得平衡. __w->_M_color = __x_parent->_M_color; __x_parent->_M_color = _S_rb_tree_black; if (__w->_M_right) __w->_M_right->_M_color = _S_rb_tree_black; _Rb_tree_rotate_left(__x_parent, __root); break; } // 下面的程式碼是映象得出的, 腦補吧. } else { // same as above, with _M_right <-> _M_left. _Rb_tree_node_base* __w = __x_parent->_M_left; if (__w->_M_color == _S_rb_tree_red) { __w->_M_color = _S_rb_tree_black; __x_parent->_M_color = _S_rb_tree_red; _Rb_tree_rotate_right(__x_parent, __root); __w = __x_parent->_M_left; } if ((__w->_M_right == 0 || __w->_M_right->_M_color == _S_rb_tree_black) && (__w->_M_left == 0 || __w->_M_left->_M_color == _S_rb_tree_black)) { __w->_M_color = _S_rb_tree_red; __x = __x_parent; __x_parent = __x_parent->_M_parent; } else { if (__w->_M_left == 0 || __w->_M_left->_M_color == _S_rb_tree_black) { if (__w->_M_right) __w->_M_right->_M_color = _S_rb_tree_black; __w->_M_color = _S_rb_tree_red; _Rb_tree_rotate_left(__w, __root); __w = __x_parent->_M_left; } __w->_M_color = __x_parent->_M_color; __x_parent->_M_color = _S_rb_tree_black; if (__w->_M_left) __w->_M_left->_M_color = _S_rb_tree_black; _Rb_tree_rotate_right(__x_parent, __root); break; } } if (__x) __x->_M_color = _S_rb_tree_black; } return __y; }
相關推薦
紅黑樹並沒有我們想象的那麼難(下)
// sgi stl _Rb_tree 插入演算法 insert_equal() 實現. // 策略概述: insert_equal() 在紅黑樹找到自己的位置, // 然後交由 _M_insert() 來處理接下來的工作. // _M_insert() 會將節點插入紅黑樹中, 接著調整紅黑樹, // 維持性
紅黑樹並沒有我們想象的那麼難(上)
紅黑樹並沒有我們想象的那麼難 上、下兩篇已經完成, 希望能幫助到大家. 紅黑樹並沒有想象的那麼難, 初學者覺得晦澀難讀可能是因為情況太多. 紅黑樹的情況可以通過歸結, 通過合併來得到更少的情況, 如此可以加深對紅黑樹的理解. 網路上的大部分紅黑樹的講解因為沒有「合併」. 紅黑樹的五個
紅黑樹,並非想象中的那麼複雜
紅黑樹是非常popular的一種self-adjusted的平衡二叉排序樹。通常他給我們的印象是很複雜,有很多case,要小心的旋轉。有人說,曾將在某公司的面試時,被要求實現紅黑樹。他覺得這很沒有道理,幾乎很少有人能在不參考教科書的情況下,記清楚那麼多的case。在這一章裡,
「碼農讀書」:我們並沒有自己想象的那麼理性
作為碼農/程式設計師,我們經常認為自己是非常理性的。其實不僅是我們自己這麼認為,甚至我們身邊的朋友們在談到對我們的評價時,在聊到對程式設計師這個職業的印象時,都會普遍的認為這是一個非常理性、思維邏輯非常清晰的群體。但事實真的是這樣嗎? 我曾經也非常自信於自己的理性。但最近看了一本大塊頭書《思考,快與慢
紅黑樹真的沒你想的那麼難!
寫本文的原由是昨晚做夢居然夢到了在看原始碼,於是便有了此文...... 雖然標題是關於紅黑樹的,不過此文是結合圖片,通過分析TreeMap的原始碼,讓你理解起來不是那麼枯燥(前方高能,此文圖片眾多,慎入)。 作者 | 馬雲飛 責編 | 胡巍巍
Java轉python機器學習,並沒有大家想象的那麼美好!
輾轉幾年Java開發,換了幾份工作,沒一個穩定的學習、工作過程。中間也相親幾次,都是沒啥結果。換工作頻繁也嚴重打亂了和姑娘接觸的節奏。糟心工作連著遇到幾次,也怪自己眼光有問題。 2018也找了2次工作,中間有4、5個月沒有工作。看了個世界盃,看了個亞運會。也怪自己這段時間一直是換工作、找工作,節
紅黑樹真的沒你想的那麼難
概述 TreeMap是紅黑樹的java實現,紅黑樹能保證增、刪、查等基本操作的時間複雜度為O(lgN)。 首先我們來看一張TreeMap的繼承體系圖: 還是比較直觀的,這裡來簡單說一下繼承體系中不常見的介面NavigableMap和SortedMa
死磕Java並:J.U.C之ConcurrentHashMap紅黑樹轉換分析
作者:chessy來源:Java技術驛站在【死磕Java併發】-----J.U.C之Java併發
數據結構(5) 第五天 快速排序、歸並排序、堆排序、高級數據結構介紹:平衡二叉樹、紅黑樹、B/B+樹
平衡二叉樹 let b+樹 堆排 mark 9.png 思想 incr 相等 01 上次課程回顧 希爾排序 又叫減少增量排序 increasement = increasement / 3 + 1 02 快速排序思想 思想: 分治法 + 挖坑
遠端辦公,也許並沒有你想象的那麼輕鬆
春節假期結束已經一個多星期了,隨著疫情的逐漸控制,很多企業陸陸續續開啟了復工模式,但為了安全考慮,有一部分企業仍然採取延遲復工的策略,比如大部分的網際網路公司,像我們熟悉的阿里、騰訊就規定復工時間延遲到2月17日,而企業的日常工作就通過遠端辦公的方式展開,藉著這次東風,很多人體驗到了遠端辦公的魅力之處,更有甚
【bzoj3227】紅黑樹
發現 blog ret amp 這樣的 spa 兩個 include log 神TM的紅黑樹,其實本質上應該還是一種樹dp的問題…… 一開始想了一個比較裸的樹dp,後來發現還有更強的做法。 每個前端黑節點是看作一個物品,然後這就是很典型的樹形dp的問題。 不過可以這麽考慮,
圖解集合7:紅黑樹概念、紅黑樹的插入及旋轉操作詳細解讀
集合 得到 2個 排序。 數據流 except boolean 修正 split 原文地址http://www.cnblogs.com/xrq730/p/6867924.html,轉載請註明出處,謝謝! 初識TreeMap 之前的文章講解了兩種Map,分別是HashMa
紅黑樹C++實現
con colors end ase 復制代碼 設置 typename ucc 技術 1 /* 2 * rbtree.h 3 * 1. 每個節點是紅色或者黑色 4 * 2. 根節點是黑色 5 * 3. 每個葉子節點是黑色(該葉子節點就空的節點)
數據結構學習筆記-排序/隊/棧/鏈/堆/查找樹/紅黑樹
算法 數據結構排序:插入排序:每次從剩余數據中選取一個最小的,插入已經排序完成的序列中合並排序:將數據分成左右兩組分別排序,然後合並,對每組數據的排序遞歸處理。冒泡排序:重復交換兩個相鄰元素,從a[1]開始向a[0]方向冒泡,然後a[2]...當a[i]無法繼續往前擠的時候說明前面的更小了,而且越往前越小(擠
查找(一)史上最簡單清晰的紅黑樹解說
ont 演示 detail align article 向上 節點 動態插入 列表 查找(一) 我們使用符號表這個詞來描寫敘述一張抽象的表格。我們會將信息(值)存儲在當中,然後依照指定的鍵來搜索並獲取這些信息。鍵和值的詳細意義取決於不同的應用。 符號表中可能會保
教你透徹了解紅黑樹
black ade 我們 工作 key 針對 otn strong lean 教你透徹了解紅黑樹 作者:July、saturnman 2010年12月29日 本文參考:Google、算法導論、STL源碼剖析、計算機程序設計藝術。 推薦閱讀: Left-
紅黑樹
else if 滿足 編碼 使用 由於 imap ica 困難 十分 轉自:http://www.cnblogs.com/yangecnu/p/Introduce-2-3-Search-Tree.html 前面一篇文章介紹了2-3查找樹,可以看到,2-3查找樹能保證在插
紅黑樹與AVL樹
target 相同 spa search htm 解決 evel 所有應用 二叉搜索樹 概述:本文從排序二叉樹作為引子,講解了紅黑樹,最後把紅黑樹和AVL樹做了一個比較全面的對比。 1 排序二叉樹 排序二叉樹是一種特殊結構的二叉樹,可以非常方便地對樹中所有節點進行排
紅黑樹 ------ luogu P3369 【模板】普通平衡樹(Treap/SBT)
div child lin main false tchar clas char als 二次聯通門 : luogu P3369 【模板】普通平衡樹(Treap/SBT) 近幾天閑來無事。。。就把各種平衡樹都寫了一下。。。 下面是紅黑樹(Red Black Tree)
關聯容器set的用法(關聯容器,紅黑樹,)
ise 特定 using iter tor pre .com main com set和multiset會根據特定的排序準則自動將元素排序,set中元素不允許重復,multiset可以重復。// 2017/7/23號 好像set容器裏面只能裝一個元素#include<