日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

红黑树的删除_Python实现红黑树的删除操作

發布時間:2024/9/30 python 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 红黑树的删除_Python实现红黑树的删除操作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上一篇文章使用Python實現了紅黑樹的插入操作。參考:Python實現紅黑樹的插入操作本篇文章使用Python實現紅黑樹的刪除操作。先將紅黑樹的5條特性列出來:1. 節點是紅色或黑色。2. 根節點是黑色。3. 所有葉子節點都是黑色的空節點。(葉子節點是NIL節點或NULL節點)4. 每個紅色節點的兩個子節點都是黑色節點。(從每個葉子節點到根的所有路徑上不能有兩個連續的紅色節點)5. 從任一節點到其每個葉子節點的所有路徑都包含相同數目的黑色節點。刪除操作是很復雜的,先把復雜的情況分解成各種情況,然后一種一種的解決。

一、代碼準備

在進行紅黑樹的刪除操作前,要先有一棵紅黑樹,所以這里使用上一篇文章中的代碼(文末附了完整代碼),先在紅黑樹中插入數據。1. 定義了一個節點類 RBNode ,用于創建新節點。

2. 定義了紅黑樹類 RBBinaryTree ,類中實現了按樹形結構打印紅黑樹的方法 show_tree(),并且根據紅黑樹的節點顏色,打印值時打印對應的顏色。還有二叉搜索樹的插入方法 insert(root, value) 和搜索方法 search(root, data) 。同時還有紅黑樹的插入方法 rb_insert(value),獲取后繼節點的get_min(root)方法,以及對紅黑樹進行調整的左旋方法left_rotate(node),右旋方法right_rotate(node)和變色方法change_color(node)。

二、實現紅黑樹的刪除方法

紅黑樹的刪除方法可以分兩個步驟實現,第一步是按照二叉搜索樹的方法將節點刪除,第二步是對刪除節點后的紅黑樹進行調整,使紅黑樹重新滿足5條特性。不過,在實際的代碼中,要將這兩個步驟倒過來,先對紅黑樹進行調整,然后刪除節點,因為刪除節點后,節點間的關系就“斷開”了,不方便進行調整。二叉搜索樹刪除節點,分為三種情況:1. 被刪除節點為葉節點,即被刪除節點沒有左子樹和右子樹。這種情況直接找到節點將其刪除。2. 被刪除節點有一棵子樹,這棵子樹可以是左子樹或右子樹。這種情況將節點刪除后,用節點的子樹替換被刪除節點的位置,進行“補位”。3. 被刪除節點有兩棵子樹,即被刪除節點同時有左子樹和右子樹。這種情況先找到被刪除節點的后繼節點,將后繼節點的值“轉移”到被刪除節點中,然后刪除后繼節點。而后繼節點一定屬于前兩種情況的其中之一。因此,對于紅黑樹的刪除,也是按這個思路。為了方便理解,先申明幾個需要使用到的術語:待刪除節點:需要被刪除的節點,因為調整放在刪除的前面,所以在進行調整時待刪除節點還在紅黑樹中,用D(delete_node)表示。因素節點:因為這個節點的變化,使紅黑樹的結構發生了變化,用F(factor_node)表示。在第一次進行調整時,因素節點就是待刪除節點,如果一次調整后進行遞歸調整,遞歸時的因素節點可能會發生改變。父節點:因素節點的父節點,用P(parent_node)表示。兄弟節點:因素節點的父節點的另一個子節點,用B(brother_node)表示。兄弟節點的左子節點:因素節點的兄弟節點的左子節點,用BL(brother_node.left_child)表示。兄弟節點的右子節點:因素節點的兄弟節點的右子節點,用BR(brother_node.right_child)表示。本文的所有結構圖中,藍色節點表示該節點可以是紅節點或黑節點,不影響調整步驟和平衡結果。

按照被刪除節點是否有子節點,分三種情況:1. 被刪除節點是葉節點(這里的葉節點不是指葉子節點NIL),葉節點沒有非空子節點。被刪除節點是葉節點時,根據被刪除節點的顏色,可以分為兩種情況。1.1 被刪除節點是紅節點,直接將節點刪除,不會破壞紅黑樹的5條特性,不需要進行調整。1.2 被刪除節點是黑節點。這是紅黑樹刪除中最復雜的部分,具體有如下三種情況。1.2.1 被刪除節點是根節點。直接將節點刪除,紅黑樹變成一棵空樹。1.2.2 被刪除節點是左子節點。根據兄弟節點的顏色,又可以分如下四種情況。1.2.2.1 兄弟節點是黑節點,并且兄弟節點的右子節點是紅節點。第一步將兄弟節點的顏色變成父節點的顏色,將父節點和兄弟節點的右子節點的顏色都設置成黑色。第二步以父節點作為旋轉節點進行左旋。調整完成,此時將待刪除節點從紅黑樹中刪除即可。

