国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java TreeMap 源碼解析

rubyshen / 2383人閱讀

摘要:源碼剖析由于紅黑樹的操作我這里不說了,所以這里基本上也就沒什么源碼可以講了,因?yàn)檫@里面重要的算法都是,這里的是指,他們是算法導(dǎo)論的作者,也就是說里面算法都是參照算法導(dǎo)論的偽代碼。因?yàn)榧t黑樹是平衡的二叉搜索樹,所以其包含操作的時(shí)間復(fù)雜度都為。

本文章首發(fā)于個(gè)人博客,鑒于sf博客樣式具有賞心悅目的美感,遂發(fā)表于此,供大家學(xué)習(xí)、批評(píng)。
本文還在不斷更新中,最新版可移至個(gè)人博客。?

繼上篇文章介紹完了HashMap,這篇文章開始介紹Map系列另一個(gè)比較重要的類TreeMap。
大家也許能感覺到,網(wǎng)絡(luò)上介紹HashMap的文章比較多,但是介紹TreeMap反而不那么多,這里面是有原因:一方面HashMap的使用場(chǎng)景比較多;二是相對(duì)于HashMap來說,TreeMap所用到的數(shù)據(jù)結(jié)構(gòu)更為復(fù)雜。

廢話不多說,進(jìn)入正題。

簽名(signature)
public class TreeMap
       extends AbstractMap
       implements NavigableMap, Cloneable, java.io.Serializable

可以看到,相比HashMap來說,TreeMap多繼承了一個(gè)接口NavigableMap,也就是這個(gè)接口,決定了TreeMap與HashMap的不同:

HashMap的key是無序的,TreeMap的key是有序的

接口NavigableMap

首先看下NavigableMap的簽名

public interface NavigableMap extends SortedMap

發(fā)現(xiàn)NavigableMap繼承了SortedMap,再看SortedMap的簽名

SortedMap
public interface SortedMap extends Map

SortedMap就像其名字那樣,說明這個(gè)Map是有序的。這個(gè)順序一般是指由Comparable接口提供的keys的自然序(natural ordering),或者也可以在創(chuàng)建SortedMap實(shí)例時(shí),指定一個(gè)Comparator來決定。
當(dāng)我們?cè)谟眉弦暯牵╟ollection views,與HashMap一樣,也是由entrySet、keySet與values方法提供)來迭代(iterate)一個(gè)SortedMap實(shí)例時(shí)會(huì)體現(xiàn)出key的順序。

這里引申下關(guān)于Comparable與Comparator的區(qū)別(參考這里):

Comparable一般表示類的自然序,比如定義一個(gè)Student類,學(xué)號(hào)為默認(rèn)排序

Comparator一般表示類在某種場(chǎng)合下的特殊分類,需要定制化排序。比如現(xiàn)在想按照Student類的age來排序

插入SortedMap中的key的類類都必須繼承Comparable類(或指定一個(gè)comparator),這樣才能確定如何比較(通過k1.compareTo(k2)comparator.compare(k1, k2))兩個(gè)key,否則,在插入時(shí),會(huì)報(bào)ClassCastException的異常。

此為,SortedMap中key的順序性應(yīng)該與equals方法保持一致。也就是說k1.compareTo(k2)comparator.compare(k1, k2)為true時(shí),k1.equals(k2)也應(yīng)該為true。

介紹完了SortedMap,再來回到我們的NavigableMap上面來。
NavigableMap是JDK1.6新增的,在SortedMap的基礎(chǔ)上,增加了一些“導(dǎo)航方法”(navigation methods)來返回與搜索目標(biāo)最近的元素。例如下面這些方法:

lowerEntry,返回所有比給定Map.Entry小的元素

floorEntry,返回所有比給定Map.Entry小或相等的元素

ceilingEntry,返回所有比給定Map.Entry大或相等的元素

higherEntry,返回所有比給定Map.Entry大的元素

設(shè)計(jì)理念(design concept) 紅黑樹(Red–black tree)

TreeMap是用紅黑樹作為基礎(chǔ)實(shí)現(xiàn)的,紅黑樹是一種二叉搜索樹,讓我們?cè)谝黄鸹貞浵露嫠阉鳂涞囊恍┬再|(zhì)

