史上最詳細的二叉樹、B樹,看不懂怨我

今天咱們要說的紅黑樹就是就是一棵非嚴格均衡的二叉樹,均衡二叉樹又是在二叉搜索樹的基礎上增長了自動維持平衡的性質,插入、搜索、刪除的效率都比較高。紅黑樹也是實現 TreeMap 存儲結構的基石。性能

1.二叉搜索樹

二叉搜索樹又叫二叉查找樹、二叉排序樹,咱們先看一下典型的二叉搜索樹,這樣的二叉樹有何規則特色呢?學習

二叉搜索樹有以下幾個特色:spa

  • 節點的左子樹小於節點自己
  • 節點的右子樹大於節點自己
  • 左右子樹一樣爲二叉搜索樹

下圖就是一棵典型的二叉搜索樹:3d

在這裏插入圖片描述在這裏插入圖片描述
二叉搜索樹是均衡二叉樹的基礎,咱們看一下它的搜索步驟如何。咱們要從二叉樹中找到值爲 58 的節點。blog

 

第一步:首先查找到根節點,值爲 60 的節點。排序

在這裏插入圖片描述在這裏插入圖片描述
第二步:比較咱們要找的值 58 與該節點的大小。教程

 

若是等於,那麼恭喜,已經找到;若是小於,繼續找左子樹;若是大於,那麼找右子樹。圖片

很明顯 58<60,所以咱們找到左子樹的節點 56,此時咱們已經定位到了節點 56。 資源

在這裏插入圖片描述在這裏插入圖片描述it

第三步:按照第二步的規則繼續找。

58>56 咱們須要繼續找右子樹,定位到了右子樹節點 58,恭喜,此時咱們已經找到了。

在這裏插入圖片描述在這裏插入圖片描述

咱們通過三步就已經找到了,其實就是咱們平時所說的二分查找,這種二叉搜索樹好像查找效率很高,但一樣它也有缺陷,以下面這樣的二叉搜索樹。

在這裏插入圖片描述在這裏插入圖片描述

看到這樣的二叉搜索樹是否很彆扭,典型的大長腿瘸子,但它也是二叉搜索樹,若是咱們要找值爲 50 的節點,基本上和單鏈表查詢沒多大區別了,性能將大打折扣。

這個時候咱們的均衡二叉樹就粉墨登場了,均衡二叉樹就是在二叉搜索樹的基礎上添加了自動維持平衡的性質。

上面的大長腿瘸子二叉搜索樹通過自動平衡後,可能就成爲了下面這樣的二叉樹。

在這裏插入圖片描述在這裏插入圖片描述

通過了自動平衡,再去找值爲 50 的節點,查找性能將提高不少。紅黑樹就是非嚴格均衡的二叉搜索樹。

2.紅黑樹規則特色

紅黑樹具體有哪些規則特色呢?具體以下:

**1. 節點分爲紅色或者黑色。

  1. 根節點必爲黑色。
  2. 葉子節點都爲黑色,且爲 null。
  3. 鏈接紅色節點的兩個子節點都爲黑色(紅黑樹不會出現相鄰的紅色節點)。
  4. 從任意節點出發,到其每一個葉子節點的路徑中包含相同數量的黑色節點。
  5. 新加入到紅黑樹的節點爲紅色節點。**

規則看着好像挺多,沒錯,由於紅黑樹也是均衡二叉樹,須要具有自動維持平衡的性質,上面的 6 條就是紅黑樹給出的自動維持平衡所須要具有的規則。

咱們看一看一個典型的紅黑樹究竟是什麼樣兒?

在這裏插入圖片描述在這裏插入圖片描述

首先解讀一下規則,除了字面上看到的意思,還隱藏了哪些意思呢?

①從根節點到葉子節點的最長路徑不大於最短路徑的 2 倍

怎麼樣的路徑算最短路徑?從規則 5 中,咱們知道從根節點到每一個葉子節點的黑色節點數量是同樣的,那麼純由黑色節點組成的路徑就是最短路徑。

什麼樣的路徑算是最長路徑?根據規則 4 和規則 3,如有紅色節點,則必然有一個鏈接的黑色節點,當紅色節點和黑色節點數量相同時,就是最長路徑,也就是黑色節點(或紅色節點)*2。

②爲何說新加入到紅黑樹中的節點爲紅色節點

從規則 4 中知道,當前紅黑樹中從根節點到每一個葉子節點的黑色節點數量是同樣的,此時假如新的是黑色節點的話,必然破壞規則。

但加入紅色節點卻不必定,除非其父節點就是紅色節點,所以加入紅色節點,破壞規則的可能性小一些,下面咱們也會舉例來講明。

