基於CRC20雜湊的百萬賬號快速查詢模擬

2021-04-20 00:30:24 字數 4911 閱讀 6763

基於數以百萬級的賬戶資訊裡面進行賬號的校驗並不是一件容易的事,關鍵點在於具體賬戶資訊的定位.本文的主題僅僅只是為了應用的實現,就不再去做雜湊和排序各種演算法之間的對比.對於一百萬的賬戶資訊,使用多大的雜湊表進行儲存,是需要考量的.對於雜湊腹得最多的應該屬256桶的hash table,但是在最好的情況下一百萬賬戶資訊在256桶的雜湊表當中重合率達到了近4000,而再從這當中進行二次搜尋,同樣也是乙個數量級的工作,於是可以往上擴充到65536(演算法使用crc16),這樣子最好的情況下重合率為15.26,但是要在這些隨機的賬號當中達到如此的平衡度完全是不可能的.另外考量記憶體,65536桶各放置一結構指標,每結構指向乙個單向鍊錶,鍊錶當中儲存下一級指標(pnext),關鍵字(key,以賬號作為關鍵字)和指向賬戶資訊的結構,其占用空間為65536 x 4(32位) + 1000000 x (4 + n + 4) + 1000000 x m,其中n為key占用的空間,m為賬戶資訊結構占用的空間.而其中賬戶資訊占用的空間是一定的,用k來表示雜湊表占用的空間,則有總占用空間 = k + 1000000 x (4 + n + 4 + m) ,假定n為30,m為100,則固定的賬戶相關資訊占用為132mb,16位的雜湊占用為263kb,這個值是相當小的,由於考慮到其重合率仍然有超過15,於是可以考慮擴大.那擴大多少合適呢?如果是20位,那占用空間應該是4.2mb,24位為67mb,67mb已經是比較大的了,所以就只需要從20位和24位中間進行考慮.20位,實際上擁有1048575個值,已經稍大於現有的賬戶資料一百萬,而24位可以表示16777215個值,對於當前一百萬的使用者資訊,即使擴充最多考慮只會是300~500萬級別,遠沒有必要使用24位這麼多.

在確定使用20位的hash值之後,就需要相應的演算法.我們所需要的是crc20,而這演算法並不常用,用得比較多的通常是crc16和crc32,相對其它演算法來說,比較優的就是其速度快,而且現成.對於crc20,實際上我們可以取crc32的低20位,如此一來遠比我們自己設計乙個20位的摘要演算法來得實在和效率.為了對想法做乙個驗證,下面就來做乙個測試:

先生成一百萬個不重複的賬號,並以每行乙個賬號儲存於檔案當中,假定儲存到:c:/accounts1m.txt

pha****em = ^tha****em;

tha****em = record

key: string;       //關鍵字,賬號

value: pointer;    //ponlineuserinfo

pnext: pha****em;

end;

accounts: array[0..$fffff] of pointer;  //hash table

//根據crc32生成crc20

function crc20(data: string): longword;

begin

result := crc32($ffffffff,pchar(data),length(data)) and $fffff;

end;

//密碼校驗測試

function checkpassword(account: string; password: string): boolean;

var_crc20: dword;

pitem: pha****em;

puser: ponlineuserinfo;

begin

result := false;

//根據賬號計算crc

_crc20 := crc20(account);

//定位到相同hash值的賬戶鍊錶

pitem := accounts[_crc20];

//遍歷匹配賬號

while pitem <> nil do begin

if pitem.key = account then begin

//關鍵字相符,取賬賬資訊

puser := ponlineuserinfo(pitem.value);

//判斷密碼是否正確,正確則返回校驗成功(true)

if puser.password = password then result := true;

exit;

end;

pitem := pitem.pnext;

end;

end;

//載入賬戶資訊

procedure tform1.btninitaccountsclick(sender: tobject);

vartls: tstringlist;

i: integer;

account: string;

_crc20: dword;

pitem: pha****em;

puser: ponlineuserinfo;

dwstart,dwend: dword;

begin

tls := tstringlist.create;