二叉搜索樹

先看看二叉搜索樹(binary search tree,BST)長(zhǎng)什么樣呢?

相信大家對(duì)這個(gè)圖都不陌生,關(guān)鍵點(diǎn)是:

左子樹的值小于根節(jié)點(diǎn),右子樹的值大于根節(jié)點(diǎn)。

二叉搜索樹的優(yōu)勢(shì)在于每進(jìn)行一次判斷就是能將問題的規(guī)模減少一半,所以如果二叉搜索樹是平衡的話,查找元素的時(shí)間復(fù)雜度為log(n),也就是樹的高度。

我這里想到一個(gè)比較嚴(yán)肅的問題,如果說二叉搜索樹將問題規(guī)模減少了一半,那么三叉搜索樹不就將問題規(guī)模減少了三分之二,這不是更好嘛,以此類推,我們還可以有四叉搜索樹,五叉搜索樹......對(duì)于更一般的情況:

n個(gè)元素,K叉樹搜索樹的K為多少時(shí)效率是最好的?K=2時(shí)嗎?

K 叉搜索樹

如果大家按照我上面分析,很可能也陷入一個(gè)誤區(qū),就是

三叉搜索樹在將問題規(guī)模減少三分之二時(shí),所需比較操作的次數(shù)是兩次(二叉搜索樹再將問題規(guī)模減少一半時(shí),只需要一次比較操作)

我們不能把這兩次給忽略了,對(duì)于更一般的情況:

n個(gè)元素,K叉樹搜索樹需要的平均比較次數(shù)為k*log(n/k)

對(duì)于極端情況k=n時(shí),K叉樹就轉(zhuǎn)化為了線性表了,復(fù)雜度也就是O(n)了,如果用數(shù)學(xué)角度來解這個(gè)問題,相當(dāng)于:

n為固定值時(shí),k取何值時(shí),k*log(n/k)的取值最???

k*log(n/k)根據(jù)對(duì)數(shù)的運(yùn)算規(guī)則可以轉(zhuǎn)化為ln(n)*k/ln(k),ln(n)為常數(shù),所以相當(dāng)于取k/ln(k)的極小值。這個(gè)問題對(duì)于大一剛學(xué)高數(shù)的人來說再簡(jiǎn)單不過了,我們這里直接看結(jié)果?

當(dāng)k=e時(shí),k/ln(k)取最小值。

自然數(shù)e的取值大約為2.718左右,可以看到二叉樹基本上就是這樣最優(yōu)解了。在Nodejs的REPL中進(jìn)行下面的操作

function foo(k) {return k/Math.log(k);}
> foo(2)
2.8853900817779268
> foo(3)
2.730717679880512
> foo(4)
2.8853900817779268
> foo(5)
3.1066746727980594

貌似k=3時(shí)比k=2時(shí)得到的結(jié)果還要小,那也就是說三叉搜索樹應(yīng)該比二叉搜索樹更好些呀,但是為什么二叉樹更流行呢?后來在萬能的stackoverflow上找到了答案,主旨如下:

現(xiàn)在的CPU可以針對(duì)二重邏輯(binary logic)的代碼做優(yōu)化,三重邏輯會(huì)被分解為多個(gè)二重邏輯。

這樣也就大概能理解為什么二叉樹這么流行了,就是因?yàn)檫M(jìn)行一次比較操作,我們最多可以將問題規(guī)模減少一半。

好了這里扯的有點(diǎn)遠(yuǎn)了?,我們?cè)倩氐郊t黑樹上來。

紅黑樹性質(zhì)

先看看紅黑樹的樣子:

上圖是從wiki截來的,需要說明的一點(diǎn)是:

葉子節(jié)點(diǎn)為上圖中的NIL節(jié)點(diǎn),國(guó)內(nèi)一些教材中沒有這個(gè)NIL節(jié)點(diǎn),我們?cè)诋媹D時(shí)有時(shí)也會(huì)省略這些NIL節(jié)點(diǎn),但是我們需要明確,當(dāng)我們說葉子節(jié)點(diǎn)時(shí),指的就是這些NIL節(jié)點(diǎn)。

