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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java中的查找树和哈希表(一级)

發(fā)布時間:2024/4/13 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java中的查找树和哈希表(一级) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

下面我們來看一下JAVA中有哪些查找樹和哈希表,我們分兩塊內(nèi)容來講唄,第一塊我們首先來講查找樹,第二塊我們來講哈希表,JAVA里面我們有一個TreeSet,還有一個TreeMap,他們底層都是使用了紅黑樹,這個大家記住,我們在這里有一個圖,這個圖說明一個什么道理呢,我是不是創(chuàng)建了一個TreeSet,我加的數(shù)都是1,2,3,4,5,但是我是不是按照不同的順序來加的,我想問的一個問題是,當我們按照不同的順序來加的話,最終會不會出現(xiàn)這中偏激的情況,會不會出現(xiàn),不會,為什么不會啊,因為他是紅黑樹,紅黑樹他是一種二叉平衡樹,當你沒加一個元素,他都會保證這個數(shù)加完之后,加之前是平衡樹,加之后還是個平衡樹,會有相關(guān)的算法來實現(xiàn)自平衡,比如我們按照1,2,3,4,5來加的話,先加一個1是平衡,再加一個2是放在右邊,因為它大于1,這時候還是平衡的,當我們再加個3的時候,他就不平衡了,他有各種算法,比如這個時候我們可以把2的左指針改一下,把1放到這里,這個1就沒有了,這個時候首先左右是平衡的,同時還是二叉平衡樹,保證左邊的小于根,根小于右邊的,你還可以再加一個4,這個時候還是平衡的,那我們再加5的時候,要加5了,是不是又不平衡了,他還要有一個相應(yīng)的解決方案,算法把它修改為平衡的狀態(tài),這個大家知道,這是我們所說的一個紅黑樹,那我順便想問大家,TreeSet和TreeMap是什么關(guān)系,或者說我們的HashSet和HashMap是什么關(guān)系,什么關(guān)系我們可以來看一下相關(guān)的源碼 下面我們來看HashMap的底層結(jié)構(gòu):我知道HashSet的底層結(jié)構(gòu)是HashMap了,那你能告訴我HashMap的底層結(jié)構(gòu)是什么嗎?我告訴你,HashMap的底層結(jié)構(gòu)就是哈希表,他就是哈希表,只要以后你見到這個名字,只要這個名字是以Hash開始的,都說明他的底層結(jié)構(gòu)是哈希表,都說明它是非常快的,速度是很快的,這是我們選擇相應(yīng)集合的一個依據(jù),這個大家知道,底層就是一個哈希表,主結(jié)構(gòu)是一個數(shù)組,每個數(shù)組上面可以引一個鏈,這個鏈叫做一個桶,我們來看,但是這個時候還有一個變化,在JDK及其之前,我們 現(xiàn)在用的是哪一個,咱們是8,有的同學(xué)用的可能是7,那我告訴大家,在JDK1.7之前的話,HashMap底層就是一個哈希表,主結(jié)構(gòu)是一個數(shù)組,從結(jié)構(gòu)是鏈表,大家來看,主結(jié)構(gòu)是一個數(shù)組,然后從結(jié)構(gòu)是一個鏈表,一個鏈表連起來就是一個桶,bucket這樣的一個單詞,但是我們知道,它是有缺點的,萬一這個沖突比較多的話,如果這個鏈表引得特別長的話,引了20個,30個的話,引了幾十個的話,他的查詢效率也是比較低的,有沒有別的辦法,當然有了,比如后面我們可以給他擴容,這個都是有的,但是即使擴容,也難免會出現(xiàn)這種情況,那我們怎么來解決,在JDK1.8的時候,給了一個更好的,當然也是一個更好的解決方案,大家再來看下面一個圖,我們來看下面這個圖,這個圖還是1.7之前的圖,每個節(jié)點里面存儲的還是entry,什么叫entry,有一個key,有一個value,還有一個指針,這是每個節(jié)點,至少包括這三部分,數(shù)據(jù)就是存在這里面的,數(shù)據(jù)就是存在這兒的,每個Entry就是一個鍵值對,當然還存放著指向下一個節(jié)點的指針,這是我們所說的內(nèi)容,下邊我們看,在1.8里面出現(xiàn)了一個什么變化,出現(xiàn)了這樣的一個變化,告訴我這個變化是什么,主結(jié)構(gòu)是不是還是一個數(shù)組,如果出現(xiàn)了沖突,是不是還會引這個鏈表,但是下面一大堆一看就知道是什么,這是不是紅黑樹,他怎么引出了紅黑樹,如果你這個列表的長度,大于等于8的時候,你這個列表太長了,大于等于8個的時候,他就會把這一塊做一下修改,給你變成下面這個結(jié)構(gòu),為什么要這么變,因為如果要是16個的話,那你這里要查找16次,當你變成一棵樹的話,層次就少了,可能3次4次就可以了,目的還是為了提高查詢的效率,他還是提供啊查詢的效率,這個主要是查詢的時間復(fù)雜度上,鏈表為O(n),而紅黑樹是log(2 n),如果沖突比較多,超過8,就采用紅黑樹來提高效率,這一點大家知道,當然紅黑樹難度就高了,代碼也就難理解了,這是一個 當我們再來看一下,HashSet的底層結(jié)構(gòu)已經(jīng)說了,底層就是HashMap,那我們再來看一下HashMap的源碼分析,我們以JDK1.7的為準,那我們現(xiàn)在是1.8的,1.8的可以簡單的看一下,怎么看呢,我們就看HashMap就可以了總結(jié)一下:注意TreeSet和TreeMap用的是紅黑樹,TreeSet的底層用的是TreeMap,HashMap的底層結(jié)構(gòu)1.7是表加鏈表,1.8有什么變化,加入了紅黑樹,鏈表長度大于等于8的時候,源碼大家去網(wǎng)上找一些相關(guān)的源碼,最好看JDK1.7的,或者你的版本是1.7,直接來看,看哪些操作,看他有哪些屬性,看他有哪些方法,看他的put和get,來看這個就可以了,網(wǎng)上找資料有什么好處,它會給你加一些中文的注釋,會給你講解,當然我們剛才找了半天也沒有找到合適的,大家耐性來找 package com.learn.search;import java.util.HashMap; import java.util.HashSet; import java.util.TreeSet;/*** HashSet的底層結(jié)構(gòu)* 底層結(jié)構(gòu)采用HashMap* HashSet的元素作為HashMap的key,* 統(tǒng)一使用Object對象作為value* 我們可以看源碼* 這是我們所說的一個內(nèi)容* 我們這里還可以再加一句話,* TreeSet的底層結(jié)構(gòu)是TreeMap,都使用了紅黑樹* 因為它底層就是TreeMap,TreeMap的底層是紅黑樹* TreeSet當然也是紅黑樹* @author Leon.Sun**/ public class TestCollection {public static void main(String[] args) {/*** 然后我們來創(chuàng)建一個TreeSet* 當我們創(chuàng)建TreeSet的時候,* 點他進來,* this(new TreeMap<E,Object>());* 底層實際上是創(chuàng)建了一個TreeMap* 你創(chuàng)建了一個TreeSet,實際上是創(chuàng)建了一個TreeMap* 他給你創(chuàng)建了一個TreeMap* 這個大家記住了* TreeSet(NavigableMap<E,Object> m)* this.m = m;* 這個m是誰看一下* private transient NavigableMap<E,Object> m;* m實際上是一個Map* 這個明確一下* 我們再來看一下size* return m.size();* 你這個哈希size,你這個TreeSet的size* 實際上就是map的size* m.clear();* 還是map的清空啊* 為什么,因為我剛才做了一個清空的操作* this(new TreeMap<E,Object>());* 是不是new了一個TreeMap* 結(jié)果把這個TreeMap做了一個實參* TreeSet(NavigableMap<E,Object> m)* 這個就是一個TreeMap,* this.m = m;* 就給這個m了* 就給他了* */TreeSet set = new TreeSet();/*** 加入一個內(nèi)容*/set.add("aaa");set.size();/*** 很多的函數(shù)*/set.clear();/*** 同樣順便我們來說一下* 我們創(chuàng)建一個HashSet* 當你new了一個HashSet的時候,* 你實際上是new了一個HashMap* map = new HashMap<>();* 這個map是誰,點一下這個map* private transient HashMap<E,Object> map;* 底層就是一個HashMap* 是這么來的* 那我們再來看,* 當我們add的時候呢* public boolean add(E e)* 你往set里面加個數(shù)據(jù),* return map.put(e, PRESENT)==null;* put我們都用過,放了一個鍵值對* 那我們這里放的abc,到map里面是key* 那value是誰啊* 一個鍵一個值* 就是我們往set里面放的元素* 放到map里面,* 會變成map里面的key* 值是這個PRESENT* PRESENT他是誰啊* private static final Object PRESENT = new Object();* 它是一個空的Object對象* 他就是一個Object對象* 表面上是Set,實際上都放到Map里面去了* 作為Map的key存在* 那他的value是什么啊* value都是統(tǒng)一的new Object(),Object對象* 這個大家知道* */HashSet set2 = new HashSet();set2.add("abc");/*** 我們再來看size,* return map.size();* map的size* */set2.size();/*** map.clear();* map的clear* */set2.clear();/*** return map.isEmpty();* map是不是空的* 這一點大家一定要記住*/set2.isEmpty();/*** 看我們添加對象的時候是怎么添加的* this.loadFactor = DEFAULT_LOAD_FACTOR;* 這個什么意思,相當于我們一創(chuàng)建HashMap的時候,* 是不是只引用了一個參數(shù),別的參數(shù)有沒有指定* 沒有指定,* static final float DEFAULT_LOAD_FACTOR = 0.75f;* 這個Default_load_factor什么意思* 0.75是什么啊,就是我們將哈希表說的裝填因子* 他采用默認的是0.75* 如果你要是100個,數(shù)組的總長度是100,* 達到75個之后就擴容了* 他就開始擴了* 那我想知道默認的總長度是多少* 我想知道哈希表默認的總長度是多少* 那我們是可以找一下的* static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;* 默認的總長度,這什么意思啊* 1左移4位,每左移相當于乘以2* 相當于16嘛* 默認的初始化長度是16* 但是你要知道* 如果從源碼上來看的話* 他里面有沒有指定默認的值* 沒有指定* 初始化容量,默認裝填因子* public HashMap(int initialCapacity, float loadFactor)* 這里面會有的* this.threshold = tableSizeFor(initialCapacity);* 會有這樣的一個操作* 從而把16傳進去,賦給另外一個屬性* 這個就是1.8,1.8來說就要難一些了* 我們再來看這個put了* */HashMap map = new HashMap();/*** 這個相當于添加* * put什么意思* 就調(diào)了個putVal,* return putVal(hash(key), key, value, false, true);* putVal里面怎么辦* 這里面來說就是相對比較復(fù)雜了* 我們這里面甚至都有TreeNode了* 那就涉及到了紅黑樹了* 紅黑樹的節(jié)點* 就是鏈表的節(jié)點,可以這么來理解* 這是我們所說的一個內(nèi)容* */map.put("cn", "China");map.put("us", "USA");/*** 請問這個時候我輸出us是誰* 是USA還是America* 是不是America* 因為我們來放是按照key來放的* 我們按照key來放的* 值是跟著key走的* 如果我們放了一次us* 現(xiàn)在再放一次us* us只存一個* 但是這個value就變了* 就由USA變成了America* 就變成他了* 那我們看一下是不是這個代碼* 打開他來看* 哈希碼相同并且對象相同* 新值替換舊值* 這什么意思啊* 返回的就是一個舊值* V oldValue = e.value;* 把原來的值賦給舊值* e.value = value;* 把現(xiàn)在的值相當于舊值替換* return oldValue;* 最后返回的是舊值* 是這么來的* 大家還是在網(wǎng)上多搜一下1.7的代碼* 還是比較好看的* 因為1.8加了一個我們紅黑樹* 代碼比較難懂* 大家就可以到網(wǎng)上找一些相關(guān)的資料來看* 那JAVA中的查找和哈希表就講到這里了*/map.put("us", "America");/*** 大家想一下,這個相當于獲取* * 我們再來看一個內(nèi)容,* get怎么辦呢,* 找HashMap的get唄* 他最終調(diào)的是getNode,* return (e = getNode(hash(key), key)) == null ? null : e.value;* 先得到這個e,* e就是那個Entry* getNode可以看一下里面的這個代碼* 因為自從1.8之后這個難度就比較高了* 比較難理解* 那我們就看一下1.7的* 1.7的就非常好理解了* 怎么看1.7呢* 那我們就網(wǎng)上來找吧* 很多人關(guān)注他* https://www.cnblogs.com/stevenczp/p/7028071.html* 很多人關(guān)注這個* http://www.cnblogs.com/wuhuangdi/p/4175991.html* 至少找一個排版比較好的* HashMap的存儲結(jié)構(gòu)* 主結(jié)構(gòu)是一個數(shù)組* 這是不是一個鏈表啊* 而每個Entry里面一放大,* 有key,有value,是不是還要有一個指針指向下一個* 我們給大家介紹一下,大家看資料的時候也比較方便* 我們找他無參構(gòu)造方法吧* 他這個不好* https://blog.csdn.net/jevonscsdn/article/details/54619114* 先了解一下他的成員* static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; * 這是我們剛才看到的默認長度16* static final float DEFAULT_LOAD_FACTOR = 0.75f;//默認加載因子* 默認的加載因子0.75* 這個也不好* 總可以找到很好的* 構(gòu)造方法,* 比如我們來看這個,* https://blog.csdn.net/u011617742/article/details/54576890* 我們就是要找無參構(gòu)造方法* https://blog.csdn.net/ghsau/article/details/16843543/* public V put(K key, V value)* 他這個put就是1.7的* 這個put什么含義* 我們找最關(guān)鍵的,* int hash = hash(key);* 得到這個方法* 把key傳進來,調(diào)用這個hash,他就會得到哈希碼* 就是key本身是有哈希碼的,這個二次進行了hash,這是一個細節(jié)* 把這個哈希碼又重新轉(zhuǎn)換了一下,這一步就相當于得到哈希碼* int i = indexFor(hash, table.length);* 這一步indexFor,根據(jù)哈希碼和數(shù)組的長度去得到這個地址* 這是我們哈希表原理里面的第一步* 第一步計算哈希碼,第二步根據(jù)哈希碼算出地址,* 第三步我們要干什么了,* 就是1這個位置,是不是要順著鏈表往下找了* 往下找怎么辦,如果找到一個14呢* 不是不放,我們放的是map,* map是什么意思,* map就是這個意思,* * */map.get("cn");} }

?

總結(jié)

以上是生活随笔為你收集整理的Java中的查找树和哈希表(一级)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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