什麼狀況下,紅黑樹的結構會被破壞呢?破壞後又怎麼維持平衡,維持平衡主要經過兩種方式【變色】和【旋轉】,【旋轉】又分【左旋】和【右旋】,兩種方式可相互結合。

下面咱們從插入和刪除兩種場景來舉例說明。

3.紅黑樹節點插入

當咱們插入值爲 66 的節點時,紅黑樹變成了這樣:

在這裏插入圖片描述在這裏插入圖片描述

很明顯,這個時候結構依然遵循着上述 6 大規則,無需啓動自動平衡機制調整節點平衡狀態。

若是再向裏面插入值爲 51 的節點,這個時候紅黑樹變成了這樣:

在這裏插入圖片描述在這裏插入圖片描述

很明顯如今的結構不遵循規則 4 了,這個時候就須要啓動自動平衡機制調整節點平衡狀態。

4.變色

咱們能夠經過變色的方式,使結構知足紅黑樹的規則:

**1. 首先解決結構不遵循規則 4 這一點(紅色節點相連,節點 49-51),需將節點 49 改成黑色。

  1. 此時咱們發現又違反了規則 5(56-49-51-XX 路徑中黑色節點超過了其餘路徑),那麼咱們將節點 45 改成紅色節點。
  2. 哈哈,妹的,又違反了規則 4(紅色節點相連,節點 56-45-43),那麼咱們將節點 56 和節點 43 改成黑色節點。
  3. 可是咱們發現此時又違反了規則 5(60-56-XX 路徑的黑色節點比 60-68-XX 的黑色節點多),所以咱們須要調整節點 68
    爲黑色。
  4. 完成!**

最終調整完成後的樹爲:

在這裏插入圖片描述在這裏插入圖片描述

但並非何時都那麼幸運,能夠直接經過變色就達成目的,大多數時候還須要經過旋轉來解決。

如在下面這棵樹的基礎上,加入節點 65:

在這裏插入圖片描述在這裏插入圖片描述

插入節點 65 後進行如下步驟:

在這裏插入圖片描述在這裏插入圖片描述

這個時候,你會發現對於節點 64 不管是紅色節點仍是黑色節點,都會違反規則 5,路徑中的黑色節點始終沒法達成一致,這個時候僅經過【變色】已經沒法達成目的。

咱們須要經過旋轉操做,固然【旋轉】操做通常還須要搭配【變色】操做。旋轉包括【左旋】和【右旋】。

左旋:逆時針旋轉兩個節點,讓一個節點被其右子節點取代,而該節點成爲右子節點的左子節點。

左旋操做步驟以下:首先斷開節點 PL 與右子節點 G 的關係,同時將其右子節點的引用指向節點 C2;而後斷開節點 G 與左子節點 C2 的關係,同時將 G 的左子節點的應用指向節點 PL。

在這裏插入圖片描述在這裏插入圖片描述

右旋:順時針旋轉兩個節點,讓一個節點被其左子節點取代,而該節點成爲左子節點的右子節點。

右旋操做步驟以下:首先斷開節點 G 與左子節點 PL 的關係,同時將其左子節點的引用指向節點 C2;而後斷開節點 PL 與右子節點 C2 的關係,同時將 PL 的右子節點的應用指向節點 G。

沒法經過變色而進行旋轉的場景分爲如下四種:

左左節點旋轉

這種狀況下,父節點和插入的節點都是左節點,以下圖(旋轉原始圖1)這種狀況下,咱們要插入節點 65。

規則以下:以祖父節點【右旋】,搭配【變色】。

在這裏插入圖片描述在這裏插入圖片描述

按照規則,步驟以下:

在這裏插入圖片描述在這裏插入圖片描述

左右節點旋轉

這種狀況下,父節點是左節點,插入的節點是右節點,在旋轉原始圖 1 中,咱們要插入節點 67。

規則以下:先父節點【左旋】,而後祖父節點【右旋】,搭配【變色】。

按照規則,步驟以下:

在這裏插入圖片描述在這裏插入圖片描述

右左節點旋轉

這種狀況下,父節點是右節點,插入的節點是左節點,以下圖(旋轉原始圖 2)這種狀況,咱們要插入節點 68。

規則以下:先父節點【右旋】,而後祖父節點【左旋】,搭配【變色】。

在這裏插入圖片描述在這裏插入圖片描述

按照規則,步驟以下:

在這裏插入圖片描述在這裏插入圖片描述

右右節點旋轉

這種狀況下,父節點和插入的節點都是右節點,在旋轉原始圖 2 中,咱們要插入節點 70。

規則以下:以祖父節點【左旋】,搭配【變色】。

按照規則,步驟以下:

在這裏插入圖片描述在這裏插入圖片描述

紅黑樹插入總結

紅黑樹插入總結:

在這裏插入圖片描述在這裏插入圖片描述