刪除節點后,黑節點減少(破壞了特性5),所以要找到一個紅節點變成黑節點,補充減少的黑色。這里相當于是“借用”了BR節點的紅色,變成黑色來補充損失的黑色。這種情況只要BR節點是紅色即可,不管BL節點是否存在和BL是什么顏色。如果BL節點為空,則調整過程與上圖一樣,沒有變化。如果BL節點是一個紅節點,即BL和BR都是紅節點,BL的加入不會對紅黑樹的特性產生影響,調整的過程如下圖所示。

如果BL節點是黑節點,調整方式也不變。因素節點是葉節點時,BL節點不可能是非空黑節點,因為在刪除節點前,紅黑樹是滿足5條特性的,因素節點和兄弟節點都是黑色,如果兄弟節點有黑色子節點,則因素節點也一定有黑色子節點,這與因素節點是葉節點矛盾。如果第一次調整后沒有達到平衡,將因素節點變成待刪除節點的父節點進行遞歸,因素節點不再是葉節點,這時可能會遇到BL節點是黑節點的情況,如后面的1.2.2.3調整后就可能變成這種情況。調整方式不變,并且經過此次調整后即可結束調整,調整過程如下圖(D的兄弟節點一開始是黑節點,上一次調整中變成了紅色)。

1.2.2.2 兄弟節點是黑節點,并且兄弟節點的左子節點是紅節點。第一步將兄弟節點變成紅色,將兄弟節點的左子節點變成黑色。第二步以兄弟節點作為旋轉節點進行右旋。這時二叉樹的結構變成了1.2.2.1的情況,第一次調整結束,因素節點不變,遞歸進行下一次調整。

刪除節點后,黑節點減少(破壞了特性5),這里相當于是“借用”了BL節點的紅色,變成黑色來補充損失的黑色。這種情況只要BL節點是紅色即可,不管BR節點是否存在和BR是什么顏色。如果BR節點為空,則調整過程與上圖一樣,沒有變化。如果BR節點是紅色,即BL和BR都是紅節點,則會直接按1.2.2.1進行處理。如果BR是黑節點,調整方式也不變。與上面的1.2.2.1一樣,因素節點是葉節點時,BR節點不可能是黑節點。在后面的1.2.2.3中,如果第一次調整后沒有達到平衡,將因素節點變成待刪除節點的父節點進行遞歸,因素節點不再是葉節點,這時可能會遇到BR節點是黑節點的情況,如后面的1.2.2.3調整后就可能變成這種情況。調整方式不變,調整過程如下圖(D的兄弟節點一開始是黑節點,上一次調整中變成了紅色)。

1.2.2.3 兄弟節點是黑節點,并且兄弟節點沒有子節點。第一步將兄弟節點變成紅色。第二步判斷父節點是不是紅節點。如果父節點是紅節點,直接將父節點變成黑節點,調整結束。如果父節點是黑節點,則將因素節點變為父節點,進行下一次遞歸調整,直到父節點是根節點。

刪除節點后,黑節點減少(破壞了特性5),這里相當于是“借用”了父節點的紅色,變成黑色來補充損失的黑色,如果父節點不是紅色,則由父節點去(父節點的BL、BR或P)“借”,如果一直遞歸到父節點是根節點,都沒地方可以“借”,則所有葉節點到根節點的路徑上黑節點都減一。在遞歸調整的過程中,可能會遇到1.2.2.1和1.2.2.2兩種情況以及后面的1.2.3.1和1.2.3.2兩種情況,也可能遇到BL和BR都是黑節點的情況。如果BL和BR都是黑節點,則繼續將兄弟節點變成紅色,將因素節點變為父節點,繼續遞歸下去,調整過程如下圖(D的兄弟節點一開始是黑節點,上一次調整中變成了紅色,第二次調整F變成了D的父節點,此時BL和BR都為黑色,則繼續將B變紅,遞歸處理)。

1.2.2.4 兄弟節點是紅節點。此時BL、BR和P一定都是黑節點,否則不滿特性4。

第一步將兄弟節點變成黑色,將父節點變成紅色。第二步以父節點作為旋轉節點進行左旋。這時二叉樹的結構變成了1.2.2.3的情況,第一次調整結束,因素節點不變,遞歸進行下一次調整。并且下一次調整中因素節點的父節點是紅節點,一定可以調整完成。

