演算法基礎 雜湊表 hash table 轉

2021-05-12 10:50:57 字數 1358 閱讀 8301

雜湊表(hash table)是比較常用的資料結構,它能提供接近常量時間複雜度的資料插入和查詢效能。雜湊表的本質是利用乙個雜湊函式(hash function)將乙個較大的取值範圍對映到乙個較小的取值範圍,從而一方面節省了儲存空間,另一方面又沒有失去隨機訪問的效能。

舉個簡單的例子,比如我們手裡有全班30個學生每個人的生日的資料**,我要求快速的找出某一天有沒有人,有哪些人過生日。最容易(或者說最笨)的 演算法是在**裡挨個查詢,看誰的生日和指定的日期一致,顯然這種演算法是線性時間複雜度的,換句話說平均所需要的時間和全班人數成正比。

如果想快一點怎麼辦呢?可以事先把所有同學的名字填到一張有365個格仔的大表裡,每格代表一年中的一天,這樣要知道某一天誰生日只要找到對應的格 子,那天過生日的同學名字就在裡面了。這個演算法是常量複雜度的,就是說不管全班有多少人,我都能在幾乎同樣的時間裡找到指定日期生日的人。

這樣就快多了,但是如果全班只有30個人,卻需要一張365格的大表顯然很浪費,絕大部分 格仔都是空著的,用計算機術語說就是太浪費記憶體。那麼怎樣能改進一些呢?實際上這張表可以只精確到月,也就是用12格來分別對應1~12月,同樣把所有同 學的名字按生日的月份填到表裡。這樣需要的儲存空間就小多了,而且平均每個格仔只有2~3人,查詢的效率並沒有低多少,仍然是接近常量時間。

當然,你可以說如果全班有100個人怎麼辦,每個月就會有接近10個人生日了,10個人裡找某一天生日的就慢的多了。的確,但是在這種情況下,你可 以把**擴張一些,比如變成每週對應一格,這樣就需要54格,每格還是不到兩個人。從年月日的日期轉換成周算起來可能比較麻煩,但是這種事交給計算機做, 算出是哪周和算出是哪月基本上沒什麼區別。

以上的例子中,把一年365天對映為12個月或者52周,這就是乙個雜湊函式。甚至最開始的365個格仔的對映也可以認為是一種極端的1:1的雜湊 函式。不同的輸入得到相同輸出的情況叫做雜湊衝突,比如上例中同乙個月或同一周生日的同學超過乙個。衡量乙個雜湊函式優劣的標準就是對映的結果在表中的位 置是否足夠隨機,也就是盡量避免雜湊衝突。當然這個標準是和輸入有關的,比如上面例子中同學們的生日如果是全年平均分布的,那麼按月或者按周對映就是乙個 很好的雜湊函式,但是實際情況下貌似有些月份生日的總是偏多,比如十月,十一月(難道是因為過年結婚的人多?),那麼取天數除以30或7取餘可能會更好。

還有一點要注意,應該保持雜湊表的尺寸與表裡的元素總數接近(稍多一些更好),這樣才能保證同乙個「格仔」裡的資料不會太多。所以一般來說隨著使用者 不斷新增資料,雜湊表需要按一定的比例擴張。擴張的時候需要把所有表裡的資料重新填到新的表裡,是開銷比較大的操作,所以不能太頻繁地擴張,最好每次擴張 把表多擴張一些;但是擴張太多又會浪費記憶體,所以需要找乙個合適的平衡點。在visual c++自帶的stl實現中,每次擴張到原來的兩倍大小。實際應用中如果你了解你將要填到雜湊表裡的資料的大致規模,也可以一開始就將表的大小設到指定值, 以便省去擴張的開銷。

Hash演算法與雜湊表基礎演算法

把乙個較大集合p對映到乙個較小集合q中,其中對映演算法位h,即q h p 每乙個p對應乙個q,乙個q可能對應多個p,這就是hash編碼的初步理解。其中雜湊表,可以認為是一種特殊的資料結構,有 q 個所謂的槽,儲存相應的q值,其中p中的元素出現,就在q中相對應的結果中進行記錄,對於不同p1,p2對應到...

演算法函式 左神演算法基礎 雜湊函式和雜湊表

筆者在讀研剛開始的時候,偶爾看面經,有這樣乙個問題 只用2gb內存在20億個整數中找到出現次數最多的數,當時的我一臉懵逼,怎麼去思考,20億個數?what the 但是,看完今天的文章,你或許就會覺得原來也不過如此啊!其核心就是雜湊函式和雜湊表的應用!雜湊函式又稱為雜湊函式,就是把任意長度的輸入 又...

雜湊表演算法

雜湊表是種資料結構,它可以提供快速的插入操作和查詢操作。第一次接觸雜湊表時,它的優點多得讓人難以置信。不論雜湊表中有多少資料,插入和刪除 有時包括側除 只需要接近常量的時間即0 1 的時間級。實際上,這只需要幾條機器指令。對雜湊表的使用者一一人來說,這是一瞬間的事。雜湊表運算得非常快,在電腦程式中,...