紅黑樹節點刪除

相比較於紅黑樹的節點插入,刪除節點更爲複雜,咱們從子節點是否爲 null 和紅色爲思考維度來討論。

子節點至少有一個爲 null

當待刪除的節點的子節點至少有一個爲 null 節點時,刪除了該節點後,將其有值的節點取代當前節點便可。

若都爲 null,則將當前節點設置爲 null,固然若是違反規則了,則按需調整,如【變色】以及【旋轉】。

在這裏插入圖片描述在這裏插入圖片描述

子節點都是非 null 節點

這種狀況下,第一步:找到該節點的前驅或者後繼。

前驅:左子樹中值最大的節點(可得出其最多隻有一個非 null 子節點,可能都爲 null)。

後繼:右子樹中值最小的節點(可得出其最多隻有一個非 null 子節點,可能都爲 null)。

前驅和後繼都是值最接近該節點值的節點,相似於該節點.prev=前驅,該節點.next=後繼。

第二步:將前驅或者後繼的值複製到該節點中,而後刪掉前驅或者後繼。

若是刪除的是左節點,則將前驅的值複製到該節點中,而後刪除前驅;若是刪除的是右節點,則將後繼的值複製到該節點中,而後刪除後繼。

這至關因而一種「取巧」的方法,咱們刪除節點的目的是使該節點的值在紅黑樹上不存在。

所以專一於該目的,咱們並不關注刪除節點時是否真是咱們想刪除的那個節點,同時咱們也不需考慮樹結構的變化,由於樹的結構自己就會由於自動平衡機制而常常進行調整。

前面咱們已經說了,咱們要刪除的其實是前驅或者後繼,所以咱們就之前驅爲主線來說解。

後繼的學習可參考前驅,包括下面幾種狀況:

①前驅爲黑色節點,而且有一個非 null 子節點

在這裏插入圖片描述在這裏插入圖片描述

分析:由於要刪除的是左節點 64,找到該節點的前驅 63;而後用前驅的值 63替換待刪除節點的值 64,此時兩個節點(待刪除節點和前驅)的值都爲 63;

刪除前驅 63,此時成爲上圖過程當中間環節,但咱們發現其不符合紅黑樹規則 4,所以須要進行自動平衡調整。這裏直接經過【變色】便可完成。

②前驅爲黑色節點,同時子節點都爲 null

在這裏插入圖片描述在這裏插入圖片描述

分析:由於要刪除的是左節點 64,找到該節點的前驅 63;而後用前驅的值 63 替換待刪除節點的值 64,此時兩個節點(待刪除節點和前驅)的值都爲 63。

刪除前驅 63,此時成爲上圖過程當中間環節,但咱們發現其不符合紅黑樹規則 5,所以須要進行自動平衡調整。這裏直接經過【變色】便可完成。

③前驅爲紅色節點,同時子節點都爲 null

在這裏插入圖片描述在這裏插入圖片描述

分析:由於要刪除的是左節點 64,找到該節點的前驅 63;而後用前驅的值 63替換待刪除節點的值 64,此時兩個節點(待刪除節點和前驅)的值都爲 63;刪除前驅 63,樹的結構並無打破規則。

紅黑樹刪除總結

紅黑樹刪除的狀況比較多,但也就存在如下狀況:

  1. 刪除的是根節點,則直接將根節點置爲 null。
  2. 待刪除節點的左右子節點都爲 null,刪除時將該節點置爲 null。
  3. 待刪除節點的左右子節點有一個有值,則用有值的節點替換該節點便可。
  4. 待刪除節點的左右子節點都不爲 null,則找前驅或者後繼,將前驅或者後繼的值複製到該節點中,而後刪除前驅或者後繼。
  5. 節點刪除後可能會形成紅黑樹的不平衡,這時咱們需經過【變色】+【旋轉】的方式來調整,使之平衡,上面也給出了例子,建議你們多多練習,而沒必要背下來。

總結

本文主要介紹了紅黑樹的相關原理,首先紅黑樹的基礎二叉搜索樹,咱們先簡單說了一下二叉搜索樹,而且講了一下搜索的流程。

而後就針對紅黑樹的六大規則特色,紅黑樹的插入操做,刪除操做,都使用了大量的圖形來加以說明。

技術都是練出來的,有時候不少似是而非的地方,當動筆去寫的時候,其實很好理解。

紅黑樹的使用很是普遍,如 TreeMap 和 TreeSet 都是基於紅黑樹實現的,而 JDK8 中 HashMap 當鏈表長度大於 8 時也會轉化爲紅黑樹。

更多資源和教程請關注公衆號:非科班的科班。
若是以爲我寫的還能夠請給個贊,謝謝你們,你的鼓勵是我創做的動力

相關文章
相關標籤/搜索