最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java深入了解數(shù)據(jù)結(jié)構(gòu)之哈希表篇

 更新時間:2022年01月27日 14:53:19   作者:/少司命  
哈希表是一種根據(jù)關(guān)鍵碼去尋找值的數(shù)據(jù)映射結(jié)構(gòu),該結(jié)構(gòu)通過把關(guān)鍵碼映射的位置去尋找存放值的地方,說起來可能感覺有點復(fù)雜,我想我舉個例子你就會明白了,最典型的的例子就是字典

1,概念

順序結(jié)構(gòu)以及平衡樹中,元素關(guān)鍵碼與其存儲位置之間沒有對應(yīng)的關(guān)系,因此在查找一個元素時,必須要經(jīng)過關(guān)鍵 碼的多次比較。順序查找時間復(fù)雜度為O(N),平衡樹中為樹的高度,即O( ),搜索的效率取決于搜索過程中 元素的比較次數(shù)。

理想的搜索方法:可以不經(jīng)過任何比較,一次直接從表中得到要搜索的元素。 如果構(gòu)造一種存儲結(jié)構(gòu),通過某種函 數(shù)(hashFunc)使元素的存儲位置與它的關(guān)鍵碼之間能夠建立一一映射的關(guān)系,那么在查找時通過該函數(shù)可以很快找到該元素。

當(dāng)向該結(jié)構(gòu)中:

插入元素

根據(jù)待插入元素的關(guān)鍵碼,以此函數(shù)計算出該元素的存儲位置并按此位置進(jìn)行存放

搜索元素

對元素的關(guān)鍵碼進(jìn)行同樣的計算,把求得的函數(shù)值當(dāng)做元素的存儲位置,在結(jié)構(gòu)中按此位置取元素比較,若關(guān)鍵碼相等,則搜索成功

例如:數(shù)據(jù)集合{1,7,6,4,5,9};

哈希函數(shù)設(shè)置為:hash(key) = key % capacity; capacity為存儲元素底層空間總的大小。

2,沖突-避免

首先,我們需要明確一點,由于我們哈希表底層數(shù)組的容量往往是小于實際要存儲的關(guān)鍵字的數(shù)量的,這就導(dǎo)致一 個問題,沖突的發(fā)生是必然的,但我們能做的應(yīng)該是盡量的降低沖突率。

3,沖突-避免-哈希函數(shù)設(shè)計

常見哈希函數(shù)

直接定制法--(常用)

取關(guān)鍵字的某個線性函數(shù)為散列地址:Hash(Key)= A*Key + B 優(yōu)點:簡單、均勻 缺點:需要事先知道關(guān) 鍵字的分布情況 使用場景:適合查找比較小且連續(xù)的情況

除留余數(shù)法--(常用)

設(shè)散列表中允許的地址數(shù)為m,取一個不大于m,但最接近或者等于m的質(zhì)數(shù)p作為除數(shù),按照哈希函數(shù): Hash(key) = key% p(p<=m),將關(guān)鍵碼轉(zhuǎn)換成哈希地址

平方取中法--(了解)

假設(shè)關(guān)鍵字為1234,對它平方就是1522756,抽取中間的3位227作為哈希地址; 再比如關(guān)鍵字為4321,對 它平方就是18671041,抽取中間的3位671(或710)作為哈希地址 平方取中法比較適合:不知道關(guān)鍵字的分 布,而位數(shù)又不是很大的情況

4,沖突-避免-負(fù)載因子調(diào)節(jié)

?負(fù)載因子和沖突率的關(guān)系粗略演示

所以當(dāng)沖突率達(dá)到一個無法忍受的程度時,我們需要通過降低負(fù)載因子來變相的降低沖突率。 、已知哈希表中已有的關(guān)鍵字個數(shù)是不可變的,那我們能調(diào)整的就只有哈希表中的數(shù)組的大小。

5,沖突-解決-閉散列

閉散列:也叫開放定址法,當(dāng)發(fā)生哈希沖突時,如果哈希表未被裝滿,說明在哈希表中必然還有空位置,那么可以 把key存放到?jīng)_突位置中的“下一個” 空位置中去。

①線性探測

比如上面的場景,現(xiàn)在需要插入元素44,先通過哈希函數(shù)計算哈希地址,下標(biāo)為4,因此44理論上應(yīng)該插在該 位置,但是該位置已經(jīng)放了值為4的元素,即發(fā)生哈希沖突。 線性探測:從發(fā)生沖突的位置開始,依次向后探測,直到尋找到下一個空位置為止。

插入

通過哈希函數(shù)獲取待插入元素在哈希表中的位置 如果該位置中沒有元素則直接插入新元素,如果該位置中有元素發(fā)生哈希沖突,使用線性探測找到 下一個空位置,插入新元素