紅黑樹通過下面5條規(guī)則,保證了樹是平衡的:

樹的節(jié)點(diǎn)只有紅與黑兩種顏色

根節(jié)點(diǎn)為黑色的

葉子節(jié)點(diǎn)為黑色的

紅色節(jié)點(diǎn)的字節(jié)點(diǎn)必定是黑色的

從任意一節(jié)點(diǎn)出發(fā),到其后繼的葉子節(jié)點(diǎn)的路徑中,黑色節(jié)點(diǎn)的數(shù)目相同

滿足了上面5個(gè)條件后,就能夠保證:根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的最長(zhǎng)路徑不會(huì)大于根節(jié)點(diǎn)到葉子最短路徑的2倍
其實(shí)這個(gè)很好理解,主要是用了性質(zhì)4與5,這里簡(jiǎn)單說下:

假設(shè)根節(jié)點(diǎn)到葉子節(jié)點(diǎn)最短的路徑中,黑色節(jié)點(diǎn)數(shù)目為B,那么根據(jù)性質(zhì)5,根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的最長(zhǎng)路徑中,黑色節(jié)點(diǎn)數(shù)目也是B,最長(zhǎng)的情況就是每?jī)蓚€(gè)黑色節(jié)點(diǎn)中間有個(gè)紅色節(jié)點(diǎn)(也就是紅黑相間的情況),所以紅色節(jié)點(diǎn)最多為B-1個(gè)。這樣就能證明上面的結(jié)論了。

紅黑樹操作

關(guān)于紅黑樹的插入、刪除、左旋、右旋這些操作,我覺得最好可以做到可視化,文字表達(dá)比較繁瑣,我這里就不在獻(xiàn)丑了,網(wǎng)上能找到的也比較多,像v_July_v的《教你透徹了解紅黑樹》。我這里推薦個(gè)swf教學(xué)視頻(視頻為英文,大家不要害怕,重點(diǎn)是看圖?),7分鐘左右,大家可以參考。

這里還有個(gè)交互式紅黑樹的可視化網(wǎng)頁,大家可以上去自己操作操作,插入幾個(gè)節(jié)點(diǎn),刪除幾個(gè)節(jié)點(diǎn)玩玩,看看左旋右旋是怎么玩的。

源碼剖析

由于紅黑樹的操作我這里不說了,所以這里基本上也就沒什么源碼可以講了,因?yàn)檫@里面重要的算法都是From CLR,這里的CLR是指Cormen, Leiserson, Rivest,他們是算法導(dǎo)論的作者,也就是說TreeMap里面算法都是參照算法導(dǎo)論的偽代碼。

因?yàn)榧t黑樹是平衡的二叉搜索樹,所以其put(包含update操作)、get、remove的時(shí)間復(fù)雜度都為log(n)

總結(jié)

到目前為止,TreeMap與HashMap的的實(shí)現(xiàn)算是都介紹完了,可以看到它們實(shí)現(xiàn)的不同,決定了它們應(yīng)用場(chǎng)景的不同:

TreeMap的key是有序的,增刪改查操作的時(shí)間復(fù)雜度為O(log(n)),為了保證紅黑樹平衡,在必要時(shí)會(huì)進(jìn)行旋轉(zhuǎn)

HashMap的key是無序的,增刪改查操作的時(shí)間復(fù)雜度為O(1),為了做到動(dòng)態(tài)擴(kuò)容,在必要時(shí)會(huì)進(jìn)行resize。

另外,我這里沒有解釋具體代碼,難免有些標(biāo)題黨了,請(qǐng)大家見諒,后面理解的更深刻了再來填坑。?

參考

http://stackoverflow.com/questions/21329662/explanation-of-red-black-tree-based-implementation-of-treemap-in-java

http://javahungry.blogspot.com/2014/04/fail-fast-iterator-vs-fail-safe-iterator-difference-with-example-in-java.html

https://en.wikipedia.org/wiki/Binary_search_tree

