數(shù)據(jù)結(jié)構(gòu)—散列表

algorithm

散列算法的作用是盡可能快地在數(shù)據(jù)結(jié)構(gòu)中找到一個值苍凛。通常在集合中獲取一個值的做法都是遍歷整個數(shù)據(jù)結(jié)構(gòu)來找到想要的值箍铭。如果用散列函數(shù)螟炫,就知道值的具體位置赁豆,所以很快就能檢索到想要的值仅醇。

hashTable 是經(jīng)常在 java 面試被問到的知識點,所以想要面試 java 開發(fā)可以準備一下看一下 hashTable 和 hashSet 的相關(guān)知識點魔种。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>散列表(Hash Table)</title>
    <link rel="stylesheet" href="index.css">
    <link rel="stylesheet" 
        integrity="sha384-nn4HPE8lTHyVtfCBi5yW9d20FjT8BJwUXyWZT9InLYax14RDjBj46LmSztkmNP9w" crossorigin="anonymous">
</head>

<body>
    <div class="wrapper">
        <table id="hashTable" class="pure-table">
            <thead>
                <tr>
                    <td>名稱</td>
                    <td>散列函數(shù)</td>
                    <td>散列值</td>
                    <td>散列表</td>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td></td>
                </tr>
            </tbody>
        </table>
    </div>
    <script src="demo.js"></script>
</body>

</html>

為了可視化 hash 表我做了一個 index.html 很簡單析二,最近也懶得寫 css 直接引用 pure.css 然后將我們生成散列表打印出來。

這方法很簡單但是很有效地將一個值的字母ASCII值相加作為查詢碼节预。

const tableEle = document.querySelector("#hashTable");
/**
 * 先創(chuàng)建
 * {key:string,hash:string,hashVal:number,value:string}
 */



 function createRow(obj){
    let rowElement = document.createElement("tr");

    let keyTrElement = document.createElement("td");
    keyTrElement.innerText=obj.key;
    let hashTrElement = document.createElement("td");
    hashTrElement.innerText = obj.hash;
    let hashValTrElement = document.createElement("td");
    hashValTrElement.innerText = obj.hashVal;
    let valueTrElement = document.createElement("td");
    valueTrElement.innerText = obj.value;

    rowElement.appendChild(keyTrElement);
    rowElement.appendChild(hashTrElement);
    rowElement.appendChild(hashValTrElement);
    rowElement.appendChild(valueTrElement);

    tableEle.appendChild(rowElement);

    return rowElement;

 }


function HashTable(){
    var table = [];

    this.put = function(key,value){
        var position = loseloseHashCode(key);
        console.log(position + ' - ' + key);
        table[position] = value;

        const obj = {
            key:key,
            hash:'',
            hashVal:position,
            value:value
        }

        createRow(obj);
        
    }

    this.get = function(key){
        return table[loseloseHashCode(key)]
    }

    this.remove = function(key){
        table[loseloseHashCode(key)] = undefined;
    }

    var loseloseHashCode = function(key){
        var hash = 0;
        for(var i = 0; i < key.length; i++){
            hash += key.charCodeAt(i);
        }

        return hash % 37;
    }
}

var tutHashTable = new HashTable();
tutHashTable.put('angular','javascript');
tutHashTable.put('spring','java');
tutHashTable.put('flask','python');


function showHashCode(key){
    var hash = 0;
    for(var i = 0; i < key.length; i++){
        hash += key.charCodeAt(i) + " - ";

    }
    console.log(key  + " -> " + hash);
    return hash % 35;
}

showHashCode('angular');
showHashCode('spring');
showHashCode('flask');

圖1

有時候叶摄,一些鍵會有相同的散列值。我們稱這種情況為沖突安拟。

tutHashTable.put('angular','javascript');
tutHashTable.put('spring','java');
tutHashTable.put('flask','python');
tutHashTable.put('react','reactjs')
tutHashTable.put('vue','vuejs')
tutHashTable.put('babylon','babylonjs')
tutHashTable.put('three','threejs')
tutHashTable.put('underscore','underscorejs')
tutHashTable.put('react-spring','reactspring');
tutHashTable.put('jquery','jqueryjs');
tutHashTable.put('call','string-query');