采用閉散列處理哈希沖突時,不能隨便物理刪除哈希表中已有的元素,若直接刪除元素會影響其他 元素的搜索。比如刪除元素4,如果直接刪除掉,44查找起來可能會受影響。因此線性探測采用標(biāo) 記的偽刪除法來刪除一個元素。

②二次探測

線性探測的缺陷是產(chǎn)生沖突的數(shù)據(jù)堆積在一塊,這與其找下一個空位置有關(guān)系,因為找空位置的方式就是挨 著往后逐個去找,因此二次探測為了避免該問題,找下一個空位置的方法為: = ( + )% m, 或者: = ( - )% m。其中:i = 1,2,3…, 是通過散列函數(shù)Hash(x)對元素的關(guān)鍵碼 key 進(jìn)行計算得到的位置, m是表的大小。 對于2.1中如果要插入44,產(chǎn)生沖突,使用解決后的情況為:

研究表明:當(dāng)表的長度為質(zhì)數(shù)且表裝載因子a不超過0.5時,新的表項一定能夠插入,而且任何一個位置都不 會被探查兩次。因此只要表中有一半的空位置,就不會存在表滿的問題。在搜索時可以不考慮表裝滿的情 況,但在插入時必須確保表的裝載因子a不超過0.5,如果超出必須考慮增容。

6,沖突-解決-開散列/哈希桶

開散列法又叫鏈地址法(開鏈法),首先對關(guān)鍵碼集合用散列函數(shù)計算散列地址,具有相同地址的關(guān)鍵碼歸于同一子 集合,每一個子集合稱為一個桶,各個桶中的元素通過一個單鏈表鏈接起來,各鏈表的頭結(jié)點存儲在哈希表中。

 
     static class Node {
         public int key;
         public int val;
         public Node next;
 
         public Node(int key, int val) {
             this.key = key;
             this.val = val;
         }
     }
 
     private Node[] array;
     public int usedSize;
 
     public HashBucket() {
         this.array = new Node[10];
         this.usedSize = 0;
     }

 public void put(int key,int val){
        int index = key % this.array.length;
        Node cur = array[index];
        while (cur != null){
            if(cur.val == key){
                cur.val = val;
                return;
            }
            cur = cur.next;
        }
        //頭插法
         Node node = new Node(key,val);
        node.next = array[index];
        array[index] = node;
        this.usedSize++;
        if(loadFactor() >= 0.75){
            resize();
        }
    }
public int get(int key) {
         //以什么方式存儲的  那就以什么方式取
         int index = key % this.array.length;
         Node cur = array[index];
         while (cur != null) {
             if(cur.key == key) {
                 return cur.val;
             }
             cur = cur.next;
         }
         return -1;//
     }

public void resize(){
 
        Node[] newArray = new Node[2*this.array.length];
        for (int i = 0; i < this.array.length; i++){
            Node cur = array[i];
            Node curNext = null;
            while (cur != null){
 
                curNext = cur.next;
                int index = cur.key % newArray.length;
                cur.next = newArray[i];
                newArray[i] = cur;
                cur = curNext.next;
                cur = curNext;
 
            }
        }
        this.array = newArray;
    }

7,完整代碼

 class HashBucket {
 
     static class Node {
         public int key;
         public int val;
         public Node next;
 
         public Node(int key, int val) {
             this.key = key;
             this.val = val;
         }
     }
 
     private Node[] array;
     public int usedSize;
 
     public HashBucket() {
         this.array = new Node[10];
         this.usedSize = 0;
     }
 
     public void put(int key,int val) {
         //1、確定下標(biāo)
         int index = key % this.array.length;
         //2、遍歷這個下標(biāo)的鏈表
         Node cur = array[index];
         while (cur != null) {
             //更新val
             if(cur.key == key) {
                 cur.val = val;
                 return;
             }
             cur = cur.next;
         }
         //3、cur == null   當(dāng)前數(shù)組下標(biāo)的 鏈表  沒要key
         Node node = new Node(key,val);
         node.next = array[index];
         array[index] = node;
         this.usedSize++;
         //4、判斷  當(dāng)前 有沒有超過負(fù)載因子
         if(loadFactor() >= 0.75) {
             //擴(kuò)容
             resize();
         }
     }
 
     public int get(int key) {
         //以什么方式存儲的  那就以什么方式取
         int index = key % this.array.length;
         Node cur = array[index];
         while (cur != null) {
             if(cur.key == key) {
                 return cur.val;
             }
             cur = cur.next;
         }
         return -1;//
     }
 
 
     public double loadFactor() {
         return this.usedSize*1.0 / this.array.length;
     }
 
 
 
    public void resize(){
 
        Node[] newArray = new Node[2*this.array.length];
        for (int i = 0; i < this.array.length; i++){
            Node cur = array[i];
            Node curNext = null;
            while (cur != null){
 
                curNext = cur.next;
                int index = cur.key % newArray.length;
                cur.next = newArray[i];
                newArray[i] = cur;
                cur = curNext.next;
                cur = curNext;
 
            }
        }
        this.array = newArray;
    }
 
 
}