刪除節點后,黑節點減少(破壞了特性5),這里相當于是“借用”了兄弟節點的紅色,變成黑色來補充損失的黑色。1.2.3 被刪除節點是右子節點。這與被刪除節點是左節點的情況互為鏡像,原理也一樣,根據兄弟節點的顏色,分如下四種情況。1.2.3.1 兄弟節點是黑節點,并且兄弟節點的左子節點是紅節點。第一步將兄弟節點的顏色變成父節點的顏色,將父節點和兄弟節點的左子節點的顏色都設置成黑色。第二步以父節點作為旋轉節點進行右旋。調整完成,此時將待刪除節點從紅黑樹中刪除即可。

與被刪除節點是左子節點的原理一樣,只要BL是紅節點即可,不用關注是否有BR節點和BR是什么顏色,處理方式都一樣,這里就不展開了。1.2.3.2 兄弟節點是黑節點,并且兄弟節點的右子節點是紅節點。第一步將兄弟節點變成紅色,將兄弟節點的右子節點變成黑色。第二步以兄弟節點作為旋轉節點進行左旋。這時二叉樹的結構變成了1.2.3.1的情況,第一次調整結束,因素節點不變,遞歸進行下一次調整。

與被刪除節點是左子節點一樣,只要BR是紅節點即可,不用關注是否有BL節點和BL是什么顏色,處理方式都一樣。1.2.3.3 兄弟節點是黑節點,并且兄弟節點沒有子節點。第一步將兄弟節點變成紅色。第二步判斷父節點是不是紅節點。如果父節點是紅節點,直接將父節點變成黑節點,調整結束。如果父節點是黑節點,則將因素節點變為父節點,進行下一次遞歸調整,直到父節點是根節點。

在遞歸調整的過程中,可能會遇到1.2.3.1和1.2.3.2兩種情況以及前面的1.2.2.1和1.2.2.2兩種情況,也可能遇到BL和BR都是黑節點的情況。如果BL和BR都是黑節點,則繼續將兄弟節點變成紅色,將因素節點變為父節點,繼續遞歸下去。1.2.3.4 兄弟節點是紅節點。此時BL、BR和P一定都是黑節點,否則不滿特性4。

第一步將兄弟節點變成黑色,將父節點變成紅色。第二步以父節點作為旋轉節點進行右旋。這時二叉樹的結構變成了1.2.3.3的情況,第一次調整結束,因素節點不變,遞歸進行下一次調整。并且下一次調整中因素節點的父節點是紅節點,一定可以調整完成。

到這里,待刪除節點是葉節點的所有情況都分析完成了,代碼實現如下。 def _rb_delete_no_child(self, node): """紅黑樹刪除兩個子節點都為空的節點""" if node == self.root: self.root = None self.root.color = 'black' return factor_node = node # 如果待刪除節點為黑節點則需要進行調整 if factor_node.color is 'black': while True: parent_node = factor_node.parent brother_node = parent_node.right_child if factor_node is parent_node.left_child else parent_node.left_child # 待刪除節點是左子節點 if factor_node is parent_node.left_child: # 如果兄弟節點是黑節點 if brother_node.color is 'black': # 如果兄弟節點沒有子節點(遞歸處理時如果兄弟節點的兩個子節點都是黑節點) if brother_node.left_child is None and brother_node.right_child is None or \ ((brother_node.left_child and brother_node.left_child.color is 'black') and (brother_node.right_child and brother_node.right_child.color is 'black')): self.change_color(brother_node) if parent_node.color is 'red': self.change_color(parent_node) break else: if parent_node == self.root: break factor_node = parent_node # 如果兄弟節點有右子節點,此右節點一定是紅節點(遞歸處理時,如果兄弟節點的右子節點為紅節點) elif brother_node.right_child is not None and brother_node.right_child.color is 'red': brother_node.color = parent_node.color parent_node.color, brother_node.right_child.color = 'black', 'black' self.left_rotate(parent_node) break # 如果兄弟節點有左節點,此左節點一定是紅節點(遞歸處理時,如果兄弟節點的左子節點為紅節點) else: brother_node.color, brother_node.left_child.color = 'red', 'black' self.right_rotate(brother_node) # 如果兄弟節點是紅節點 elif brother_node.color is 'red': self.change_color(parent_node) self.change_color(brother_node) self.left_rotate(parent_node) # 待刪除節點是右子節點 if factor_node is parent_node.right_child: if brother_node.color is 'black': # 如果兄弟節點沒有子節點(遞歸處理時如果兄弟節點的兩個子節點都是黑節點) if brother_node.left_child is None and brother_node.right_child is None or \ ((brother_node.left_child and brother_node.left_child.color is 'black') and (brother_node.right_child and brother_node.right_child.color is 'black')): self.change_color(brother_node) if parent_node.color is 'red': self.change_color(parent_node) break else: if parent_node == self.root: break factor_node = parent_node # 如果兄弟節點有左節點,此左節點一定是紅節點(遞歸處理時,如果兄弟節點的左子節點為紅節點) elif brother_node.left_child is not None and brother_node.left_child.color is 'red': brother_node.color = parent_node.color parent_node.color, brother_node.left_child.color = 'black', 'black' self.right_rotate(parent_node) break # 如果兄弟節點有右節點,此右節點一定是紅節點(遞歸處理時,如果兄弟節點的右子節點為紅節點) else: brother_node.color, brother_node.right_child.color = 'red', 'black' self.left_rotate(brother_node) # 如果兄弟節點是紅節點 elif brother_node.color is 'red': self.change_color(parent_node) self.change_color(brother_node) self.right_rotate(parent_node) if node is node.parent.left_child: node.parent.left_child = None else: node.parent.right_child = None node.parent = None_rb_delete_no_child(node): 紅黑樹刪除葉節點的方法。刪除葉節點后的調整是三種情況中最復雜的一種,要先理解每一種情況的調整方法,以及遞歸處理時可能會變成哪些情況。代碼是按照上面的分析過程實現的,需要仔細分析并理解。2. 被刪除節點有一個子節點。被刪除節點要么有左子節點沒有右子節點,要么沒有左子節點有右子節點。這種情況的處理比較簡單,因為在刪除前,紅黑樹滿足5條特性,所以不管子節點是左子節點還是右子節點,這個子節點一定是紅節點,否則不滿足特性5,進一步可以得出被刪除節點一定是黑節點,否則不滿足特性4。刪除比較簡單,第一步將待刪除節點的子節點變成黑色,第二步按照二叉搜索樹的方法將待刪除節點刪除,即用子節點補位到待刪除節點的位置。

