1. 程式人生 > 實用技巧 >紅黑樹鍵值對 -- TreeMp

紅黑樹鍵值對 -- TreeMp

一:概述

Collection系列的List與Set實現都只能儲存單個元素,想要使用 key – value 的結構就需要使用到Map。整體來說Map的實現結構並不複雜,三個具體實現類TreeMap、HashMap、LinkedHashMap,分別採用紅黑樹、雜湊表、連結串列 + 雜湊表的結構實現。本文將講解採用紅黑樹實現的TreeMap,紅黑樹結構註定這將是一個元素擁有一定比較順序的集合

二:繼承結構

在這裡插入圖片描述

三:紅黑樹實現

在這裡插入圖片描述
靜態內部類Entry其實就是紅黑樹的節點類。key、value屬性記錄節點值,left、right、parent分別記錄左右節點與父節點,color則記錄節點顏色,紅與黑。說到這裡如果不瞭解紅黑樹的請自行查閱相關書籍,演算法導論就不錯嘛。基礎有以下幾點特徵:

  • 根節點必須是黑色
  • 紅節點上下必須是黑色,也就是它的父親與兒子
  • 任意節點通過任意路徑到葉子節點中黑節點的累計數量相等

四:比較器

在這裡插入圖片描述
看一下TreeMap類的屬性發現除了root維護紅黑樹根節點之外還有一個比較器comparator,這個比較器自然就是定義節點元素大小規則的比較器。在元素節點插入的時候會使用

4.1 構造注入

在這裡插入圖片描述
例項化物件的時候可以傳遞Comparator型別比較器,這時就會將其賦值給屬性comparator。注意泛型限制的咯,這個K是TreeMap中key鍵的泛型,比較器要求是其父類亦或是自身,滿足里氏替換原則設計要求

4.2 預設比較器

在這裡插入圖片描述
如果是無參構造那就比較慘烈了,比較器就是一個null。那麼元素節點新增的時候就不用了麼?預設的比較器肯定是存在的嘛,看看下圖

在這裡插入圖片描述
這個比較方法就是在需要使用到比較器呼叫的比較方法,三目表示式規定如果有比較器就用,沒有就用key值呼叫compareTo()。所以,敲黑板咯,儲存到TreeMap的元素要麼提供Compartator比較器,要麼自身實現Comparable介面。不然這個強轉可以錯的一塌糊塗

五:紅黑樹左右旋轉

在涉及到節點新增或刪除的時候就有可能導致紅黑樹特徵被破壞,這時候就需要調整紅黑樹重新形成紅黑樹特徵結構。要麼選擇改變節點顏色,要麼選擇紅黑樹結構調整。左右旋就是紅黑樹結構調整中基礎的兩個方法

5.1 紅黑樹左旋

在這裡插入圖片描述
紅黑樹的左旋其實就是以旋轉節點為中心的逆時針順序旋轉,最後效果如上圖所示。總結起來就兩點:

1、旋轉節點右節點成為其父節點
2、 右節點的左節點給旋轉節點做右節點

以下就是模擬TreeMap進行左旋轉的程式碼:
在這裡插入圖片描述
在這裡插入圖片描述

5.2 紅黑樹右旋

在這裡插入圖片描述
紅黑樹的右旋其實就是以旋轉節點為中心的順時針順序旋轉,最後效果如上圖所示。總結起來就兩點:
1、旋轉節點左節點成為其父節點
2、左節點的右節點給旋轉節點做左節點

以下就是模擬TreeMap進行右旋轉的程式碼:
在這裡插入圖片描述

六:新增節點

6.1 節點新增

在這裡插入圖片描述
根節點等於null不就是說沒有節點麼,這是開張第一位客官,直接例項化節點Entry後將其賦值給root屬性即可。compare()方法上面講過,其實在這裡的目的就是判斷你是不是既沒傳Comparator比較器,儲存元素又沒有實現Comparable介面,真這樣就報錯的咯

在這裡插入圖片描述
cpr不等於空就是說你傳了比較器,do while操作嘛,反正這個過程你要麼找到一樣的key取而代之返回,要麼你就老老實實找到最後一個葉子結點當爹
在這裡插入圖片描述
沒傳比較器的時候compara()方法會有一次強轉,長痛不如短痛。key值為null直接給你幹一個異常就OK結束即可。如果不是null就還是老規矩,do while迴圈操作嘛,與傳遞了Comparator比較器一致有兩種情況,看你是哪種騷操作
在這裡插入圖片描述
走到這裡的都是有了爹的孩子,這時候就是看看你比你爹大還是小。以右為大,青出於藍而勝於藍的靠右站,其餘的靠左涼快。cmp就是前面最後一次跳出迴圈的時候你和你爹較量的結果

6.2 紅黑樹調整

在這裡插入圖片描述
注意最後一個條件,一下所有情況的列舉都是建立在父節點為紅色節點的前提下進行的

前面講了紅黑樹節點的變更有可能就會破壞掉紅黑樹的約束,所以需要呼叫fixAfterInsertion()更改下節點顏色或者是調整下紅黑樹結構。就六種情況,劃分為兩類。第一類就是新插入節點的父節點是爺爺節點的右節點,第二種情況就是左節點。反正拗口,下面列舉左節點的情況,右節點就是相對的,把左右修改下就OK:
在這裡插入圖片描述

  • if判斷爺爺節點的左節點是不是等於父親節點,這不就是說父親節點為爺爺節點的左節點麼
  • 叔叔節點是紅色
    1 ) 將“父節點”設為黑色
    2 ) 將“叔叔節點”設為黑色
    3 ) 將“爺爺節點”設為“紅色”
    4 ) 將“爺爺節點”設為“當前節點”(紅色節點)
  • 叔叔節點是黑色,且當前節點是其父節點的右孩子
    1 ) 將“父節點”作為“新的當前節點”
    2 ) 以“新的當前節點”為支點進行左旋
  • 叔叔節點是黑色,且當前節點是其父節點的左孩子
    1 ) 將“父節點”設為“黑色”
    2 ) 將“爺爺節點”設為“紅色”
    3 ) 以“爺爺節點”為支點進行右旋

為了程式碼的完整性,下面粘貼出TreeMap處理右節點的邏輯,自己總結下就行了
在這裡插入圖片描述

七:NavigableMap

TreeMap繼承實現NaviableMap介面,該介面繼承自SortedMap。介面提供系列大小比較的API,返回值分為key與節點Entry
在這裡插入圖片描述
在這裡插入圖片描述

  • lower: 返回小於給定key的最大key/Entry
  • higher:返回大於給定key的最小key/Entry
  • ceiling:返回等於給定值的key/Entry或大於給定值最小的key/value
  • floor : 返回等於給定值的key/Entry或小於給定值最大的key/value