到此這篇關(guān)于Java深入了解數(shù)據(jù)結(jié)構(gòu)之哈希表篇的文章就介紹到這了,更多相關(guān)Java 哈希表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何優(yōu)雅的進(jìn)行Spring整合MongoDB詳解

    如何優(yōu)雅的進(jìn)行Spring整合MongoDB詳解

    這篇文章主要給大家介紹了如何優(yōu)雅的進(jìn)行Spring整合MongoDB的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-02-02
  • SpringBoot+Netty實現(xiàn)簡單聊天室的示例代碼

    SpringBoot+Netty實現(xiàn)簡單聊天室的示例代碼

    這篇文章主要介紹了如何利用SpringBoot Netty實現(xiàn)簡單聊天室,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)SpringBoot有一定幫助,感興趣的同學(xué)可以了解一下
    2022-02-02
  • SpringCloud Bus如何實現(xiàn)配置刷新

    SpringCloud Bus如何實現(xiàn)配置刷新

    這篇文章主要介紹了SpringCloud Bus如何實現(xiàn)配置刷新,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • flutter?TabBarView?動態(tài)添加刪除頁面的示例代碼

    flutter?TabBarView?動態(tài)添加刪除頁面的示例代碼

    在Flutter中使用TabBarView動態(tài)添加和刪除頁面時,如果未為每個頁面設(shè)置唯一的key,會導(dǎo)致刪除頁面時出現(xiàn)狀態(tài)錯誤或刪除錯誤的頁面,正確的做法是為每個頁面指定全局唯一的key,這樣可以確保頁面在添加和刪除時狀態(tài)正確,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • springboot 2.0 mybatis mapper-locations掃描多個路徑的實現(xiàn)

    springboot 2.0 mybatis mapper-locations掃描多個路徑的實現(xiàn)

    這篇文章主要介紹了springboot 2.0 mybatis mapper-locations掃描多個路徑的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 詳解Java中使用泛型實現(xiàn)快速排序算法的方法

    詳解Java中使用泛型實現(xiàn)快速排序算法的方法

    這篇文章主要介紹了Java中使用泛型實現(xiàn)快速排序算法的方法,快速排序的平均時間復(fù)雜度為(n\log n),文中的方法立足于基礎(chǔ)而并沒有考慮優(yōu)化處理,需要的朋友可以參考下
    2016-05-05
  • 初探Java內(nèi)部類的使用

    初探Java內(nèi)部類的使用

    Java內(nèi)部類一般可以分為以下三種:成員內(nèi)部類、靜態(tài)內(nèi)部類和匿名內(nèi)部類。這篇文章主要帶大家初探一下Java內(nèi)部類的使用,感興趣的可以了解一下
    2022-09-09
  • 五分鐘解鎖springboot admin監(jiān)控新技巧

    五分鐘解鎖springboot admin監(jiān)控新技巧

    本文不會講如何搭建企業(yè)的運(yùn)維監(jiān)控系統(tǒng),有興趣的可以去找找成熟的比如Zabbix、Prometheus,甚至比較簡單的Wgcloud都能滿足一定的需求,不在此贅述。本文講解如何使用Springboot admin對spring boot項目進(jìn)行應(yīng)用監(jiān)控,感興趣的朋友一起看看吧
    2021-06-06
  • java1.5中訪問環(huán)境變量

    java1.5中訪問環(huán)境變量

    這篇文章主要介紹了如何在java1.5中訪問環(huán)境變量,使用System.getenv()可以訪問環(huán)境變量
    2014-01-01
  • Java基本類型與byte數(shù)組之間相互轉(zhuǎn)換方法

    Java基本類型與byte數(shù)組之間相互轉(zhuǎn)換方法

    下面小編就為大家?guī)硪黄狫ava基本類型與byte數(shù)組之間相互轉(zhuǎn)換方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08

最新評論

山阴县| 阜康市| 尚义县| 冷水江市| 大关县| 嫩江县| 舒兰市| 罗甸县| 和田县| 沭阳县| 无极县| 甘南县| 青浦区| 达拉特旗| 穆棱市| 呼伦贝尔市| 文登市| 黄大仙区| 长葛市| 绵竹市| 吉隆县| 雅江县| 增城市| 靖江市| 巴马| 个旧市| 滁州市| 石棉县| 松原市| 革吉县| 桐城市| 晋宁县| 呼伦贝尔市| 沙湾县| 阿拉善盟| 红原县| 恭城| 囊谦县| 西贡区| 阿克陶县| 鹿泉市|