關於紅黑樹(R-B tree)原理,看這篇如何

學過數據數據結構都知道二叉樹的概念,而又有多種比較常見的二叉樹類型,好比徹底二叉樹、滿二叉樹、二叉搜索樹、均衡二叉樹、完美二叉樹等;今天咱們要說的紅黑樹就是就是一顆非嚴格均衡的二叉樹,均衡二叉樹又是在二叉搜索樹的基礎上增長了自動維持平衡的性質,插入、搜索、刪除的效率都比較高。紅黑樹也是實現TreeMap存儲結構的基石。數據結構

一. 二叉搜索樹

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

  1. 節點的左子樹小於節點自己;
  2. 節點的右子樹大於節點自己;
  3. 左右子樹一樣爲二叉搜索樹;

下圖就是一顆典型的二叉搜索樹學習

二叉搜索樹是均衡二叉樹的基礎,咱們看一下它的搜索步驟如何blog

咱們要從二叉樹中找到值爲 58 的節點排序

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

第二步:比較咱們要找的值58與該節點的大小class

若是等於,那麼恭喜,已經找到;效率

若是小於,繼續找左子樹;基礎

若是大於,那麼找右子樹;原理

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

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

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

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

看到這樣的二叉搜索樹是否很彆扭,典型的大長腿瘸子,但它也是二叉搜索樹,若是咱們要找值爲50的節點,基本上和單鏈表查詢沒多大區別了,性能將大打折扣。這個時候咱們的均衡二叉樹就粉墨登場了,均衡二叉樹就是在二叉搜索樹的基礎上添加了自動維持平衡的性質。

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

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

二. 紅黑樹規則特色

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

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

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

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

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

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

  怎麼樣的路徑算最短路徑?

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

  什麼樣的路徑算是最長路徑?

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

第二. 爲何說新加入到紅黑樹中的節點爲紅色節點

  從規則4中知道,當前紅黑樹中從根節點到每一個葉子節點的黑色節點數量是同樣的,此時假如新的黑色節點的話,必然破壞規則,但加入紅色節點卻不必定,除非其父節點就是紅色節點,所以加入紅色節點,破壞規則的可能性小一些,下面咱們也會舉例來講明。

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

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

三. 紅黑樹節點插入

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

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

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

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

3.1 變色

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

  • 首先解決結構不遵循規則 4 這一點(紅色節點相連,節點49-51),需將節點49改成黑色;
  • 此時咱們發現又違反了規則5(56-49-51-XX路徑中黑色節點超過了其餘路徑),那麼咱們將節點45改成紅色節點;
  • 哈哈,妹的,又違反了規則4(紅色節點相連,節點56-45-43),那麼咱們將節點56和節點43改成黑色節點;
  • 可是咱們發現此時又違反了規則5(60-56-XX路徑的黑色節點比60-68-XX的黑色節點多),所以咱們須要調整節點68爲黑色;
  • 完成!!

最終調整完成後的樹爲:

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

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

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

這個時候,你會發現對於節點64不管是紅色節點仍是黑色節點,都會違反規則5,路徑中的黑色節點始終沒法達成一致,這個時候僅經過【變色】已經沒法達成目的。咱們須要經過旋轉操做,固然【旋轉】操做通常還須要搭配【變色】操做。

旋轉包括【左旋】和【右旋】,

左旋:

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

左旋操做步驟以下:

首先斷開節點PL與右子節點G的關係,同時將其右子節點的引用指向節點C2;而後斷開節點G與左子節點C2的關係,同時將G的左子節點的應用指向節點PL

右旋:

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

右旋操做步驟以下:

首先斷開節點G與左子節點PL的關係,同時將其左子節點的引用指向節點C2;而後斷開節點PL與右子節點C2的關係,同時將PL的右子節點的應用指向節點G

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

3.2 左左節點旋轉

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

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

按照規則,步驟以下:

3.3 左右節點旋轉

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

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

按照規則,步驟以下:

3.4 右左節點旋轉

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

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

按照規則,步驟以下:

3.5 右右節點旋轉

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

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

按照規則,步驟以下:

3.6 紅黑樹插入總結

