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...