在這個過程中,不用區分待刪除節點的子節點是左子節點還是右子節點,也不用區分待刪除節點是其父節點的左子節點還是右子節點,或者待刪除節點是不是根節點。處理方式都一樣,將其子節點變黑補位即可,代碼如下。 def _rb_delete_one_child(self, node): """紅黑樹刪除有一個子節點的節點""" if node.left_child: self.change_color(node.left_child) if node.parent and node.parent.left_child == node: node.left_child.parent, node.parent.left_child = node.parent, node.left_child elif node.parent and node.parent.right_child == node: node.left_child.parent, node.parent.right_child = node.parent, node.left_child else: self.root = node.left_child node.left_child.parent, node.left_child = None, None elif node.right_child: self.change_color(node.right_child) if node.parent and node.parent.left_child == node: node.right_child.parent, node.parent.left_child = node.parent, node.right_child elif node.parent and node.parent.right_child == node: node.right_child.parent, node.parent.right_child = node.parent, node.right_child else: self.root = node.right_child node.right_child.parent, node.right_child = None, None node.parent = None_rb_delete_one_child(self, node): 紅黑樹刪除只有一個子節點的節點。這種情況的處理很簡單,代碼也比較簡單。3. 被刪除節點有兩個子節點,即被刪除節點同時有左子節點和右子節點。根據二叉搜索樹的刪除方法,這種情況需要找到被刪除節點的前繼節點或后繼節點,本文中使用后繼節點,用后繼節點的值替換被刪除節點的值,避免樹的“斷裂”,然后將后繼節點刪除。后繼節點是不可能有左子節點的,因此后繼節點要么沒有子節點,要么有一個右子節點,處理方法可以分為兩種。3.1 后繼節點沒有子節點。這時調用上面的情況1,將后繼節點刪除。3.2 后繼節點有一個右子節點。后繼節點一定是黑節點,后繼節點的右子節點一定是紅節點,調用上面的情況2,將后繼節點刪除。代碼實現如下。 def _rb_delete(self, node): """刪除節點的三種情況""" if node.left_child is None and node.right_child is None: self._rb_delete_no_child(node) elif node.left_child and not node.right_child or not node.left_child and node.right_child: self._rb_delete_one_child(node) else: rear_node = self.get_min(node.right_child) node.data = rear_node.data self._rb_delete(rear_node)刪除節點,首先這個節點要在紅黑樹中,因此不能創建一個節點然后刪除,而是根據節點的值,先到紅黑樹中進行搜索,如果這個值存在紅黑樹中,則將其刪除。(本文中的紅黑樹不會添加重復的值,這個可以按需進行修改)

最后,紅黑樹的刪除方法如下。