無需調整 【變色】便可實現平衡 【旋轉+變色】纔可實現平衡
狀況1: 當父節點爲黑色時插入子節點 空樹插入根節點,將根節點紅色變爲黑色 父節點爲紅色左節點,叔父節點爲黑色,插入左子節點,那麼經過【左左節點旋轉】
狀況2: - 父節點和叔父節點都爲紅色 父節點爲紅色左節點,叔父節點爲黑色,插入右子節點,那麼經過【左右節點旋轉】
狀況3: - - 父節點爲紅色右節點,叔父節點爲黑色,插入左子節點,那麼經過【右左節點旋轉】
狀況4: - - 父節點爲紅色右節點,叔父節點爲黑色,插入右子節點,那麼經過【右右節點旋轉】

四. 紅黑樹節點刪除

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

4.1 子節點至少有一個爲null

當待刪除的節點的子節點至少有一個爲null節點時,刪除了該節點後,將其有值的節點取代當前節點便可,若都爲null,則將當前節點設置爲null,固然若是違反規則了,則按需調整,如【變色】以及【旋轉】。

4.2 子節點都是非null節點

這種狀況下,

第一步:找到該節點的前驅或者後繼

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

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

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

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

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

這至關因而一種「取巧」的方法,咱們刪除節點的目的是使該節點的值在紅黑樹上不存在,所以專一於該目的,咱們並不關注刪除節點時是否真是咱們想刪除的那個節點,同時咱們也不需考慮樹結構的變化,由於樹的結構自己就會由於自動平衡機制而常常進行調整。

前面咱們已經說了,咱們要刪除的其實是前驅或者後繼,所以咱們就之前驅爲主線來說解,後繼的學習可參考前驅,包括幾種狀況

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

分析:

由於要刪除的是左節點64,找到該節點的前驅63;

而後用前驅的值63替換待刪除節點的值64,此時兩個節點(待刪除節點和前驅)的值都爲63;

刪除前驅63,此時成爲上圖過程當中間環節,但咱們發現其不符合紅黑樹規則4,所以須要進行自動平衡調整;

這裏直接經過【變色】便可完成。

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

分析:

由於要刪除的是左節點64,找到該節點的前驅63;

而後用前驅的值63替換待刪除節點的值64,此時兩個節點(待刪除節點和前驅)的值都爲63;

刪除前驅63,此時成爲上圖過程當中間環節,但咱們發現其不符合紅黑樹規則5,所以須要進行自動平衡調整;

這裏直接經過【變色】便可完成。

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

分析:

由於要刪除的是左節點64,找到該節點的前驅63;

而後用前驅的值63替換待刪除節點的值64,此時兩個節點(待刪除節點和前驅)的值都爲63;

刪除前驅63,樹的結構並無打破規則。

4.3 紅黑樹刪除總結

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

刪除的是根節點,則直接將根節點置爲null;

待刪除節點的左右子節點都爲null,刪除時將該節點置爲null;

待刪除節點的左右子節點有一個有值,則用有值的節點替換該節點便可;

待刪除節點的左右子節點都不爲null,則找前驅或者後繼,將前驅或者後繼的值複製到該節點中,而後刪除前驅或者後繼;

節點刪除後可能會形成紅黑樹的不平衡,這時咱們需經過【變色】+【旋轉】的方式來調整,使之平衡,上面也給出了例子,建議你們多多練習,而沒必要背下來。

五. 總結

本文主要介紹了紅黑樹的相關原理,首先紅黑樹的基礎二叉搜索樹,咱們先簡單說了一下二叉搜索樹,而且講了一下搜索的流程,而後就針對紅黑樹的6大規則特色,紅黑樹的插入操做,刪除操做,都使用了大量的圖形來加以說明,技術都是練出來的,有時候不少似是而非的地方,當動筆去寫的時候,其實很好理解。紅黑樹的使用很是普遍,如TreeMap和TreeSet都是基於紅黑樹實現的,而Jdk8中HashMap當鏈表長度大於8時也會轉化爲紅黑樹,紅黑樹比較複雜,本人也是還在學習過程當中,若是有不對的地方請批評指正,望共同進步謝謝。

相關文章
相關標籤/搜索