trytls.loadfromfile('c:/accounts1m.txt');

dwstart := gettickcount;

for i := 0 to tls.count - 1 do

begin

//取得賬號

account := tls.strings[i];

//計算crc值

_crc20 := crc20(account);

//根據crc值儲存到同crc的賬戶資訊鍊錶當中

if accounts[_crc20] = nil then begin

new(pitem);

pitem^.key := account;

pitem^.pnext := nil;

new(puser);

puser^.account := account;

puser^.password := account; //以賬號作為其密碼

pitem^.value := puser;

accounts[_crc20] := pitem;

end else begin

pitem := accounts[_crc20];

while (pitem.pnext <> nil) and (pitem.key <> account) do pitem := pitem.pnext;

if pitem.key <> account then begin

new(pitem.pnext);

pitem := pitem.pnext;

pitem.pnext := nil;

pitem.key := account;

new(puser);

puser^.account := account;

puser^.password := account; //以賬號作為其密碼

pitem.value := puser;

end;

end;

end;

dwend := gettickcount;

//顯示初始化完所有賬號所需要的時間

showmessage(inttostr(dwend-dwstart));

finally

tls.free;

end;

end;

//對所有賬號進行一次全盤校驗

procedure tform1.btncheckallaccountsclick(sender: tobject);

vartls: tstringlist;

i: integer;

account: string;

_crc32,_crc20: dword;

pitem: pha****em;

puser: ponlineuserinfo;

dwstart,dwend: dword;

begin

tls := tstringlist.create;

trytls.loadfromfile('c:/accounts1m.txt');

dwstart := gettickcount;

for i := 0 to tls.count - 1 do

begin

account := tls.strings[i];

randomize;

//根據隨機數,測試是否使用正確的密碼進行校驗

if (random($7fffffff) mod 2) = 0 then

checkpassword(account,account)

else

checkpassword(account,'account');

end;

dwend := gettickcount;

//顯示校驗完所有賬號所需要的時間

showmessage(inttostr(dwend-dwstart));

finally

tls.free;

end;

end;

測試環境:

os 名稱:          microsoft(r) windows(r) server 2003, enterprise edition

os 版本:          5.2.3790 service pack 2 build 3790

系統型號:         latitude d630

系統型別:         x86-based pc

處理器:           安裝了 2 個處理器。

[01]: x86 family 6 model 15 stepping 13 genuineintel ~777 mhz

[02]: x86 family 6 model 15 stepping 13 genuineintel ~777 mhz

bios 版本:        dell   - 27d80614

測試結果:

初始化100萬賬號資訊:550-ms

校驗完100萬賬號資訊:2600-ms

基於MODBUS 協議的CRC16程式實現

modbus 通訊協議的 crc 冗餘迴圈校驗碼含2個位元組,即 16 位二進位制數。crc 碼由傳送裝置計算,放置於所傳送資訊幀的尾部。接收資訊裝置再重新計算所接收資訊 除 crc 之外的部分 的 crc,比較計算得到的 crc 是否與接收到crc相符,如果兩者不相符,則認為資料出錯。1 預置 1...

雜湊表 棧 20 有效的括號

給定乙個只包括 的字串,判斷是否有效。左括號必須用相同型別的右括號閉合,左括號必須以正確的順序閉合。首先字串轉換成字元陣列,可以進行for的迴圈。用棧進行判斷,當左括號時,入棧,當右括號時,出棧,如果最後棧非空,返回錯誤。用雜湊陣列進行輔助,增加了 的復用性。同時減少了判斷次數 鍵值對,用key代表...

雜湊 基於詞頻的檔案相似度

實現一種簡單原始的檔案相似度計算,即以兩檔案的公共詞彙佔總詞彙的比例來定義相似度。為簡化問題,這裡不考慮中文 因為分詞太難了 只考慮長度不小於3 且不超過10的英文單詞,長度超過10的只考慮前10個字母。輸入首先給出正整數n 100 為檔案總數,隨後按以下格式給出每個檔案的內容 首先給出檔案正文,最...