一、二叉查找樹(二叉查找樹、二叉搜索樹 )
二叉排序樹(Binary Sort Tree)或者是一棵空樹;或者是具有下列性質的二叉樹:
1.若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
2.若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
3.左、右子樹也分別為二叉排序樹;
4.沒有鍵值相等的節點
二、紅黑樹
紅黑樹,一種二叉查找樹,但在每個結點上增加一個存儲位表示結點的顏色,可以是Red或Black。通過對任何一條從根到葉子的路徑上各個結點着色方式的限制,紅黑樹確保沒有一條路徑會比其他路徑長出倆倍,因而是接近平衡的。
因為一棵由n個結點隨機構造的二叉查找樹的高度為lgn,所以順理成章,二叉查找樹的一般操作的執行時間為O(lgn)。但二叉查找樹若退化成了一棵具有n個結點的線性鏈后,則這些操作最壞情況運行時間為O(n)。
紅黑樹雖然本質上是一棵二叉查找樹,但它在二叉查找樹的基礎上增加了着色和相關的性質使得紅黑樹相對平衡,從而保證了紅黑樹的查找、插入、刪除的時間復雜度最壞為O(log n),為了保證這個性質,所以紅黑樹有以下幾個特性:
1.每個結點要么是紅的要么是黑的。
2.根結點是黑的。
3.每個葉結點(葉結點即指樹尾端NIL指針或NULL結點)都是黑的。
4.如果一個結點是紅的,那么它的兩個兒子都是黑的。
5. 對於任意結點而言,其到葉結點樹尾端NIL指針的每條路徑都包含相同數目的黑結點。
三、紅黑樹的旋轉
紅黑樹的基本操作是添加、刪除。在對紅黑樹進行添加或刪除之后,都會用到旋轉方法。為什么呢?道理很簡單,添加或刪除紅黑樹中的節點之后,紅黑樹就發生了變化,可能不滿足紅黑樹的5條性質,也就不再是一顆紅黑樹了,而是一顆普通的樹。而通過旋轉,可以使這顆樹重新成為紅黑樹。簡單點說,旋轉的目的是讓樹保持紅黑樹的特性。旋轉包括兩種:左旋和右旋。如下圖所示:
1.左旋
左旋的動態圖與靜態圖如下所示:左邊為左旋前,右邊為旋轉后
左旋轉的偽代碼如下,我們可以從中分析出左旋轉的流程
LEFT-ROTATE(T, x) 01 y ← right[x] // 前提:這里假設x的右孩子為y。下面開始正式操作 02 right[x] ← left[y] // 將 “y的左孩子” 設為 “x的右孩子”,即 將β設為x的右孩子 03 p[left[y]] ← x // 將 “x” 設為 “y的左孩子的父親”,即 將β的父親設為x 04 p[y] ← p[x] // 將 “x的父親” 設為 “y的父親” 05 if p[x] = nil[T] 06 then root[T] ← y // 情況1:如果 “x的父親” 是空節點,則將y設為根節點 07 else if x = left[p[x]] 08 then left[p[x]] ← y // 情況2:如果x是它父節點的左孩子,則將y設為“x的父節點的左孩子” 09 else right[p[x]] ← y // 情況3:(x是它父節點的右孩子)將y設為“x的父節點的右孩子” 10 left[y] ← x // 將 “x” 設為 “y的左孩子” 11 p[x] ← y // 將 “x的父節點” 設為 “y”
示例:
2.右旋轉
右旋的動態圖與靜態圖如下所示:左邊為右旋前,右邊為旋轉后
右旋轉的偽代碼如下
RIGHT-ROTATE(T, y) 01 x ← left[y] // 前提:這里假設y的左孩子為x。下面開始正式操作 02 left[y] ← right[x] // 將 “x的右孩子” 設為 “y的左孩子”,即 將β設為y的左孩子 03 p[right[x]] ← y // 將 “y” 設為 “x的右孩子的父親”,即 將β的父親設為y 04 p[x] ← p[y] // 將 “y的父親” 設為 “x的父親” 05 if p[y] = nil[T] 06 then root[T] ← x // 情況1:如果 “y的父親” 是空節點,則將x設為根節點 07 else if y = right[p[y]] 08 then right[p[y]] ← x // 情況2:如果 y是它父節點的右孩子,則將x設為“y的父節點的左孩子” 09 else left[p[y]] ← x // 情況3:(y是它父節點的左孩子) 將x設為“y的父節點的左孩子” 10 right[x] ← y // 將 “y” 設為 “x的右孩子” 11 p[y] ← x // 將 “y的父節點” 設為 “x”
示例:
轉載小小城御園博主,現給出原文鏈接:https://blog.csdn.net/qq_37600027/article/details/84493443