創(chuàng)建一個遍歷 hashTable 方法


圖2
    this.print = function(){
        for(let i = 0; i < table.length; ++i){
            if(table[i] !== undefined){
                console.log(i + ": " + table[i]);
            }
        }
    }

發(fā)現(xiàn) underscorejs 覆蓋掉了 reactjs 蛤吓,所有因為可能有相同hash值,也就是 hash 值沖突前面的值被后來值覆蓋掉了糠赦。我們怎么來解決這樣的問題呢会傲?


圖3

有幾種方法可以解決上面的問題: 分離鏈接、線性探查和雙散列法可以解決

分離鏈接

是為散列表的每一個位置創(chuàng)建一個鏈表并將元素保存在鏈表里面拙泽。

    var ValuePair = function(key, value){
        this.key = key;
        this.value = value;

        this.toString = function(){
            return `[ ${this.key} - ${this.value} ]`
        }
    }

我們引入 LinkedList

    <script src="linkedList.js"></script>
    <script src="demo.js"></script>
this.put = function(key,value){
        var position = loseloseHashCode(key);

        if(table[position] == undefined){
            table[position] = new LinkedList();
        }
        table[position].append(new ValuePair(key,value));

        const obj = {
            key:key,
            hash:'',
            hashVal:position,
            value:value
        }

        createRow(obj);
        
    }
    this.get = function(key){
        let position = loseloseHashCode(key);
        if(table[position] !== undefined){
            let current = table[position].getHead();
            while(current.next){
                if(current.element.key === key){
                    return current.element.value;
                }
                current = current.next;
            }
            if(current.element.key === key){
                return current.element.value;
            }
        }
        return undefined;
    }
  • 首先hash所對應(yīng)的鏈表是否存在淌山,如果不存在直接返回 undefined。
    this.remove = function(key){

        let position = loseloseHashCode(key);

        if(table[position] !== undefined){
            let current = table[position].getHead();
            while(current.next){
                if(current.element.key === key){
                    table[position].remove(current.element);
                    if(table[position].isEmpty()){
                        table[position] = undefined;
                    }
                    return true;
                }
                current = current.next;
            }

            if(current.element.key === key){
                table[position].remove(current.element);
                if(table[position].isEmpty()){
                    table[position] = undefined;
                }
                return true;
            }
        }

        return false;
    }

圖5
javascript

線性探索

另一種解決沖突的方法就是線性探索顾瞻。當(dāng)想要向表中某個位置加入一個新元素的時候艾岂,如果索引為 index 的位置已經(jīng)被占用,就向后順延 1 位保存數(shù)據(jù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末朋其,一起剝皮案震驚了整個濱河市王浴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梅猿,老刑警劉巖氓辣,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異袱蚓,居然都是意外死亡钞啸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門喇潘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來体斩,“玉大人,你說我怎么就攤上這事颖低⌒醭常” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵忱屑,是天一觀的道長蹬敲。 經(jīng)常有香客問我暇昂,道長,這世上最難降的妖魔是什么伴嗡? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任急波,我火速辦了婚禮,結(jié)果婚禮上瘪校,老公的妹妹穿的比我還像新娘澄暮。我一直安慰自己,他們只是感情好阱扬,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布赏寇。 她就那樣靜靜地躺著,像睡著了一般价认。 火紅的嫁衣襯著肌膚如雪嗅定。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天用踩,我揣著相機與錄音渠退,去河邊找鬼。 笑死脐彩,一個胖子當(dāng)著我的面吹牛碎乃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惠奸,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼梅誓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了佛南?” 一聲冷哼從身側(cè)響起梗掰,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嗅回,沒想到半個月后及穗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡绵载,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年埂陆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娃豹。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡焚虱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出懂版,到底是詐尸還是另有隱情鹃栽,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布定续,位于F島的核電站谍咆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏私股。R本人自食惡果不足惜摹察,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望倡鲸。 院中可真熱鬧供嚎,春花似錦、人聲如沸峭状。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽优床。三九已至劝赔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間胆敞,已是汗流浹背着帽。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留移层,地道東北人仍翰。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像观话,于是被迫代替她去往敵國和親予借。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容