<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

      Sparta Yew

         簡約、職業(yè)、恒久
    隨筆 - 15, 文章 - 1, 評論 - 276, 引用 - 0
    數(shù)據(jù)加載中……

    Java中Map相關的快速查找算法與唯一性探討


        sparta-紫杉  11/4/21 15:21


        在對《Set和hashCode()》的一篇原創(chuàng)文章寫完后,由于對自己的一些論斷產(chǎn)生了模糊和懷疑,因此又對Set進行了一些研究,形成本篇。

        在Set的使用場景中,我們不外乎看中了她存儲數(shù)據(jù)的唯一性,即不能存儲重復值,這在某些應用場合下是很必要的一個特性。那么從更深一層來考慮,Set究竟如何使數(shù)據(jù)不重復的呢? 從另一個層面來考慮,她又如何確保在驗證數(shù)據(jù)是否重復過程中的快速性呢? 假設存儲在Set中的數(shù)據(jù)有很多條,很普通的一個實現(xiàn)是每放入Set一個值value1,便提取Set中已有的多條數(shù)據(jù)跟該value1值進行對比,若相同,則不允許放入,反之則放入。運氣好的話,迭代到幾個元素之后便能夠判斷該值是否重復,否則,將會迭代所有已有的值。若是該Set中已經(jīng)存儲了上萬條的數(shù)據(jù),或者十幾萬條的數(shù)據(jù)?

        一篇網(wǎng)文《Set是如何實現(xiàn)沒有重復元素的?》一文給出了答案,該文內(nèi)容翔實,說理性強,論據(jù)充分,是一篇難得的好文,在此感謝作者。尤其它指出了在Set的實現(xiàn)中,使用了Map的key唯一性來確保Set的值不重復(眾所周知,Map中的key是唯一的),有興趣的可以去查看一下。

        那么,Map中的key又是如何確保重復驗證的快速性及key值的唯一性呢?

        放心,這難不倒聰明的java的創(chuàng)造者們。他們巧妙地利用了Hash算法來實現(xiàn)并達到這一目的。 那么Hash又是什么?

        Hash算法又稱為散列算法,其實Hash算法產(chǎn)生的目的很單純,其發(fā)明的目的是提高海量數(shù)據(jù)的查找速度。舉個實例更能說明問題:

        假設數(shù)據(jù)表中有N個無序的字符串(例如:中文人名),給你一個字符串,請迅速找到它在數(shù)據(jù)表中的序號。
    最笨的方法是逐個比較的方式來查找。查找時間是O(N),簡單說最后的情況是比較N次。

        hash 表能夠加快查找速度。使用hash表首先要申請一個定長的指針數(shù)組。通過在建立數(shù)據(jù)表時通過特定的計算公式(hash散列函數(shù))計算出每個字符串對應的一個數(shù)值(就是將不固定長度的字符串轉(zhuǎn)換成一個固定長度的數(shù)值或索引值)。而后把此數(shù)值作為數(shù)組下標,把此字符串在數(shù)據(jù)表的序號保存在此數(shù)組元素中(可以擴展到保存一個對象實例指針)。將來想查找某字符串對應位置時,只需要通過hash散列函數(shù)計算出字符串對應的值就可以直接知道此字符串的序號等信息了。
        這樣查找時間是O(1)了。因為不需要查找了,知道數(shù)組下標就能訪問數(shù)組相應元素了,而元素中保存的就是序號等信息。

         不妨給你一個直觀的比方吧:

        張三,給你個任務,你到山東省東營區(qū)去找一下一個叫做“李四”的人吧。張三很老實,說了聲是就走了,三個月后回來,終于找著了那個叫做李四的人。他后來跟我們說,他采用了遍歷的手法,即挨家挨戶的去問,去找。

        而將這個任務分配給王五的時候,王五說,老板,你給個確切的地址吧。老板說:山東省東營市東營區(qū)xx街道辦事處xx社區(qū)xx號。結果不到一天時間,王五便找著了。

        這也許就是hash查找算法與普通查找算法的區(qū)別。

        通過查看HashMap的源代碼證實,該HashMap確實采用了Hash算法來提高查找key的速度,并且使用了equals()來判斷是否重復,有代碼為證:

    hash:

        static int hash(int h) {
            h 
    ^= (h >>> 20^ (h >>> 12);
            
    return h ^ (h >>> 7^ (h >>> 4);
        }

    put:

         public V put(K key, V value) {
            
    if (key == null
                
    return putForNullKey(value);
            
    int hash = hash(key.hashCode());
            
    int i = indexFor(hash, table.length);
            
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                Object k;
                
    if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                    V oldValue 
    = e.value;
                    e.value 
    = value;
                    e.recordAccess(
    this);
                    
    return oldValue;
                }

            }


            modCount
    ++;
            addEntry(hash, key, value, i);
            
    return null;
        }


    HashMap的put原理是這樣的:
    1、首先對key采用hashCode()方法進行散列化,就是將key轉(zhuǎn)換生成一個int值,相同的key肯定會生成相同的int值,并對該int值進行hash計算得到hash值。
    2、通過hash值得到Entry數(shù)組的下標,然后通過該下標,得到已經(jīng)存入的數(shù)據(jù),將已經(jīng)存入的數(shù)據(jù)的key和hash進行比對,若相同證明是重復,則忽略。
    3、若不相同,則通過addentry()方法將數(shù)據(jù)存入該數(shù)組的下標中,同時存入的還有key、hash值。

    用一句話說來就是,通過待存入的key的hash值計算出數(shù)組的下標,并根據(jù)該下標提取已經(jīng)存入的值,將兩者進行比對,若相同則忽略,不同則put進去。

    現(xiàn)在知道為什么Map中的key是唯一性的原因了吧? 這與Map在put時兢兢業(yè)業(yè)檢查的努力是分不開的。

    假設有一個key為1,value為"zhangSan",經(jīng)過hash之后成為101,那么這個101就作為數(shù)組的下標,然后將hash=101、key=1及value="zhangSan"的值封裝成實體對象存放到該數(shù)組的101下標處。因為不同的key會產(chǎn)生不同的hash值,這也是為什么HashMap不排序的原因!

    get:

        public V get(Object key) {
            
    if (key == null)
                
    return getForNullKey();
            
    int hash = hash(key.hashCode());
            
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
                 e 
    != null;
                 e 
    = e.next) {
                Object k;
                
    if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                    
    return e.value;
            }

            
    return null;
        }


        那么通過key提取值時,當然先要通過該key計算出hash值來,再通過這個hash值作為下標提取出對應的實體對象所容納的value來。
    同時加了必要的判斷來確保提取出正確的數(shù)值來。

        哈哈,在一個確定的城市里,領到了一個確定的門牌號,相比在茫茫人海中漫無目的的撈針,知道為何提取數(shù)據(jù)如何之快了吧!



                -東營 sparta-紫杉 原創(chuàng),轉(zhuǎn)載請注明出處 :)
                http://www.tkk7.com/SpartaYew/
                SpartaYew@163.com
     
                
    QQ:22086526

    posted on 2011-05-18 16:15 sparta-紫杉 閱讀(2660) 評論(0)  編輯  收藏 所屬分類: Java

    主站蜘蛛池模板: 亚洲国产日韩在线视频| 国产zzjjzzjj视频全免费| 亚洲码国产精品高潮在线| 日韩在线观看免费完整版视频| 成人性生活免费视频| 亚洲精品免费网站| 最新仑乱免费视频| 亚洲第一综合天堂另类专| 日韩免费视频一区| 麻豆一区二区三区蜜桃免费| 国产精品免费视频一区| 香蕉97碰碰视频免费| 亚洲自偷自偷偷色无码中文| 成人网站免费看黄A站视频| 久久亚洲国产成人亚| 最近中文字幕免费完整| 亚洲黄页网在线观看| 精品久久久久久久免费人妻 | 亚洲youwu永久无码精品| 国产精品麻豆免费版| 全部在线播放免费毛片| 亚洲国产日韩在线视频| 久久久久国产精品免费网站| 亚洲一区二区三区深夜天堂| 成在人线AV无码免费| 午夜不卡AV免费| 亚洲天堂男人天堂| 日韩一区二区在线免费观看 | 在线观看免费毛片| 欧洲美女大片免费播放器视频 | 亚洲人成人网毛片在线播放| 四虎影院永久免费观看| 四虎影视无码永久免费| 亚洲国产视频一区| 亚洲国产精品一区二区第一页免| 在线看片免费人成视频播| 亚洲人成777在线播放| 亚洲Av无码国产情品久久| 三年片在线观看免费观看大全一| 亚洲中文字幕久久久一区| 久久久久亚洲爆乳少妇无|