散列表

什么散列

散列是提供對(duì)任何有名項(xiàng)提供存取操作和刪除操作的列表萤衰。這種結(jié)構(gòu)的目的是提供常數(shù)時(shí)間的基本操作阎肝。

舉個(gè)例子:如果所有元素都是16-bits且不帶正負(fù)號(hào)的整數(shù),范圍是0-65535凑阶。那么簡(jiǎn)單運(yùn)用一個(gè) array 就可以滿足上面的期望稻据。首先配置一個(gè)arrayA.,擁有65536個(gè)元素衬鱼,初值全部為0业筏,每個(gè)元素值代表相應(yīng)元素出現(xiàn)的次數(shù)。如果插入元素i馁启,就執(zhí)行A[i]++驾孔,如果刪除元素i,就執(zhí)行A[i]--惯疙,如果搜素元素就檢查A[i]是否為0翠勉。以上的每一個(gè)操作都是常數(shù)時(shí)間。這種解法的額外負(fù)擔(dān)是array的空間和初始化時(shí)間霉颠。

繪圖1.jpg

但是這種解法存在2個(gè)現(xiàn)實(shí)的問題:

  • 如果元素很多对碌,那么要準(zhǔn)備的數(shù)組大小就很大,空間占用太大蒿偎。
  • 如果元素是其他的類型(非整型)朽们,那么就不能作為數(shù)組索引。

第一個(gè)問題:
我們是可以采用一個(gè)映射函數(shù)诉位,將大數(shù)轉(zhuǎn)換為小數(shù)骑脱,比如給定整數(shù)x,那么
x % array.size()苍糠,那么就會(huì)得到一個(gè)范圍在 [ 0叁丧,array.size() - 1 ] 之間的數(shù),也可以作為數(shù)組索引岳瞭,但這會(huì)引入新的問題:如何解決碰撞沖突的問題拥娄。

第二個(gè)問題:
我們可以將一個(gè)非整數(shù)類型的轉(zhuǎn)換為整型,比如字符串"string"瞳筏,轉(zhuǎn)換為ASCII編碼稚瘾。

線性探測(cè)

當(dāng)用散列函數(shù)計(jì)算出元素的插入位置,而該位置已經(jīng)不能使用時(shí)姚炕,最簡(jiǎn)單的辦法就是循序往下一一尋找摊欠,直到找到一個(gè)可用的位置為止。
元素的刪除則可以采用"惰性刪除"钻心,也就是標(biāo)記刪除記號(hào)凄硼,實(shí)際刪除則待散列表重新整理時(shí)再進(jìn)行。

線性探測(cè).jpg

但線性探測(cè)會(huì)有一個(gè)不好的現(xiàn)象是:如圖最后狀態(tài)中捷沸,除非元素進(jìn)過散列函數(shù)計(jì)算之后直接得出位置在#4 ~ #7摊沉,否則#4 ~ #7永遠(yuǎn)不可能會(huì)被優(yōu)先考慮,因?yàn)?8 9 0 1 2已被占痒给,遇到?jīng)_突會(huì)線性巡訪整個(gè)表格) #3一直會(huì)被優(yōu)先考慮说墨。
這樣會(huì)暴露出一個(gè)問題:主集團(tuán)(primary clustering)陷阱骏全。散列表中是一大團(tuán)被用過的方格,插入操作極有可能在主集團(tuán)所形成的泥濘中奮力爬行尼斧,不斷解決碰撞問題姜贡,最后再找到空位置。然而插入之后又助長(zhǎng)了主集團(tuán)的長(zhǎng)度棺棵。

public class LinearProbingHashST<Key, Value> {
    private int n;            // 當(dāng)前key-value元素對(duì)數(shù)
    private int m;            // 線性表(key-value)的總長(zhǎng)度
    private Key[] keys;     // the keys
    private Value[] vals;   // the values

    public void put(Key key, Value val) {
        .....省略參數(shù)的有效性判斷
        // 如果已經(jīng)用掉50%楼咳,則擴(kuò)容,減小主集團(tuán)的影響
        if (n >= m / 2)
          resize(2 * m);      // resize里面會(huì)重新計(jì)算散列值烛恤,插入元素
    
        // 線性探測(cè)過程
        for (int i = hash(key); keys[i] != null; i = (i + 1) % m) {
            // 如果已經(jīng)存在key母怜,則更新value
            if (keys[i].equals(key)) {
                vals[i] = val;
                    return;
            }
        }
        keys[i] = key;
        vals[i] = val;
        n++;
    }
    
