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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

映射表map(平衡二叉树实现)_手动实现Java集合容器之TreeMap(上)

發(fā)布時(shí)間:2024/7/5 java 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 映射表map(平衡二叉树实现)_手动实现Java集合容器之TreeMap(上) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上一篇我們手寫(xiě)了HashMap,還有一個(gè)很重要的Map的實(shí)現(xiàn)類(lèi)TreeMap。打開(kāi)源碼第一句話:* A Red-Black tree based {@link NavigableMap} implementation.TreeMap是一個(gè)基于紅黑樹(shù)的實(shí)現(xiàn)。對(duì)紅黑樹(shù)沒(méi)有了解怎么辦,那就先搞清楚紅黑樹(shù)的原理。只要理解紅黑樹(shù)的玩法,TreeMap實(shí)現(xiàn)起來(lái)就沒(méi)有那么大的難度了。

紅黑樹(shù)(Red Black Tree) 是一種自平衡二叉查找樹(shù)。所以我們先搞明白什么是二叉查找樹(shù)和完美平衡二叉樹(shù)。

二叉排序樹(shù)(Binary Sort Tree)是具有下列性質(zhì)的二叉樹(shù):

  • 元素以關(guān)鍵字為依據(jù),每個(gè)結(jié)點(diǎn)可比較大小,各元素關(guān)鍵字互不相同。
  • 對(duì)于每個(gè)結(jié)點(diǎn),其左子樹(shù)上所有結(jié)點(diǎn)均小于該結(jié)點(diǎn),右子樹(shù)上所以結(jié)點(diǎn)均大于該結(jié)點(diǎn)。
  • 每個(gè)結(jié)點(diǎn)的左右子樹(shù)也分別為二叉排序樹(shù)。
    • 查找:從根結(jié)點(diǎn)開(kāi)始查找,根據(jù)每一次比較結(jié)果,在當(dāng)前結(jié)點(diǎn)的左子樹(shù)與右子樹(shù)選擇其一,從而縮小一半的查找范圍。如果到達(dá)葉子結(jié)點(diǎn)仍然不相等,則查找不成功。
    • 插入:首先使用查找算法確定元素的插入位置。如果查找成功,說(shuō)明相同元素已經(jīng)存在,則不插入;否則在查找不成功的一條路徑之尾插入結(jié)點(diǎn),作為葉子結(jié)點(diǎn)。
    • 刪除:a. 葉結(jié)點(diǎn)直接刪除 b. 如果被刪除的結(jié)點(diǎn)有一個(gè)子結(jié)點(diǎn),將子結(jié)點(diǎn)移到被刪除的元素的位置。c. 采用中序遍歷(左-根-右),找到待刪除的結(jié)點(diǎn)的后繼結(jié)點(diǎn),將其與待刪除的結(jié)點(diǎn)互換,然后刪除待刪除的結(jié)點(diǎn)。假如我們要?jiǎng)h除29,中序遍歷結(jié)果為10-11-13-20-27-29-31-32-39-41-53-50-65-72-91,所以29的后繼結(jié)點(diǎn)是31,然后互換位置,刪除29。
    • 二叉查找樹(shù)的查詢復(fù)雜度,和二分查找一樣,插入和查找的時(shí)間復(fù)雜度均為 O(logn) ,但是在最壞的情況下仍然會(huì)有 O(n) 的時(shí)間復(fù)雜度。原因在于插入和刪除元素的時(shí)候,樹(shù)沒(méi)有保持平衡。

    為了降低二叉排序樹(shù)的高度,提高查找效率。平衡二叉樹(shù)(又稱(chēng)為AVL樹(shù))。平衡二叉樹(shù)(Balanced Binary Tree)是具有下列性質(zhì)的二叉排序樹(shù):

  • 左子樹(shù)和右子樹(shù)都是平衡二叉樹(shù)
  • 左子樹(shù)與右子樹(shù)高度差絕對(duì)值不超過(guò)一。結(jié)點(diǎn)的平衡因子定義為其左子樹(shù)與右子樹(shù)的高度之差。
  • 在平衡二叉樹(shù)中,插入或刪除一個(gè)結(jié)點(diǎn)可能破壞二叉樹(shù)的平衡性,因此在插入或刪除時(shí)都要調(diào)整二叉樹(shù)。
  • 插入:如果插入一個(gè)結(jié)點(diǎn)后破壞了二叉樹(shù)的平衡性,需要調(diào)整一棵最小不平衡子樹(shù)。最小不平衡子樹(shù)是離插入結(jié)點(diǎn)最近,且以平衡因子絕對(duì)值大于1的結(jié)點(diǎn)為根的子樹(shù)。若出現(xiàn)不平衡,則要根據(jù)新插入的結(jié)點(diǎn)與最低不平衡結(jié)點(diǎn)的位置關(guān)系進(jìn)行相應(yīng)的調(diào)整。分為L(zhǎng)L,RR,LR,RL四種類(lèi)型。以下只介紹了最簡(jiǎn)單的情況。

    LL型:在最低不平衡結(jié)點(diǎn)的左孩子的左子樹(shù)上插入結(jié)點(diǎn)。插入C后,A的平衡因子由1增加到2 。結(jié)點(diǎn)B變成新的根結(jié)點(diǎn)。A變成右孩子結(jié)點(diǎn),C變成左孩子結(jié)點(diǎn)。

    RR型:在最低不平衡結(jié)點(diǎn)的右孩子的右子樹(shù)上插入結(jié)點(diǎn)。結(jié)點(diǎn)B變成新的根結(jié)點(diǎn)。C變成右孩子結(jié)點(diǎn),A變成左孩子結(jié)點(diǎn)。

    LR型:在最低不平衡結(jié)點(diǎn)的左孩子的右子樹(shù)上插入結(jié)點(diǎn)。結(jié)點(diǎn)C變成新的根結(jié)點(diǎn)。A變成右孩子結(jié)點(diǎn),B變成左孩子結(jié)點(diǎn)。

    RL型:在最低不平衡結(jié)點(diǎn)的右孩子的左子樹(shù)上插入結(jié)點(diǎn)。結(jié)點(diǎn)C變成新的根結(jié)點(diǎn)。B變成右孩子結(jié)點(diǎn),A變成左孩子結(jié)點(diǎn)。

    平衡二叉樹(shù)似乎完美解決了二叉排序樹(shù)的問(wèn)題,通過(guò)旋轉(zhuǎn)使樹(shù)的高度最小化,對(duì)于有 n 個(gè)節(jié)點(diǎn)的平衡樹(shù),最壞的查找時(shí)間復(fù)雜度也為 O(logn)。

    那么我們?yōu)槭裁催€需要紅黑樹(shù)?

    因?yàn)槲覀儾粌H僅需要關(guān)心查找的效率,還要考慮插入的效率。因?yàn)槠胶舛鏄?shù)要求每個(gè)節(jié)點(diǎn)的左子樹(shù)和右子樹(shù)的高度差至多等于1,這個(gè)要求非常嚴(yán)格,每次進(jìn)行插入/刪除數(shù)據(jù)的時(shí)候,幾乎都會(huì)破壞這個(gè)規(guī)則。在插入/刪除數(shù)據(jù)很頻繁的場(chǎng)景中,平衡二叉樹(shù)的性能就會(huì)受到很?chē)?yán)重的影響。所以我們需要紅黑樹(shù)。

    紅黑樹(shù)的定義

  • 每個(gè)節(jié)點(diǎn)或者是黑色,或者是紅色。
  • 根節(jié)點(diǎn)是黑色。
  • 每個(gè)葉子節(jié)點(diǎn)是黑色。
  • 如果一個(gè)節(jié)點(diǎn)是紅色的,則它的子節(jié)點(diǎn)必須是黑色的
  • 從任意一個(gè)節(jié)點(diǎn)到葉子節(jié)點(diǎn),經(jīng)過(guò)的黑色節(jié)點(diǎn)是一樣的。
    • 查找:紅黑樹(shù)的查找和二叉排序樹(shù)一樣,不再贅述
    • 添加:
    這是一個(gè)把數(shù)據(jù)結(jié)構(gòu)可視化的網(wǎng)站,我們用網(wǎng)站進(jìn)行一些插入數(shù)據(jù)的試驗(yàn)Red/Black Tree Visualization?www.cs.usfca.edu

    添加根結(jié)點(diǎn)時(shí),結(jié)點(diǎn)為黑色

    添加一個(gè)子結(jié)點(diǎn),插入結(jié)點(diǎn)為紅色,滿足紅黑樹(shù)的定義,無(wú)需變化

    在添加一個(gè)孩子,如果添加的數(shù)比根結(jié)點(diǎn)小,很簡(jiǎn)單

    如果添加的數(shù)比根結(jié)點(diǎn)的右結(jié)點(diǎn)還要大,左旋,15變成根結(jié)點(diǎn),并且改變顏色

    如果繼續(xù)插入一個(gè)數(shù),因?yàn)椴粷M足性質(zhì)4,所以10和20的顏色變黑,30變紅

    繼續(xù)在右子樹(shù)上添加35,左旋

    繼續(xù)插入25,此時(shí)不需要旋轉(zhuǎn),只需要改變結(jié)點(diǎn)顏色,滿足性質(zhì)四

    所以我們發(fā)現(xiàn)每一次插入數(shù)據(jù)之后,如果不滿足紅黑樹(shù)的定義,就需要對(duì)紅黑樹(shù)的結(jié)構(gòu)進(jìn)行調(diào)整。兩種方式:旋轉(zhuǎn)和重新上色。所以我們?cè)贘ava源碼中找到了添加數(shù)據(jù)的方法,并分析這個(gè)方法。

    /**

    假如我們要往這個(gè)紅黑數(shù)里面添加6

    沒(méi)有調(diào)整過(guò)的樹(shù)是這樣的

    第一步,8和6兩個(gè)同為紅色結(jié)點(diǎn),所以改變顏色,8和14變黑,10變紅。對(duì)應(yīng)源碼中的情況1,當(dāng)插入結(jié)點(diǎn)的叔叔結(jié)點(diǎn)為紅,把父結(jié)點(diǎn)變黑,叔叔結(jié)點(diǎn)也變黑,再把爺爺結(jié)點(diǎn)變紅

    如果插入結(jié)點(diǎn)的爺爺結(jié)點(diǎn)是右孩子結(jié)點(diǎn),我們找到爺爺結(jié)點(diǎn)的父結(jié)點(diǎn),然后在這個(gè)結(jié)點(diǎn)上左旋,對(duì)應(yīng)源碼中的情況2

    下一步,右旋,10變黑,20變紅,對(duì)應(yīng)源碼中的情況3

    從源碼中看出,情況2是情況3的一種擴(kuò)展。情況4、5、6是1、2、3的鏡像,就不展開(kāi)了。

    刪除也需要調(diào)整樹(shù)的結(jié)構(gòu),但是更復(fù)雜一些,我們看一下源碼中的方法。

    /**

    刪除一共8種情況,1-4和5-8也是鏡像的,就不舉具體的例子了。TreeMap果然要比HashMap還要復(fù)雜的多,就算讀懂了 rebalance的方法,真正實(shí)現(xiàn)起來(lái)還是有很大的難度。以此為基礎(chǔ),下一篇我們嘗試一下手寫(xiě)HashMap。

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的映射表map(平衡二叉树实现)_手动实现Java集合容器之TreeMap(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。