為什麼是雜湊表?!

2021-09-01 20:22:55 字數 2802 閱讀 8630

為什麼是雜湊表?!

1、提出問題:

這裡有乙個大的跨國公司,公司中的職員資訊全部儲存在資料庫中。對於其中的任何乙個職員來說,他們的唯一標識就是員工號,而這個公司的員工號是按照職員工作的地點以及部門及工作開始時間確定的,比如01-20-09-24-3,這乙個職工編號(純屬杜撰,但也有實際作用,因為在像群體查詢時會比較方便等),其中的01代表亞洲辦公區員工,20表示在研發部門,09-24表示09年9月24號入職,3表示為當天入職的第三個人。這樣每乙個員工號就代表唯一的乙個員工,假如現在我們需要隨機抽取20000名員工搞乙個什麼活動,然後我們需要從資料庫取出20000個員工的資訊存在乙個地方,然後對員工資訊進行一系列的操作,無非增、刪、改、查,現在就會出現乙個問題,我們怎麼儲存這20000個員工的資訊,使得操作的時間更快?

我們會想到的是什麼,陣列?鍊錶?

如果是陣列,那我們怎麼根據乙個員工號來得到員工所在陣列的索引,快速返回相應的員工資訊呢?

如果是鍊錶,難道我們每次查詢時都要遍歷整個鍊錶嗎?如果員工數更多,這樣可行嗎?

由此就引出為什麼是雜湊表?

因為實際中會存在上述的問題,因此雜湊表應運而生,在大資料量中進行查詢,為了提高速度,我們會選擇陣列,因為如果知道資料在陣列中的索引,那麼時間複雜度就是o(1)的,但是對於實際中的這些問題,陣列的索引就不是那麼好得到的。比如就像上面那樣,知道員工號,來找資料,而員工號根本不是索引!所以我們需要根據員工號來生成索引,那麼我們給定乙個員工號,就會對應乙個索引,那麼就可以直接找到儲存的位置,這樣就很好了。

因此,上面最後所說的由員工號拿到陣列的索引的過程,就是乙個雜湊化過程。雜湊化過程:給定關鍵字,通過雜湊函式,生成確定的索引值。

2、給出上述問題的解決方法(一步步演示用雜湊表處理):

我們現在明確一下目標,就是根據職員號生成陣列索引,將職員資料存入陣列中,快速進行修改!

雜湊表的方法是什麼呢?

雜湊表的方法是,對於鍵值(這裡是職員號)給出乙個對映,將鍵值對映到確定的陣列索引上,每次查詢時,只需要輸入鍵值,然後根據對映找到索引就可以進行操作。因為鍵值的資料型別各式各樣,那麼這個對映也是五花八門,沒有固定的取法,但是對於這個對映最好滿足兩個要求:計算方便、產生的索引隨機性好!

這樣對映在雜湊表中稱為雜湊函式。對於上面的職員號,我們可以簡單的定義乙個雜湊函式為,對於上面的職員號轉化為整數,直接對於儲存陣列的大小進行取餘運算,通過這樣的方法來生成陣列索引。對於儲存的陣列一般選取的都會比要儲存的元素大,對於現在已知所需儲存資料的大小,經證明一般來說,當所儲存的資料是整個陣列的2/3時,效果比較好,因此我們的儲存陣列大小可以設定為30001,為什麼是30001呢?選取質數的原因與後面怎麼解決雜湊衝突有莫大的關係!

給出雜湊函式如下:

/**

* 根據key值,進行hash過程

* 其中的capacity為陣列容量大小

* @param key 傳進來的鍵值key

* @return 返回hash函式產生的陣列索引值

*/public int hash(string key)

那麼從上面很容易就會知道,這樣的雜湊函式,對於不同的鍵值可能產生相同的陣列索引值,這就是所謂的雜湊衝突。

一般來說,對於開放位址法,又可以分為:線性探測法、二次探測和再雜湊。(不要被名詞嚇著......其實都很簡單)

首先概述一下對於開放位址法的這三種方法的大體實現思想:

線性探測:當經過hash方法計算產生陣列索引後,如果發生衝突,那麼就檢查索引的下一位陣列是否空著,如果空著,那麼就將資料放置進去,如果沒有空著,則繼續向下一位進行檢測,知道將資料放入或是陣列已經放滿。示例**:

public void put(string key,clerk clerk)

clerkarray[index] = clerk;

}

二次探測:同樣的類似上面的線性探測,但是這次不是移向下一位,而是這樣移動,第乙個移動1^2位,如果非空,則繼續再移動2^2位,如果還是非空,那麼再移動3^2位,以此類推。

public void put(string key,clerk clerk)

clerkarray[index] = clerk;

}

再雜湊:對於上面兩種處理衝突的方法,只要是對映到同一索引位置,如果發生衝突,所有的衝突元素的移位步長都是相同的,所以為了避免這種情況,才會有了再雜湊這個方法,方法是,在衝突時,對於鍵值,再經過乙個hash方法的計算,來生成對於特定鍵值有特定步長,這樣即使是對映到同一索引位置放生衝突,但是對於不同的鍵值,處理衝突移動的步長會不同。

public void put(string key,clerk clerk)

clerkarray[index] = clerk;}

public int hashstep(string key)

也許我們會問,為什麼會有這三種方法呢?產生的原因是什麼呢?

產生這三個方法的原因是,在處理雜湊衝突的時候會引起聚焦(就是元素會聚集在發生衝突的地方,從而會影響雜湊表的效能),因此這三種方法依次減弱了這種聚焦效應。同時在這裡也可以解釋為什麼陣列的長度要選擇質數?如果不選擇質數,那麼總有乙個比原數小,而比1大的數整除這個長度,所以當我們按照我們選擇的步長去移動時,可能會出現整除陣列長度的情況,那麼這會使得移動跳過某些空位,而在固定的幾個位置上進行檢測,但是如果長度是質數,就會避免這種情況。

3、問題總結

現在我們可以由上面的結果,就可以實現我們自己的雜湊表了,因為上面已經描述了,如何進行雜湊化處理得到陣列索引,在得到索引衝突時,該如何處理衝突。然後剩下的工作就是圍繞這兩點展開的,來實現查詢,刪除或是新增等方法,在這裡就不再贅述了。

什麼是雜湊表

1 基本原理 我們使用乙個下標範圍比較大的陣列來儲存元素。可以設計乙個函式 雜湊函式,也叫做雜湊函式 使得每個元素的關鍵字都與乙個函式值 即陣列下標 相對應,於是用這個陣列單元來儲存這個元素 也可以簡單的理解為,按照關鍵字為每乙個元素 分類 然後將這個元素儲存在相應 類 所對應的地方。但是,不能夠保...

什麼是雜湊表

為什麼要用雜湊表?陣列的特點是 定址容易,插入和刪除困難 鍊錶的特點是 定址困難,插入和刪除容易 那麼能不能綜合兩者的特性,做出一種定址容易,插入和刪除也容易的資料結構?答案是肯定的,這就是我們要了解的雜湊表,也叫雜湊表 什麼是雜湊表?雜湊表也叫hash表 是根據關鍵碼值而進行直接進行訪問的資料結構...

雜湊表的大小為什麼最好是素數

我也是總結了這篇帖子的主要內容。首先在說明為什麼雜湊表的大小最好為素數之前,先說一下若大小取2的整數冪的問題,對於x mod m這樣的函式,m即為雜湊表的大小,其中的好壞應該取決於x的生成法師和m的值。比如乙個字串 abc 如果把字串當成乙個128進製的整數,寫成 abc 128 128 65 12...