    public void delete(Key key) {
        ...... 省略參數(shù)有效性判斷
        // find position i of key
        int i = hash(key);
        while (!key.equals(keys[i]))
            i = (i + 1) % m;
        
      // delete key and associated value
        keys[i] = null;
        vals[i] = null;

        // rehash all keys in same cluster
        i = (i + 1) % m;
        while (keys[i] != null) {
            // delete keys[i] an vals[i] and reinsert
            Key keyToRehash = keys[i];
            Value valToRehash = vals[i];
            keys[i] = null;
            vals[i] = null;
            n--;
            put(keyToRehash, valToRehash);
            i = (i + 1) % m;
        }
        n--;
        // halves size of array if it's 12.5% full or less
        if (n > 0 && n <= m / 8)
            resize(m / 2);
    }
}

二次探測(cè)

二次探測(cè)主要用于解決主集團(tuán)的問題。
其命名由來是因?yàn)榻鉀Q碰撞的方程式:F(i) = i^2是一個(gè)二次方程式缚柏。更明確的說苹熏,如果散列函數(shù)計(jì)算出新元素位置H,而該位置實(shí)際上已經(jīng)被使用币喧,那么我們就依次嘗試H+12轨域,H+22,H+3^2......而不是像線性探測(cè)一樣依序嘗試:H+1杀餐,H+2干发,H+3.......

二次探測(cè).jpg

二次探測(cè)可以消除主集團(tuán),但卻可能造成次集團(tuán):兩個(gè)元素經(jīng)散列函數(shù)計(jì)算出來的位置若相同史翘,那么插入時(shí)所探測(cè)的位置也相同铐然,形成某種浪費(fèi)。

但總體來說恶座,還是二次探測(cè)相比于線性探測(cè),仍然值得選擇沥阳。

開鏈法

開鏈法是在每一個(gè)表格元素中維護(hù)一個(gè)list跨琳,散列函數(shù)分配某一個(gè)list,然后再那個(gè)list身上執(zhí)行元素的插入桐罕,搜尋脉让,刪除等操作。雖然針對(duì)list是一種線性搜索功炮,但list夠短溅潜。速度還是很快。

開鏈法jpg

散列函數(shù)


參考資料
[1] 《STL源碼剖析》侯捷
[2] 《算法》4th [美] Robert Sedgewick薪伏,Kevin Wayne

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末滚澜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嫁怀,更是在濱河造成了極大的恐慌设捐,老刑警劉巖借浊,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異萝招,居然都是意外死亡蚂斤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門槐沼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來曙蒸,“玉大人,你說我怎么就攤上這事岗钩∨撸” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵凹嘲,是天一觀的道長(zhǎng)师倔。 經(jīng)常有香客問我,道長(zhǎng)周蹭,這世上最難降的妖魔是什么趋艘? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮凶朗,結(jié)果婚禮上瓷胧,老公的妹妹穿的比我還像新娘。我一直安慰自己棚愤,他們只是感情好搓萧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宛畦,像睡著了一般瘸洛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上次和,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天反肋,我揣著相機(jī)與錄音,去河邊找鬼踏施。 笑死石蔗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的畅形。 我是一名探鬼主播养距,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼日熬!你這毒婦竟也來了棍厌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎定铜,沒想到半個(gè)月后阳液,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揣炕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年帘皿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畸陡。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鹰溜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丁恭,到底是詐尸還是另有隱情曹动,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布牲览,位于F島的核電站墓陈,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏第献。R本人自食惡果不足惜贡必,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庸毫。 院中可真熱鬧仔拟,春花似錦、人聲如沸飒赃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽载佳。三九已至炒事,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蔫慧,已是汗流浹背羡洛。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留藕漱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓崭闲,卻偏偏與公主長(zhǎng)得像肋联,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子刁俭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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

  • 數(shù)據(jù)結(jié)構(gòu)與算法--散列表 之前學(xué)習(xí)了基于鏈表的順序查找橄仍、基于有序數(shù)組的二分查找、二叉查找樹、紅黑樹侮繁,這些算法在查找...
    sunhaiyu閱讀 647評(píng)論 3 5
  • 散列表是支持 INSERT 虑粥、DELETE 和 SEARCH 的字典操作,其是對(duì)普通數(shù)組概念的推廣宪哩,因?yàn)榭梢詫?duì)數(shù)組...
    點(diǎn)融黑幫閱讀 855評(píng)論 0 11
  • 本文主要介紹散列表(Hash Table)這一常見數(shù)據(jù)結(jié)構(gòu)的原理與實(shí)現(xiàn)娩贷。由于個(gè)人水平有限,文章中難免存在不準(zhǔn)確或是...
    absfree閱讀 16,282評(píng)論 2 35
  • 什么是哈希表锁孟? 哈希表(Hash table彬祖,也叫散列表),是根據(jù)關(guān)鍵碼值(Key value)而直接進(jìn)行訪問的數(shù)...
    郝程序猿閱讀 2,232評(píng)論 1 7
  • 概念 散列表的實(shí)現(xiàn)常常叫做散列(hashing)品抽。散列是一種用于以常數(shù)平均時(shí)間執(zhí)行插入储笑、刪除和查找的技術(shù)。散列函數(shù)...
    NoFacePeace閱讀 324評(píng)論 0 0