1. 程式人生 > >使用雜湊錶快速查詢字串的一種解決方案

使用雜湊錶快速查詢字串的一種解決方案

必備知識:
什麼是雜湊表?
雜湊表(Hash table,也叫散列表),是根據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。
雜湊表hashtable(key,value) 的做法其實很簡單,就是把Key通過一個固定的演算法函式既所謂的雜湊函式轉換成一個整型數字,然後就將該數字對陣列長度進行取餘,取餘結果就當作陣列的下標,將value儲存在以該數字為下標的陣列空間裡。
而當使用雜湊表進行查詢的時候,就是再次使用雜湊函式將key轉換為對應的陣列下標,並定位到該空間獲取value,如此一來,就可以充分利用到陣列的定位效能進行資料定位

以上即為雜湊表的基礎知識。需要指出的是,當資料量過大時,很容易發生碰撞問題,即不同的字串生成的雜湊值,對資料長度取模後得到同樣的陣列下標。此時必須要進行碰撞處理。
常規的碰撞處理方式有兩種,第一種是開放定址法,第二種是拉鍊定址法點選檢視詳細處理過程
兩種方式均有利弊,簡單的說:
- 開放定址法需要找到合適的定址探測方案,但是不管是線性遞增方式還是隨機數方式,很容易產生堆積現象,從而導致插入和查詢效能下降。
- 拉鍊定址法則較為簡單,但是當碰撞較多時,需要動態申請額外較多的記憶體塊來構建連結串列。

本方案結合以上兩種方式的特點,分三步建立完成一個雜湊表,具體過程如下圖所示:
雜湊表建立過程


簡要說明:
- 第一步:由雜湊函式生成的雜湊值與總儲存量進行求模,所得結果A即為該資料在雜湊表中的位置。如果該位置為空,則將該資料的MD5值填入此處,但是由於資料碰撞,不同資料的雜湊值可能會得到相同的A值,此時僅將碰撞次數加1,直至迴圈結束。
- 第二步:根據第一步得到的碰撞次數,申請同等長度的快取空間Buffer。在第二次迴圈中,按序迴圈,依次檢查每一處是否為空,如果為空,將此位置下標B記錄到快取空間Buffer中,直至迴圈結束。
- 進行第三次迴圈,如果A處已存在資料,則從Buffer中按序摘取一個下標B,將該資料的MD5值與原始檔案下標值填入此處,然後再將下標B插入到A處資訊的指標域,以此形成連結串列結構。

示例虛擬碼如下:

int iHitCnt = 0;//碰撞次數
for(UINT jj = 0;jj < 3;jj++)
{
    for(UINT ii = 0;ii< nTotal;ii++)
    {
        if (jj == 1)
        {
            if(strlen(mp_HashPtr[ii].chMD5) == 0)
            {   
                if (pp >= iHitCnt)
                {//雜湊表公共溢位區空間不足
                    delete []pFreeOffSet;
                    delete []mp_HashPtr;
                    return FALSE;
                }
                pFreeOffSet[pp++] = ii;
            }
        }
        else
        {
            HashA = HashStringA(/*傳入字串*/);
            pMD5 = MD5(/*傳入字串*/);
            iHashPos = HashA % nTotal;//雜湊值A做下標
            //填充到雜湊表中
            if (strlen(mp_HashPtr[iHashPos].chMD5) != 0)
            {
                if (jj == 0)
                {//第一次迴圈僅統計發生碰撞的次數
                    iHitCnt++;
                }
                else
                {
                    if (pp >= iHitCnt)
                    {//超出公共溢位區長度
                        delete []mp_HashPtr;
                        delete []pFreeOffSet;
                        return FALSE;
                    }
                    PHASHSTRUCT pNewHashSt = mp_HashPtr + pFreeOffSet[pp];//從公共溢位區摘一個空白的區域,並將其加入到連結串列中
                    memcpy(pNewHashSt->chMD5,pMD5,MD5_LENGTH);
                    pNewHashSt->NextOffset = mp_HashPtr[iHashPos].NextOffset;
                    mp_HashPtr[iHashPos].NextOffset = pFreeOffSet[pp];
                    pp++;
                }
            }
            else
            {//第一遍時如果該位置沒有資料則會被填充
                memcpy(mp_HashPtr[iHashPos].chMD5,pMD5,MD5_LENGTH);
                mp_HashPtr[iHashPos].NextOffset = 0;
            }
        }
    }
    if (jj == 0)
    {   
        //根據統計結果,生成公共溢位區
        pFreeOffSet = new int[iHitCnt];
        if (nullptr == pFreeOffSet)
        {//內碼公共溢位區申請失敗
            delete []mp_HashPtr;
            return FALSE;
        }
        ZeroMemory(pFreeOffSet,sizeof(int)*iHitCnt);
    }
    if (jj == 1)
    {
        pp = 0;
    }
}
delete []pFreeOffSet;

