當一組資料項的排列是無序時,我們就用順序查詢;當資料項是有序時,我們可以用二分查詢法來降低演算法複雜度,從順序查詢法的o(n),降低到二分查詢法的o(log n),從而實現更高效的查詢。
那麼問題來了,我們能否進一步降低查詢的演算法複雜度呢?
答案是,能。
現在,我們進一步構造乙個新的資料結構,能使得查詢演算法的複雜度降低到o(1),也就是常數級別。實現的這種概念就是雜湊(hashing)。
雜湊(hashing)
要使得查詢的次數降低到常數級別,先要對資料項所處的位置有更多的先驗知識——如果事先能知道要找的資料項應該出現在資料集裡的什麼位置,就可以直接到那個位置檢視資料項是否存在即可。 由資料項的值來確定其存放位置,如何能做到這一點呢?
雜湊表(hash table,又稱雜湊表)就是我們的答案。
雜湊表,是一種資料集,其中資料項的儲存方式尤其有利於將來快速的查詢定位。
雜湊表中的每乙個儲存位置,稱為槽(slot),是用來儲存資料項的。每個槽都有唯一的名稱。
實現從資料項到儲存槽名稱轉換的,稱為雜湊函式(hash function)。
乙個雜湊的示例
下面示例中,雜湊函式接受資料項作為引數,返回整數值0~10,表示資料項儲存的槽號(名稱)。 假設我們有這麼一些資料項:
54, 26, 93, 17, 77, 31
有一種常用的雜湊方法「求餘數」,將資料項除以雜湊表的大小,得到的餘數作為槽號。
實際上「求餘數」方法會以不同形式出現在所有的雜湊函式裡。
因為雜湊函式返回的槽號必須在雜湊表大小範圍之內,所以一般會對雜湊表大小求餘。
在我們的這個示例中,因為槽號的下標是0~10,一共11個槽,所以雜湊函式是最簡單的求餘:
h(item) = item % 11
按照雜湊函式h(item),為每個資料項計算出存放的位置之後,就可以將資料項存入相應的槽中。如下表所示:
item hash value
54 10
26 4
93 5
17 6
77 0
31 9
可以看到,示例中的6個資料項各自佔據了1個槽,也就是6個資料項一共佔據了11個槽中的6個。這種槽被資料項佔據的比例稱為雜湊表的「負載因子」。本例中的負載因子是6/11。
我們把資料項都儲存在雜湊表中之後,查詢就非常簡單了。
如果要查詢某個資料項是否存在於表中,我們需要使用同乙個雜湊函式,對查詢項進行計算,測試下返回的槽號所對應的槽中是否有資料項即可。
如此,我們便實現了複雜度為o(1)的查詢演算法。
雜湊表查詢方法的劣勢
上述例子雖然實現了o(1)複雜度的查詢演算法,但是,我們注意到,示例比較特殊,6個資料項佔據了6個槽,也就是每個槽只有1個獨一無二的資料項。
那麼問題來了,如果再增加1個資料項,比如44,h(44)=0,就造成了#0槽有兩個資料項,7個資料項只佔據了6個槽的情況,即有乙個槽有2個不同的資料項。這種情況稱為衝突(collision)。
關於衝突的情況,我們後面再討論其解決方案。
資料結構與演算法 查詢與排序
參考 線性查詢 二分查詢 氣泡排序 插入排序 選擇排序 快速排序 歸併排序 逐個查詢要查詢的物件 include typedef char datatype int mysearch datatype ts,int n,const datatype d int main printf d n mys...
資料結構與演算法(九) 查詢與排序
打卡第九天 快速排序 c 異常處理沒有搞定 lll 排序陣列本身就是陣列旋轉的乙個特例。在對陣列進行排序或查詢時,要注意陣列中有相同數字的特例,比如下面的旋轉陣列的時候 查詢 順序查詢 二分查詢 雜湊表查詢 二叉排序查詢 排序 插入排序 氣泡排序 歸併排序 快速排序 實現快速排序演算法的關鍵在於先在...
Python 資料結構與演算法 查詢與排序
查詢和排序是最基本的演算法,在很多指令碼中都會用到查詢和排序。儘管 python 提供的用於查詢和排序的函式能夠滿足絕大多數需求,但還是有必要了解最基本的查詢和排序演算法,以便在有特殊需求的情況下,可以自己編寫查詢 排序指令碼。基本的查詢方法有順序查詢 二分查詢和分塊查詢等。其中,順序查詢是最簡單的...