1 Star 1 Fork 0

bit.zy / xzy.C++

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
HashTable.h 6.54 KB
一键复制 编辑 原始数据 按行查看 历史
bit.zy 提交于 2022-09-27 22:44 . 哈希表的模拟实现
#pragma once
#include<iostream>
#include<string>
#include<vector>
using namespace std;
//利用仿函数将数据类型转换为整型
template<class K>
struct DefaultHash
{
size_t operator()(const K& key)
{
return (size_t)key;
}
};
//模板的特化
template<>
struct DefaultHash<string>
{
size_t operator()(const string& key)
{
//BKDR哈希算法
size_t hash = 0;
for (auto ch : key)
{
hash = hash * 131 + ch;//把所有字符的ascii码值累计加起来
}
return hash;
}
};
//闭散列哈希表的模拟实现
namespace CloseHash
{
enum State
{
EMPTY,
EXIST,
DELETE
};
//哈希节点状态的类
template<class K, class V>
struct HashData
{
pair<K, V> _kv;
State _state = EMPTY;//记录每个位置的状态,默认给空
};
//哈希表的类
template<class K, class V, class HashFunc = DefaultHash<K>>//添加仿函数便于把其他类型的数据转换为整型数据
class HashTable
{
typedef HashData<K, V> Data;
public:
//插入
bool Insert(const pair<K, V>& kv)
{
//1、去除冗余
if (Find(kv.first))
{
//说明此值已经有了,直接返回false
return false;
}
//2、扩容
//负载因子超过0.7,就扩容
if (_tables.size() == 0 || _n * 10 / _tables.size() >= 7)
{
size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
//扩容以后,需要重新建立映射关系
HashTable<K, V, HashFunc> newHT;
newHT._tables.resize(newSize);
//遍历旧表,把旧表每个存在的元素插入newHT
for (auto& e : _tables)
{
if (e._state == EXIST)
{
newHT.Insert(e._kv);
}
}
newHT._tables.swap(_tables);//建立映射关系后交换
}
//3、插入
HashFunc hf;
size_t starti = hf(kv.first);//取出键值对的key,并且避免了负数的情况,借用仿函数确保是整型数据
starti %= _tables.size();
size_t hashi = starti;
size_t i = 1;
//线性探测/二次探测
while (_tables[hashi]._state == EXIST)
{
hashi = starti + i;//二次探测改为 +i^2
++i;
hashi %= _tables.size();//防止hashi超出数组
}
_tables[hashi]._kv = kv;
_tables[hashi]._state = EXIST;
_n++;
return true;
}
//查找
Data* Find(const K& key)
{
//判断表的size是否为0
if (_tables.size() == 0)
{
return nullptr;
}
HashFunc hf;
size_t starti = hf(key);//通过仿函数把其它类型数据转为整型数据
starti %= _tables.size();
size_t hashi = starti;
size_t i = 1;
//线性探测/二次探测
while (_tables[hashi]._state != EMPTY)//不为空就继续
{
if (_tables[hashi]._state != DELETE && _tables[hashi]._kv.first == key)
{
return &_tables[hashi];//找到了就返回此对象的地址
}
hashi = starti + i;//二次探测改为 +i^2
++i;
hashi %= _tables.size();//防止hashi超出数组
}
return nullptr;
}
//删除
bool Erase(const K& key)
{
//复用Find函数去帮助我们查找删除的值是否存在
Data* ret = Find(key);
if (ret)
{
//若存在,直接把此位置的状态置为DELETE即可
ret->_state = DELETE;
return true;
}
else
{
return false;
}
}
private:
vector<Data> _tables;
size_t _n = 0;//记录存放的有效数据的个数
};
}
//开散列哈希桶的实现
namespace Bucket
{
template<class K, class V>
struct HashNode
{
pair<K, V> _kv;
HashNode<K, V>* _next;
//构造函数
HashNode(const pair<K, V>& kv)
:_kv(kv)
, _next(nullptr)
{}
};
template<class K, class V, class HashFunc = DefaultHash<K>>
class HashTable
{
typedef HashNode<K, V> Node;
public:
//析构函数
~HashTable()
{
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
_tables[i] = nullptr;//释放后置空
}
}
//插入
bool Insert(const pair<K, V>& kv)
{
//1、去除冗余
if (Find(kv.first))
{
return false;
}
//构建仿函数,把数据类型转为整型,便于后续建立映射关系
HashFunc hf;
//2、负载因子 == 1就扩容
if (_tables.size() == _n)
{
/*法一
size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
HashTable<K, V> newHT;//
newHT._tables.resize(newSize, nullptr);
//遍历旧表,把旧表的数据重新映射到新表
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)//如果cur不为空,就插入
{
newHT.Insert(cur->_kv);
cur = cur->_next;
}
}
newHT._tables.swap(_tables);*/
//法二:
size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
vector<Node*> newTable;
newTable.resize(newSize, nullptr);
for (size_t i = 0; i < _tables.size(); i++)//遍历旧表
{
Node* cur = _tables[i];
while (cur)
{
Node* next = cur->_next;
size_t hashi = hf(cur->_kv.first) % newSize;//确认映射到新表的位置
//头插
cur->_next = newTable[hashi];
newTable[hashi] = cur;
cur = next;
}
_tables[i] = nullptr;
}
newTable.swap(_tables);
}
//3、头插
//找到对应的映射位置
size_t hashi = hf(kv.first);
hashi %= _tables.size();
//头插到对应的桶即可
Node* newnode = new Node(kv);
newnode->_next = _tables[hashi];
_tables[hashi] = newnode;
++_n;
return true;
}
//查找
Node* Find(const K& key)
{
//防止后续除0错误
if (_tables.size() == 0)
{
return nullptr;
}
//构建仿函数,把数据类型转为整型,便于后续建立映射关系
HashFunc hf;
//找到对应的映射下标位置
size_t hashi = hf(key);
//size_t hashi = HashFunc()(key);//匿名对象
hashi %= _tables.size();
Node* cur = _tables[hashi];
//在此位置的链表中进行遍历查找
while (cur)
{
if (cur->_kv.first == key)
{
//找到了
return cur;
}
cur = cur->_next;
}
//遍历结束,没有找到,返回nullptr
return nullptr;
}
//删除
/*法一*/
bool Erase(const K& key)
{
//防止后续除0错误
if (_tables.size() == 0)
{
return false;
}
//构建仿函数,把数据类型转为整型,便于后续建立映射关系
HashFunc hf;
//找到key所对应的哈希桶的位置
size_t hashi = hf(key);
hashi %= _tables.size();
Node* cur = _tables[hashi];
Node* prev = nullptr;
//删除
while (cur)
{
if (cur->_kv.first == key)
{
if (prev == nullptr)//头删
{
_tables[hashi] = cur->_next;
}
else//非头删
{
prev->_next = cur->_next;
}
delete cur;
return true;
}
prev = cur;
cur = cur->_next;
}
return false;
}
/*法二替换法……*/
private:
//指针数组
vector<Node*> _tables;
size_t _n = 0;//记录有效数据的个数
};
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/bit-zy/xzy--c.git
git@gitee.com:bit-zy/xzy--c.git
bit-zy
xzy--c
xzy.C++
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891