def rb_delete(self, value): """紅黑樹刪除""" if not self.is_empty(): node_delete = self.search(self.root, value) if node_delete: self._rb_delete(node_delete) else: raise KeyError("Error, {value} not in this tree".format(value=value)) else: raise KeyError("Error, tree is empty")rb_delete(value): 紅黑樹的刪除方法。總結,紅黑樹的刪除中,被刪除節點是葉節點時最復雜,需要仔細分析每一種情況。當被刪除節點是黑節點時,會破壞特性5,經過被刪除節點的路徑上黑節點少了一個,所以要找一個紅節點變成黑色來補充,每一種情況分別是去BL、BR或P“借”,如果沒有紅節點可以“借”,則讓父節點去“借”,一直到父節點變成根節點都沒有紅節點可以“借”,則所有路徑上的黑節點都減一,從而保持平衡。被刪除節點有一個子節點時比較簡單,將子節點變黑補位即可。被刪除節點有兩個子節點時,可以將被刪除節點轉換成后繼節點,從而變成前兩種情況進行處理。

三、紅黑樹刪除方法的驗證

1. 先插入數據到紅黑樹中,如還是用之前的數據[50, 77, 55, 29, 10, 30, 66, 18, 80, 51, 90]。if __name__ == '__main__': tree = RBBinaryTree() data = [50, 77, 55, 29, 10, 30, 66, 18, 80, 51, 90] for i in data: tree.rb_insert(i) tree.show_tree()運行結果:

插入數據后紅黑樹的結構如下圖。

現在刪除其中的一個節點,如刪除節點66。 tree.rb_delete(66) tree.show_tree()運行結果:

刪除節點66后紅黑樹的結構如下圖。

