用hash table简单实现hash map
参考网址
- https://blog.csdn.net/stpeace/article/details/81274233
- https://blog.csdn.net/qq_36221862/article/details/73488162
- https://blog.csdn.net/xyzbaihaiping/article/details/51607770
哈希表的理论知识
这里关系哈希表的基本知识不做赘述
哈希表的简单应用
基于哈希表简单实现HashMap(拉链法)
代码仅供参考:github地址
#include <iostream>
#include <string>
#include <memory>
#include <functional>
using namespace std;
//hash table 内部节点
template <typename T,typename U>
class Node{
public:
Node(const T& key,const T& value){
m_key = key;
m_value = value;
}
~Node(){
std::cout<<"~Node()"<<std::endl;
}
public:
T m_key;
U m_value;
std::unique_ptr<Node<T,U>> pNode = nullptr; //内存是否能回收?
};
//基于hash table 实现的HashMap 冲突解决使用拉链法
template <typename T,typename U>
class HashMap{
public:
explicit HashMap(const unsigned int size){
this->m_size = size;
m_ppNode = std::make_unique<unique_ptr<Node<T,U>>[]>(m_size);
for(unsigned int index=0;index<m_size;index++){
m_ppNode[index].reset(nullptr);
}
}
public:
void Insert(const T& key,const U& value){
int index = std::hash<T>{}(key)%m_size; //std::hash C++ 17
std::unique_ptr<Node<T,U>> newNode = std::make_unique<Node<T,U>>(key,value);
if(m_ppNode[index] == nullptr){
m_ppNode[index] = std::move(newNode);//内存是否被正确回收?待验证
return ;
}
//map容器考虑去重
Node<T,U>* node = m_ppNode[index].get();
while(node->pNode!= nullptr){
if(node->m_key == key){
node->m_value = value;
return;
}
node = node->pNode.get();
}
if(node->m_key == key){ //判断循环最后一个元素
node->m_value = value;
return ;
}
//没有重复的元素 采用尾插法
node->pNode = std::move(newNode);
}
pair<U,bool> Find(const T&key){
int index = std::hash<T>{}(key)%m_size;
auto p = m_ppNode[index].get();
while(p!= nullptr){
if(p->m_key == key){
return make_pair(p->m_value, true);
}
p = p->pNode.get();
}
return make_pair(U(), false);
}
private:
std::unique_ptr<unique_ptr<Node<T,U>>[]> m_ppNode = nullptr;//unique_ptr对象数组
unsigned int m_size=0;
};
int main() {
{
HashMap<string,string> map(100);
map.Insert("a","aaa");
map.Insert("b","bbb");
pair<string,bool> ret1 = map.Find("a");
if(ret1.second){
std::cout<<"find:value="<<ret1.first<<std::endl;
} else{
std::cout<<"not find"<<std::endl;
}
pair<string,bool> ret2 = map.Find("b");
if(ret2.second){
std::cout<<"find:value="<<ret2.first<<std::endl;
} else{
std::cout<<"not find"<<std::endl;
}
pair<string,bool> ret3 = map.Find("c");
if(ret3.second){
std::cout<<"find:value="<<ret3.first<<std::endl;
} else{
std::cout<<"not find"<<std::endl;
}
}
return 0;
}
基于哈希表简单实现HashMap(线性探查法、二次探查法)
代码仅供参考:github地址
#include <iostream>
#include <string>
#include <vector>
using namespace std;
enum State{
EMPTY,
DELETE,
EXIST
};
//hash table 内部节点
template <typename K,typename V>
class HashNode{
public:
HashNode():m_state(EMPTY){}
public:
std::pair<K,V> m_kv;
State m_state;
};
//基于hash table 实现的HashMap 冲突解决使用开放地址法
template <typename K,typename V,bool isLine = true> //模板偏特化
class HashMap{
public:
explicit HashMap(const unsigned int size = 10):m_size(0){
m_table.resize(GetNextPrime(size));
}
public:
bool Insert(const K& key,const V& value){
CheckSize();
unsigned int hashAddr = std::hash<K>{}(key)%m_table.size();//C++ 17
unsigned int index = hashAddr;
unsigned int i = 1;
while(m_table[index].m_state == EXIST){
if(m_table[index].m_kv.first == key){
return false;
}
if(isLine){
index = DetectedLine(index);
}else{
index = DetectedSquare(index,i++);
}
}
m_table[index].m_kv = std::make_pair(key,value);
m_table[index].m_state = EXIST;
m_size++;
return true;
}
std::pair<HashNode<K,V>*,bool> Find(const K&key){
unsigned int hashAddr = std::hash<K>{}(key)%m_table.size();//C++ 17
unsigned int index = hashAddr;
HashNode<K, V>& elem = m_table[index];
if(elem.m_kv.first!=key){ //产生冲突了 继续寻找
if(isLine){//线性查找
while(true){
index = DetectedLine(index);
if(index == hashAddr){
return std::make_pair(&elem,false);
}
if(m_table[index].m_kv.first == key && m_table[index].m_state == EXIST){
return std::make_pair(&m_table[index], true);
}
}
}else{//平方查找
unsigned int i = 1;
while(m_table[index].m_state != EMPTY){ //EXIST和DELETE都是要查找的目标
index = DetectedSquare(index,i++);
if(m_table[index].m_kv.first == key && m_table[index].m_state == EXIST){
return std::make_pair(&m_table[index], true);
}
}
}
}else{
if(m_table[index].m_state == EXIST){
return make_pair(&elem, true);
}
}
return make_pair(&elem, false);
}
bool Remove(const K& key){
auto ret = Find(key);
if(ret.second){
ret.first->m_state = DELETE;
m_size--;
return true;
}
return false;
}
inline unsigned int Size(){
return m_size;
}
private:
unsigned int DetectedLine(unsigned int hashAddr){ //线性探查法
hashAddr++;
if(hashAddr == m_table.size()){
hashAddr = 0;
}
return hashAddr;
}
unsigned int DetectedSquare(unsigned int hashAddr, unsigned int i){//平方探查法
/*
* H(i) = H0 + i^2
* H(i-1) = H0 + (i-1)^2
* H(i) = H(i-1) + 2*i - 1 = H(i-1) + i<<1 - 1
* */
hashAddr = hashAddr + 2*i - 1;
hashAddr = hashAddr % m_table.size() ;
return hashAddr;
}
void CheckSize(){
if(m_size/m_table.size()*10>=6){ //当装载因子a大于0.5时,需要将vector扩容处理
m_table.resize(GetNextPrime(m_size));
HashMap<K,V,isLine> hm;
for(auto it : m_table){
if(it.m_state == EXIST){
hm.Insert(it.m_kv.first,it.m_kv.second);
}
}
this->Swap(hm);
}
}
void Swap(HashMap<K,V,isLine> hm){
std::swap(m_size,hm.m_size);
m_table.swap(hm.m_table);
}
unsigned int GetNextPrime(const unsigned int size){//使用素数表对齐做哈希表的容量,降低哈希冲突
const int _PrimeSize = 28;
static const unsigned long _PrimeList[_PrimeSize] ={
52ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 24165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
};
for(unsigned i = 0; i < _PrimeSize; ++i){
if (_PrimeList[i] > size){
return _PrimeList[i];
}
}
return _PrimeList[_PrimeSize-1];
}
private:
std::vector<HashNode<K,V>> m_table; //hash table
unsigned int m_size=0;//hash table store element number
};
int main() {
{
HashMap<int,int,false> map;
map.Insert(25, 1);
map.Insert(25, 2);
map.Insert(14, 2);
map.Insert(36, 3);
map.Insert(49, 4);
map.Insert(68, 5);
map.Insert(57, 6);
map.Insert(11, 7);
map.Insert(37, 8);
cout<<map.Size()<<endl;
auto ret = map.Find(25);
if(ret.second){
std::cout<<"Find:key="<<ret.first->m_kv.first<<" value="<<ret.first->m_kv.second<<std::endl;
}else{
std::cout<<"not find"<<std::endl;
}
ret = map.Find(11);
if(ret.second){
std::cout<<"Find:key="<<ret.first->m_kv.first<<" value="<<ret.first->m_kv.second<<std::endl;
}else{
std::cout<<"not find"<<std::endl;
}
ret = map.Find(12);
if(ret.second){
std::cout<<"Find:key="<<ret.first->m_kv.first<<" value="<<ret.first->m_kv.second<<std::endl;
}else{
std::cout<<"not find:12"<<std::endl;
}
map.Remove(25);
ret = map.Find(25);
if(ret.second){
std::cout<<"Find:key="<<ret.first->m_kv.first<<" value="<<ret.first->m_kv.second<<std::endl;
}else{
std::cout<<"not find:25"<<std::endl;
}
map.Remove(14);
cout<<map.Size()<<endl;
}
return 0;
}