https://en.wikipedia.org/wiki/Red%E2%80%93black_tree

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/64493.html

相關(guān)文章

  • Java 集合Hashtable源碼深入解析

    摘要:分別獲取正序反序的鍵集。是用來實(shí)現(xiàn)機(jī)制的第部分源碼解析基于為了更了解的原理,下面對(duì)源碼代碼作出分析。實(shí)現(xiàn)了迭代器和枚舉兩個(gè)接口獲取的迭代器若的實(shí)際大小為則返回空迭代器對(duì)象否則,返回正常的的對(duì)象。 概要 前面,我們已經(jīng)系統(tǒng)的對(duì)List進(jìn)行了學(xué)習(xí)。接下來,我們先學(xué)習(xí)Map,然后再學(xué)習(xí)Set;因?yàn)镾et的實(shí)現(xiàn)類都是基于Map來實(shí)現(xiàn)的(如,HashSet是通過HashMap實(shí)現(xiàn)的,TreeSe...

    Turbo 評(píng)論0 收藏0
  • TreeMap就這么簡(jiǎn)單【源碼剖析】

    摘要:在這種情況下,是以其為根的樹的最后一個(gè)結(jié)點(diǎn)。來源二總結(jié)底層是紅黑樹,能夠?qū)崿F(xiàn)該集合有序如果在構(gòu)造方法中傳遞了對(duì)象,那么就會(huì)以對(duì)象的方法進(jìn)行比較。 前言 聲明,本文用得是jdk1.8 前面章節(jié)回顧: Collection總覽 List集合就這么簡(jiǎn)單【源碼剖析】 Map集合、散列表、紅黑樹介紹 HashMap就是這么簡(jiǎn)單【源碼剖析】 LinkedHashMap就這么簡(jiǎn)單【源碼剖析】 本...

    ormsf 評(píng)論0 收藏0
  • java源碼一帶一路系列】之TreeMap

    摘要:基于紅黑樹實(shí)現(xiàn),在之前篇章中有所涉及,所以本篇重點(diǎn)不在此。費(fèi)解順帶一提,如果你還記得之前文章中的也用到了紅黑樹,而它先比較的再比值,這比較的是值。在這的作用類似中的,修復(fù)紅黑樹性質(zhì)。 TreeMap基于紅黑樹實(shí)現(xiàn),在之前HashMap篇章中有所涉及,所以本篇重點(diǎn)不在此。上路~ containsKey() --> getEntry() --> getEntryUsingComparat...

    Bamboy 評(píng)論0 收藏0
  • Java集合問題大匯總

    摘要:集合中成員很豐富,常用的集合有,,等。實(shí)現(xiàn)接口的集合主要有。集合中不能包含重復(fù)的元素,每個(gè)元素必須是唯一的。而以作為實(shí)現(xiàn)的構(gòu)造函數(shù)的訪問權(quán)限是默認(rèn)訪問權(quán)限,即包內(nèi)訪問權(quán)限。與接口不同,它是由一系列鍵值對(duì)組成的集合,提供了到的映射。 原文地址 Java集合 Java集合框架:是一種工具類,就像是一個(gè)容器可以存儲(chǔ)任意數(shù)量的具有共同屬性的對(duì)象。 Java集合中成員很豐富,常用的集合有Arra...

    894974231 評(píng)論0 收藏0
  • TreeMap 源碼分析

    摘要:當(dāng)往中放入新的鍵值對(duì)后,可能會(huì)破壞紅黑樹的性質(zhì)。修復(fù)操作要重新使紅黑樹恢復(fù)平衡,修復(fù)操作的源碼分析如下方法分析如下上面對(duì)部分代碼邏輯就行了分析,通過配圖的形式解析了每段代碼邏輯所處理的情況。四總結(jié)本文可以看做是本人紅黑樹詳細(xì)分析一文的延續(xù)。 一、簡(jiǎn)介 TreeMap最早出現(xiàn)在JDK 1.2中,是 Java 集合框架中比較重要一個(gè)的實(shí)現(xiàn)。TreeMap 底層基于紅黑樹實(shí)現(xiàn),可保證在log...

    chaos_G 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<