可以看到,紅黑樹的刪除功能已經實現了。不過,由于數據比較少,沒有包含刪除的每一種情況,本文中也不可能每種情況都進行驗證,并且數據量大時,也不方便畫出紅黑樹的結構圖。所以,有必要實現一個方法來對紅黑樹進行自查,判斷當前紅黑樹是否滿足5條特性。 def rb_check(self): """檢查紅黑樹是否滿足5條特性""" if self.is_empty(): print("空樹") return queue = list() queue.insert(0, self.root) height = 0 while len(queue): node = queue.pop() if node.color is not "red" and node.color is not "black": raise Exception("節點{}不滿足特性1".format(node.data)) if node is self.root and node.color is not "black": raise Exception("節點{}不滿足特性2".format(node.data)) if node.color is "red" and (node.left_child and node.left_child.color is "red" or node.right_child and node.right_child.color is "red"): raise Exception("節點{}不滿足特性4".format(node.data)) if node.left_child is None and node.right_child is None: path = 0 cur = node while cur: if cur.color is "black": path += 1 cur = cur.parent if height and path != height: raise Exception("節點{}不滿足特性5".format(node.data)) else: height = path if node.left_child is not None: queue.insert(0, node.left_child) if node.right_child is not None: queue.insert(0, node.right_child) print("滿足紅黑樹的5條特性,葉子節點到根節點的非空黑節點個數為{}".format(height))rb_check(): 對當前紅黑樹進行判斷,如果不滿足5條特性中的一條,則拋出異常。此方法對紅黑樹的所有節點進行層序遍歷,依次對每一個節點判斷是否滿足紅黑樹的特性。下面添加一棵有1000個節點的紅黑樹,進行驗證。 data = range(1000) for i in data: tree.rb_insert(i) tree.rb_check() tree.rb_delete(66) print("--- after delete ---") tree.rb_check()運行結果:滿足紅黑樹的5條特性,葉子節點到根節點的非空黑節點個數為9--- after delete ---滿足紅黑樹的5條特性,葉子節點到根節點的非空黑節點個數為9代碼附在后面,更多情況請自行取用驗證。(部分代碼是可以精簡的,不過為了保證可讀性和方便與分析過程對照,這樣更好一點)四、完整代碼# coding=utf-8class RBNode(object): """節點類""" def __init__(self, data, left_child=None, right_child=None, color='red'): self.data = data self.parent = None self.left_child = left_child self.right_child = right_child self.color = colorclass RBBinaryTree(object): """紅黑樹類""" def __init__(self): self.__root = None self.prefix_branch = '├' self.prefix_trunk = '|' self.prefix_leaf = '└' self.prefix_empty = '' self.prefix_left = '─L─' self.prefix_right = '─R─' def is_empty(self): return not self.__root @property def root(self): return self.__root @root.setter def root(self, value): self.__root = value if isinstance(value, RBNode) else RBNode(value) def left_rotate(self, node): """紅黑樹左旋""" parent_node, right_node = node.parent, node.right_child if not right_node: return # 1.node是旋轉節點,將旋轉節點的右子節點的左子節點變為旋轉節點的右子節點 node.right_child = right_node.left_child if node.right_child: node.right_child.parent = node # 2.將旋轉節點修改為右子節點的左子節點 right_node.left_child, node.parent = node, right_node # 3.將右子節點替換旋轉節點的位置,作為旋轉節點父節點的子節點 if not parent_node: self.root = right_node else: if parent_node.left_child == node: parent_node.left_child = right_node else: parent_node.right_child = right_node right_node.parent = parent_node def right_rotate(self, node): """紅黑樹右旋""" parent_node, left_node = node.parent, node.left_child if not left_node: return # 1.node是旋轉節點,將旋轉節點的左子節點的右子節點變為旋轉節點的左子節點 node.left_child = left_node.right_child if node.left_child: node.left_child.parent = node # 2.將旋轉節點修改為左子節點的右子節點 left_node.right_child, node.parent = node, left_node # 3.將左子節點替換旋轉節點的位置,作為旋轉節點父節點的子節點 if not parent_node: self.root = left_node else: if parent_node.left_child == node: parent_node.left_child = left_node else: parent_node.right_child = left_node left_node.parent = parent_node def change_color(self, node): """紅黑樹變色""" if node.color is 'red': node.color = 'black' elif node.color is 'black': node.color = 'red' def rb_insert(self, value): """紅黑樹插入""" node = value if isinstance(value, RBNode) else RBNode(value) if self.search(self.root, node.data): return if self.is_empty(): node.color = 'black' self.root = node return self.insert(self.root, node) factor_node = node while True: parent_node = factor_node.parent if parent_node.color is 'red': grandparent_node = parent_node.parent if parent_node is grandparent_node.left_child: uncle_node = grandparent_node.right_child else: uncle_node = grandparent_node.left_child # 如果父節點為紅節點且叔節點為黑節點 if uncle_node is None or uncle_node and uncle_node.color is 'black': if parent_node == grandparent_node.left_child: # 先左旋為左左結果,然后父節點和祖父節點變色,再右旋 if factor_node == parent_node.right_child: self.left_rotate(parent_node) self.change_color(factor_node) else: self.change_color(parent_node) self.change_color(grandparent_node) self.right_rotate(grandparent_node) elif parent_node == grandparent_node.right_child: # 先右旋為右右結構,然后父節點和祖父節點變色,再左旋 if factor_node == parent_node.left_child: self.right_rotate(parent_node) self.change_color(factor_node) else: self.change_color(parent_node) self.change_color(grandparent_node) self.left_rotate(grandparent_node) break # 如果父節點為紅節點且叔節點也為紅節點 elif uncle_node and uncle_node.color is 'red': # 父節點和叔節點變色,祖父節點變色(祖父節點是根節點除外) self.change_color(parent_node) self.change_color(uncle_node) if grandparent_node != self.root: self.change_color(grandparent_node) # 祖父節點變成紅節點后,將祖父節點作為新的因素節點,判斷其父節點,避免不滿足特性4 factor_node = grandparent_node else: break def insert(self, root, value): """二叉搜索樹插入節點-遞歸""" node = value if isinstance(value, RBNode) else RBNode(value) if self.is_empty(): self.root = node return if root is None: root = node elif node.data < root.data: root.left_child = self.insert(root.left_child, value) root.left_child.parent = root elif node.data > root.data: root.right_child = self.insert(root.right_child, value) root.right_child.parent = root return root def rb_delete(self, value): """紅黑樹刪除""" if not self.is_empty(): node_delete = self.search(self.root, value) if node_delete: self._rb_delete(node_delete) else: raise KeyError("Error, {value} not in this tree".format(value=value)) else: raise KeyError("Error, tree is empty") def _rb_delete(self, node): """刪除節點的三種情況""" if node.left_child is None and node.right_child is None: self._rb_delete_no_child(node) elif node.left_child and not node.right_child or not node.left_child and node.right_child: self._rb_delete_one_child(node) else: rear_node = self.get_min(node.right_child) node.data = rear_node.data self._rb_delete(rear_node) def _rb_delete_no_child(self, node): """紅黑樹刪除兩個子節點都為空的節點""" if node == self.root: self.root = None self.root.color = 'black' return factor_node = node # 如果待刪除節點為黑節點則需要進行調整 if factor_node.color is 'black': while True: parent_node = factor_node.parent brother_node = parent_node.right_child if factor_node is parent_node.left_child else parent_node.left_child # 待刪除節點是左子節點 if factor_node is parent_node.left_child: # 如果兄弟節點是黑節點 if brother_node.color is 'black': # 如果兄弟節點沒有子節點(遞歸處理時如果兄弟節點的兩個子節點都是黑節點) if brother_node.left_child is None and brother_node.right_child is None or \ ((brother_node.left_child and brother_node.left_child.color is 'black') and (brother_node.right_child and brother_node.right_child.color is 'black')): self.change_color(brother_node) if parent_node.color is 'red': self.change_color(parent_node) break else: if parent_node == self.root: break factor_node = parent_node # 如果兄弟節點有右子節點,此右節點一定是紅節點(遞歸處理時,如果兄弟節點的右子節點為紅節點) elif brother_node.right_child is not None and brother_node.right_child.color is 'red': brother_node.color = parent_node.color parent_node.color, brother_node.right_child.color = 'black', 'black' self.left_rotate(parent_node) break # 如果兄弟節點有左節點,此左節點一定是紅節點(遞歸處理時,如果兄弟節點的左子節點為紅節點) else: brother_node.color, brother_node.left_child.color = 'red', 'black' self.right_rotate(brother_node) # 如果兄弟節點是紅節點 elif brother_node.color is 'red': self.change_color(parent_node) self.change_color(brother_node) self.left_rotate(parent_node) # 待刪除節點是右子節點 if factor_node is parent_node.right_child: if brother_node.color is 'black': # 如果兄弟節點沒有子節點(遞歸處理時如果兄弟節點的兩個子節點都是黑節點) if brother_node.left_child is None and brother_node.right_child is None or \ ((brother_node.left_child and brother_node.left_child.color is 'black') and (brother_node.right_child and brother_node.right_child.color is 'black')): self.change_color(brother_node) if parent_node.color is 'red': self.change_color(parent_node) break else: if parent_node == self.root: break factor_node = parent_node # 如果兄弟節點有左節點,此左節點一定是紅節點(遞歸處理時,如果兄弟節點的左子節點為紅節點) elif brother_node.left_child is not None and brother_node.left_child.color is 'red': brother_node.color = parent_node.color parent_node.color, brother_node.left_child.color = 'black', 'black' self.right_rotate(parent_node) break # 如果兄弟節點有右節點,此右節點一定是紅節點(遞歸處理時,如果兄弟節點的右子節點為紅節點) else: brother_node.color, brother_node.right_child.color = 'red', 'black' self.left_rotate(brother_node) # 如果兄弟節點是紅節點 elif brother_node.color is 'red': self.change_color(parent_node) self.change_color(brother_node) self.right_rotate(parent_node) if node is node.parent.left_child: node.parent.left_child = None else: node.parent.right_child = None node.parent = None def _rb_delete_one_child(self, node): """紅黑樹刪除有一個子節點的節點""" if node.left_child: self.change_color(node.left_child) if node.parent and node.parent.left_child == node: node.left_child.parent, node.parent.left_child = node.parent, node.left_child elif node.parent and node.parent.right_child == node: node.left_child.parent, node.parent.right_child = node.parent, node.left_child else: self.root = node.left_child node.left_child.parent, node.left_child = None, None elif node.right_child: self.change_color(node.right_child) if node.parent and node.parent.left_child == node: node.right_child.parent, node.parent.left_child = node.parent, node.right_child elif node.parent and node.parent.right_child == node: node.right_child.parent, node.parent.right_child = node.parent, node.right_child else: self.root = node.right_child node.right_child.parent, node.right_child = None, None node.parent = None def rb_check(self): """檢查紅黑樹是否滿足5條特性""" if self.is_empty(): print("空樹") return queue = list() queue.insert(0, self.root) height = 0 while len(queue): node = queue.pop() if node.color is not "red" and node.color is not "black": raise Exception("節點{}不滿足特性1".format(node.data)) if node is self.root and node.color is not "black": raise Exception("節點{}不滿足特性2".format(node.data)) if node.color is "red" and (node.left_child and node.left_child.color is "red" or node.right_child and node.right_child.color is "red"): raise Exception("節點{}不滿足特性4".format(node.data)) if node.left_child is None and node.right_child is None: path = 0 cur = node while cur: if cur.color is "black": path += 1 cur = cur.parent if height and path != height: raise Exception("節點{}不滿足特性5".format(node.data)) else: height = path if node.left_child is not None: queue.insert(0, node.left_child) if node.right_child is not None: queue.insert(0, node.right_child) print("滿足紅黑樹的5條特性,葉子節點到根節點的非空黑節點個數為{}".format(height)) def search(self, root, data): """二叉搜索樹的查詢操作""" if root is None: return if root.data == data: return root elif data < root.data: return self.search(root.left_child, data) elif data > root.data: return self.search(root.right_child, data) def get_min(self, root): """查找二叉搜索樹值最小的節點""" if self.is_empty(): return return self.get_min(root.left_child) if root.left_child else root def show_tree(self): if self.is_empty(): print('空二叉樹') return print('-' * 20) print("\033[31m{}\033[0m".format(str(self.root.data))) if self.root.color is 'red' else print(str(self.root.data)) self.__print_tree(self.__root) print('-' * 20) def __print_tree(self, node, prefix=None): if prefix is None: prefix, prefix_left_child = '', '' else: prefix = prefix.replace(self.prefix_branch, self.prefix_trunk).replace(self.prefix_leaf, self.prefix_empty) prefix_left_child = prefix.replace(self.prefix_leaf, self.prefix_empty) if self.has_child(node): if node.right_child is not None: if node.right_child.color is 'red': print(prefix + self.prefix_branch + self.prefix_right + "\033[31m{}\033[0m".format(str(node.right_child.data))) else: print(prefix + self.prefix_branch + self.prefix_right + str(node.right_child.data)) if self.has_child(node.right_child): self.__print_tree(node.right_child, prefix + self.prefix_branch + ' ') else: print(prefix + self.prefix_branch + self.prefix_right) if node.left_child is not None: if node.left_child.color is 'red': print(prefix + self.prefix_leaf + self.prefix_left + "\033[31m{}\033[0m".format(str(node.left_child.data))) else: print(prefix + self.prefix_leaf + self.prefix_left + str(node.left_child.data)) if self.has_child(node.left_child): prefix_left_child += ' ' self.__print_tree(node.left_child, self.prefix_leaf + prefix_left_child) else: print(prefix + self.prefix_leaf + self.prefix_left) def has_child(self, node): return node.left_child is not None or node.right_child is not Noneif __name__ == '__main__': tree = RBBinaryTree() # data = [50, 77, 55, 29, 10, 30, 66, 18, 80, 51, 90] # for i in data: # tree.rb_insert(i) # # tree.show_tree() # # tree.rb_delete(66) # tree.show_tree() data = range(1000) for i in data: tree.rb_insert(i) tree.rb_check() tree.rb_delete(66) print("--- after delete ---") tree.rb_check()