注:
1. 本方案中的value為資料的MD5值,長度固定為32位。
2. 連結串列的節點的指標域儲存的是指向下一個節點的陣列偏移量,讀取節點內容時需要使用陣列首地址+偏移量來得到真正的節點內容

總結:
本方案結合了兩種碰撞處理的優點,減少記憶體碎片及避免堆積現象出現。提高了查詢效率。
缺點是:建表過程需要經過3次迴圈才可以完成。可能會增加等待時間,降低客戶體驗。

by Jared Kin

相關推薦

使用快速查詢字串解決方案

必備知識: 什麼是雜湊表? 雜湊表(Hash table,也叫散列表),是根據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表

MyBatis模糊查詢不報錯但查不出資料的解決方案

今天在用MyBatis寫一個模糊查詢的時候,程式沒有報錯,但查不出來資料,隨即做了一個測試,部分程式碼如下: @Test public void findByNameTest() throws IOException { String resource = "SqlMa

React 流程圖的解決方案 GGEditor

要實現型別下圖的需求,所以研究了一些g6 editor   瞭解連結:https://antvis.github.io/g6/api/graph.html g6文件 https://www.yuque.com/antv/g6/api-graph g6 https://

微服務架構是解決方案

企業應用架構演變: 單機程式->c/s->b/s->面向服務架構(SOA)->微服務架構 加粗的是單體程式 微服務架構   細粒度SOA,是強調小型短暫元件的SOA,小即是美   重點是服務,如何進行服務之間解耦   每個服務元件都可以獨立開發、構建、測試、部署   自包含

華為ENSP中AR啟動失敗錯誤程式碼40,42,43,及啟動後一直#的問題的解決方案

系統是64位win10安裝ensp510時不斷40.42.43的錯且在不報錯時開啟ar時一直輸出#  查閱網上各種方法 一 一嘗試後發現, 我的問題是虛擬機器不是最新版本,且虛擬機器中沒有配置網絡卡,檢視是否有網絡卡配置,在virtualbox中點選左上角的管理,選擇全域性設定,然後在

關於quartz定時任務實現Job介面無法註解為spring bean 的解決方案

  通常情況下,我們使用quartz之後,定時任務實現Job介面,並重寫execute()方法: public class QuartzJob1 implements Job { /** * quartz回撥此介面,此介面中為定時任務具體執行內容 *

內外網分離後如何保證檔案安全交換?介紹解決方案

近年來全球網路安全威脅態勢的加速嚴峻,使得企業對於網路安全有了前所未有的關注高度。 在嚴峻的安全態勢之下,企業的網路安全體系建設正從“以合規為導向”轉變到“以風險為導向”,從原來的“保護安全邊界”轉換到“保護核心資料資產”的思路上來。 絕大多數企業都在內部實施了內外網分離,網際網路與內網隔離,生產網與辦公

[JAVA IDEA]在使用maven專案中,無法讀取resources資料夾中的配置檔案的解決方案

1、在通過配置檔案來連線資料庫時,在resouces檔案中放入了db.properties配置檔案,但無法正常讀取到  讀取配置檔案資訊的程式碼: InputStream input=JdbcUtil.class.getClassLoader().getResourceAsStream("db.prope

跨域請求的解決方案

<!doctype html> <html> <head> <meta charset="utf-8"> <title>無標題文件</title> </head> <script src="http://libs.

關於win8下pip安裝mysql找不到config-win.h檔案的解決方案

關於win8下 pip安裝mysql報錯_mysql.c(42) : fatal error C1083: Cannot open include file: ‘config-win.h’: No such file or director的一種解決方案

關於IE7 IE8相容HTML5和CSS3的解決方案

 今天突然發現一網站用JS來實現這個支援 新增到head裡 <!--[if IE 7]> <script type='text/javascript' src='js/excanvas.js'></script> <link rel

Struts2.3 以及 2.5 過濾 xss攻擊 的解決方案

Struts 2.3 本方案採用struts2的攔截器過濾,將提交上來的引數轉碼來解決。 配置struts.xml <package name="default" namespace="

完全跨域下單點登入的解決方案

  根據oums單點登入解決方案介紹 一文我們知道單點登入有兩種模型,一種是共同父域下的單點登入(例如域名都是 xx.a.com),還有就是完全跨域下的單點登入(例如域名是xx.a.com,xx.b.com),本文我們講一下完全跨域下的單點登入該怎麼實現。  

SpringBoot WEB-INF目錄下檔案無法訪問解決方案

平時都好用的百度 沒搜尋到直接的解決方案,查閱資料提供一種方案  實驗可行 廢話不多說 上圖專案index.html位置  至於為什麼將資源放在WEB-INF目錄下  是不是更安全? 如果你怎麼也訪問不到 ,不妨試試我想到的方法 這是我的控制器寫法 直接request物

springMVC之spring容器注入失敗的解決方案

spring-config.xml中存在掃描service類所在的包,而我在初學springMVC時,在web.xml只配置載入了spring-web.xml,因此我在controller層呼叫service類中的方法時,就會出現以上問題。web.xml的部分程式碼<servlet> <se

eclipse cleanup svn時卡死或者失敗的解決方案

經常遇到一種情況,在進行pull或者push時,svn報錯,提示你應該cleanup一下,但當你cleanup時,要麼就卡死,要麼就報錯,說是在cleanup過程中需要等待其他操作。這種情況可能是由於,以前的某次SVN操作在沒有執行完就被強行終止了,導致svn會根據記錄的操

react-cropper 圖片選中某區域的解決方案

react-cropper 圖片選中某一區域的一種解決方案 npm 上面搜尋會出來兩個版本 react-cropper2 react-cropper 參考連結記錄 github地址 784 star JavaScript image cro

Chrome瀏覽器開啟網頁慢的另解決方案

目錄 前言 經驗總結 前言 折磨了我近一個月的Chrome開啟網頁慢的問題終於在今天告一段落,完結撒花~然後覺得很有必要發一篇文章來指引誤入歧途的後來人~ 網際網路上大部分教程無非都是教你在瀏覽器設定裡取消勾選一些選項,在區域網設定裡取消勾選云云,但還有一種情況

Struts2 過濾CSRF攻擊的解決方案

CSRF(Cross-site request forgery跨站請求偽造,也被稱為“One Click Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網

跨域的另解決方案——CORS(Cross-Origin Resource Sharing)跨域資源共享

      在我們日常的專案開發時使用AJAX,傳統的Ajax請求只能獲取在同一個域名下面的資源,但是HTML5打破了這個限制,允許Ajax發起跨域的請求。瀏覽器是可以發起跨域請求的,比如你可以外鏈一個外域的圖片或者指令碼。但是Javascript指令碼是不能獲取這些資源的內容的,它只能被瀏覽器執行或渲染。主