HashMap與衝突解決演算法

2021-07-28 10:36:42 字數 2972 閱讀 8621

hash_map是經常被使用的一種資料結構,而其實現方式也是多種多樣。如果要求我們使用盡可能簡單的方式實現hash_map,具體該如何做呢?

我們知道hash_map最重要兩個概念是hash函式和衝突解決演算法。hash_map鍵-值之間的對映關係,hash函式將鍵對映為記憶體位址,衝突解決演算法用於解決不同的鍵對映為相同位址時候的情況。

資料結構和演算法導論中介紹了大量的hash函式和衝突解決演算法,如果選擇實現精簡的hash_map,那麼可以選擇「除留取餘法」作為hash函式,選擇「開雜湊位址鏈」作為衝入解決演算法。這樣的選擇不僅使得hash_map實現簡單,而且有很高的查詢效率。其設計結構如下:

基於位址鏈的開雜湊雜湊表實現

如圖所示,鍵347通過除留取餘法得到位址鏈的索引,然後將347對應的元素插入到該位址鏈的尾端。

為了實現位址鏈,我們需要定義鍊錶節點型別node。為了簡化問題,我們將鍵值都定義為int型別。

struct node

//位址鏈節點

};

value用於記錄節點陣列,key在檢索節點時會被使用,next儲存鍊錶關係。

基於此,定義hash_map型別simhash。

#define size 100 

//位址鏈個數,足夠大

class simhash

public:

simhash()

~simhash()

} delete map;

//清除陣列

}void insert(

int key,

int value)

node*p=map[hash(key)];

//確定位址鏈索引

node*q=

new node(key,value);

//建立節點

while(p&&p->next)p=p->next;

//索引到位址鏈末端

if(p)p->next=q;

//新增節點

else map[hash(key)]=q;

//位址鏈的第乙個節點

}void remove(

int key)

q=p;

p=p->next; }

}node* find(

int key)

return p; }

};

首先,我們需要乙個node**型別的指標map記錄位址鏈陣列的位址,至於陣列大小,我們給乙個較大的值(這裡設定為100),為了簡化問題,不需要考慮插入時表滿等情況。在建構函式和析構函式內對map記憶體分配和撤銷。另外,節點的記憶體是動態增加的,因此析構時需要單獨處理每個位址鍊錶。

對於資料結構,最關鍵的便是插入、刪除、檢索操作,為此定義操作insert、remove、find。

檢索操作實現時,首先通過hash函式定位位址鍊錶的索引,然後在位址鍊錶上檢索鍵是否存在即可。

插入操作實現時,首先會檢索鍵是否存在,如果存在則僅僅更新對應節點的資料即可,否則建立新的節點,插入到鍊錶的結尾。對於空鍊錶需要做特殊處理。

刪除操作實現時,需要使用兩個指標記錄節點的位置資訊,當遇到滿足鍵的節點時,就將該節點從鍊錶內刪除即可。如果刪除鍊錶的第乙個節點,需要做特殊處理。

如果考慮雜湊表的鍵值型別、特殊鍵型別的hash對映(字串型別鍵如何對映為數值)、特殊鍵型別的比較處理(怎麼比較兩個自定義型別鍵是否相等)、索引運算過載這些問題的話,hash_map的實現就變得複雜了。不過這些在stl內實現的比較完整,若你感興趣可以多做了解。這裡我給出自己的乙個考慮以上問題的簡單hash_map實現。

struct str_hash

};

struct str_cmp

return !*str1&&!*str2; }

};template<

class k,

class t>

class hashnode

k key;

t data;

hashnode*next;

};template<

class k,

class t,

class h,

class c>

class hashmap

h h;

c c;

hashnode* _find(k key)

} return null; }

public:

size_t size;

//hash表容量

size_t count;

//元素個數

hashmap(size_t sz=

6):size(

6),div(

2),count(

0)map=

new hashnode*[div];

for(size_t i=

0;ifor(size_t i=

0;iwhile(

true)

else

break; }

}delete map; }

void insert(k key,t data)

} delete oldmap; }

hashnode*p=_find(key);

//已經存在,替換資料

if(p)p->data=data;

else

}void remove(k key)

} delete oldmap; }

size_t pos=hash(key);

//獲取桶號

for(hashnode*p=map[pos],*q=null;p;p=p->next)

q=p; }

}t& 

get(k key)

t&  operator(k key)

bool find(k key)

};

int main()

分治思想解決演算法問題

不多bb,o n 2 include using namespace std void solve int f 5000 int m cin m for int i 0 i m i cin a i f 0 0 for int i 1 i m i f i f i 1 sum cout f m 1 en...

約瑟夫環鏈表解決演算法

1.起源 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了乙個自殺方式,41個人排成乙個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下乙個重新報...

這就是弄演算法層面解決演算法層面問題

這就是弄演算法層面解決演算法層面問題 關注前沿科技 量子位 今天 景色很好看,可是手機相機解析度太低,照不出清晰的 沒關係,試試這個超解析度演算法,讓ai 自動 幫你調整解析度。經過演算法調整後,幾乎立刻就清晰了數倍,連角落裡模糊的文字都看得清 這是來自谷歌的乙個手機超解析度演算法,此前登上過sig...