總結

以上是生活随笔為你收集整理的红黑树的删除_Python实现红黑树的删除操作的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲精品999 | 最近中文字幕第一页 | 久免费一级suv好看的国产 | 国产精品久久久久久久久免费桃花 | 色屁屁一区二区三区视频 | 精品国产乱码久久久久久88av | 国产精品麻豆欧美日韩ww | 在线观看成人一区 | 老熟妇午夜毛片一区二区三区 | av黄色在线观看 | av免费高清 | a黄色一级片 | 中文文字幕一区二区三三 | 久久久精品日韩 | 国产永久av | 国产一区二区网址 | 韩国一级淫一片免费放 | eeuss日韩 | 波多野结衣女同 | 欧美一区二区三区色 | www.超碰97 | 国内毛片毛片 | 91精选视频 | 日韩精品在线视频 | 日韩欧| 日本三级精品 | 欧美日韩精品一区二区三区四区 | 国产三级精品在线 | 国产97自拍 | 亚洲精品国产成人久久av盗摄 | 国产寡妇亲子伦一区二区三区四区 | 污污的网站在线观看 | 美国美女群体交乱 | 国v精品久久久网 | 午夜寂寞剧场 | 天天插天天狠 | 在线看亚洲 | 日韩欧美一区二区在线观看 | japanesehdxxxx | 国产视频污| 婷婷精品视频 | 超碰在线伊人 | 中国丰满老妇xxxxx交性 | 国内自拍青青草 | 国产一级片麻豆 | 久色资源 | 男女啪啪av | 天堂va在线 | 国产91在线高潮白浆在线观看 | 四虎影成人精品a片 | 中文字幕2021| 久草福利在线视频 | 中文字幕区 | 午夜免费一级片 | 欧美69久成人做爰视频 | 日韩久久久久久 | av三级网站 | 婷婷综合| 国产男女在线 | 日韩视频在线观看视频 | 最新av在线播放 | 侵犯女教师一区二区三区 | 精品一区久久久 | 日韩精品在线观看一区 | 国产青草 | 国产成人aaa | 国产日韩欧美综合在线 | 91精品国产综合久久久久 | 成年人视频免费 | 国产人妻精品一区二区三区不卡 | 91蜜桃臀久久一区二区 | 他揉捏她两乳不停呻吟动态图 | 污污的网站在线免费观看 | a毛片大片 | 女生扒开尿口给男生捅 | 日韩精品大片 | 图书馆的女友动漫在线观看 | 国产乱淫精品一区二区三区毛片 | 欧美老熟妇乱大交xxxxx | 欧美性猛交xx | 精品国产午夜福利 | 国产又爽又黄的视频 | 熟睡侵犯の奶水授乳在线 | 91喷水 | 韩国三级bd高清中字2021 | 日韩av在线免费播放 | av网站黄色| 草比网站 | 免费毛片看片 | 奇米第四色777 | 亚洲天天 | 欧美一级啪啪 | 中文字幕一区二区人妻视频 | 最新在线视频 | 日韩一级黄色录像 | 能直接看的av网站 | 国产黄色一区二区 | 国产精品高清网站 | 性视频网|