当前位置:网站首页>散列表HashTable分离链接法类模板的实现
散列表HashTable分离链接法类模板的实现
2022-07-13 18:01:00 【wild _wolf】
分离链接法(separate chaining),做法是将散列到同一个值得所有元素保留到一个链表List中。如果这个元素是个新的元素,那么它将被插入到链表的前端。
插入前端的原因是:
常常发生这样的事实:新近插入的元素最有可能不久又被访问。
假设关键字是前10个完全平方数并设散列函数就是 hash(x)=x mod 10,则最后得到的分离链接散列表为下图所示。

定义散列表的装填因子λ为散列表中的元素个数对该表大小的比,分离链接散列表的一般法则是让表的大小大致与预料的元素个数差不多(即λ ≈ 1)。
实现代码:
#include<list>
#include<vector>
#include"UniversalHash.h"
//分离链接散列表的类型声明
template<typename HashedObj>
class HashTable {
private:
std::vector<std::list<HashedObj>>theLists; //链表的数组
int currentSize;
void rehash()
{
std::vector<std::list<HashedObj>> oldLists = theLists;
//创建两倍大的空表
theLists.resize(nextPrime(2 * theLists.size()));
for (auto& thisList : theLists)
thisList.clear();
//复制整个表
currentSize = 0;
for (auto& thisList : oldLists)
for (auto& x : thisList)
insert(std::move(x));
}
size_t myhash(const HashedObj& x)const
{
static _hash<HashedObj>hf;
return hf(x) % theLists.size();
}
public:
explicit HashTable(int size = 101) :theLists{
nextPrime(101) } {
makeEmpty();
}
bool contains(const HashedObj& x)const
{
auto& whichList = theLists[myhash(x)];
return find(begin(whichList), end(whichList), x) != end(whichList);
}
void makeEmpty()
{
for (auto& thisList : theLists)
thisList.clear();
}
bool insert(const HashedObj& x)
{
auto& whichList = theLists[myhash(x)];
if (find(begin(whichList), end(whichList), x) != end(whichList))
return false; //重复元
whichList.push_back(x);
//再散列
if (++currentSize > theLists.size())
rehash();
return true;
}
bool insert(HashedObj&& x)
{
auto& whichList = theLists[myhash(x)];
if (find(begin(whichList), end(whichList), x) != end(whichList))
return false; //重复元
whichList.push_back(std::move(x));
//再散列
if (++currentSize > theLists.size())
rehash();
return true;
}
bool remove(const HashedObj& x)
{
auto& whichList = theLists[myhash(x)];
auto itr = find(begin(whichList), end(whichList), x);
if (itr == end(whichList))
return false;
whichList.erase(itr);
--currentSize;
return true;
}
};
头文件UniversalHash.h:
#pragma once
#include<string>
//通用散列的简单实现
/* * x代表要哈希的对象,m代表TableSize,a、b是随机选出的 * 散列函数簇 H={H(x)=((ax+b)mod p)mod m,其中1<=a<=p-1,0<=b<=p-1}是通用的。 */
int universalHash(int x, int a, int b, int p, int m)
{
return static_cast<int>(((static_cast<long long>(a) * x) + b) % p) % m;
}
/* * 形如2^n-1的素数叫Mersenne素数,如2^5-1、2^61-1、2^31-1等, * 涉及Mersenne素数的模运算可以通过一次移位和一次减法实现 */
const int DIGS = 31;
const int mersennep = (1 << DIGS) - 1;
int universalHash(int x, int a, int b, int m)
{
long long hashVal = static_cast<long long>(a) * x + b;
hashVal = ((hashVal >> DIGS) + (hashVal & mersennep));
if (hashVal >= mersennep)
hashVal -= mersennep;
return static_cast<int>(hashVal) % m;
}
/** * 判断素数 */
bool isPrime(int n)
{
if (n == 2 || n == 3)
return true;
if (n == 1 || n % 2 == 0)
return false;
for (int i = 3; i * i <= n; i += 2)
if (n % i == 0)
return false;
return true;
}
/** * 获取下一个比b大的素数 * Assumes n > 0. */
int nextPrime(int n)
{
if (n % 2 == 0)
++n;
for (; !isPrime(n); n += 2)
;
return n;
}
//使用函数对象,让散列函数只用对象作为参数并返回适当的整形量
template<typename T>
class _hash
{
public:
size_t operator()(const T& key) {
size_t hashVal = 0;
T tmp = key;
while (tmp > 0) {
hashVal = 37 * hashVal + tmp % 10;
tmp /= 10;
}
return hashVal;
}
};
template<>
class _hash<std::string>
{
public:
size_t operator()(const std::string& key) {
size_t hashVal = 0;
for (char ch : key)
hashVal = 37 * hashVal + ch;
return hashVal;
}
};
边栏推荐
- Implementation of array flattening
- Go秒杀系统3--Work模式,Publish模式
- Talk about the interface
- [introduction to go language] 07 go language string
- Rtthread creation of thread
- SSM integration (classic self version)
- 01 machine learning: evaluation indicators
- leetcode-2 两数相加(链表的头插法、尾插法、两个不同长度链表相加、减操作的处理方法)
- 信息安全基础
- 01. Write three listeners in a class
猜你喜欢

LeetCode 刷题 第八天

LeetCode精讲——735. 行星碰撞(难度:中等)

Leetcode lecture - 676 Implement a magic Dictionary (difficulty: medium)

Leetcode lecture - 1252 Number of odd cells (difficulty: simple)

Chapter VI use of OLED module +stm32

RT_ Thread idle thread and two commonly used hook functions

LeetCode精讲——1252. 奇数值单元格的数目(难度:简单)
![[go language introduction] 06 go language circular statement](/img/c1/097bbd37199d2755caccf64c4ae162.png)
[go language introduction] 06 go language circular statement

Leetcode lecture - 735 Planetary collision (difficulty: medium)

AMD RDNA 3 Navi 31旗舰GPU据称采用3D V-Cache封装以及最高384MB缓存
随机推荐
js知识点
Comparison and application of DHT11 and dht22 (am2302)
DL第四天
VIM usage
Dark horse database notes DCL
IIC communication
LeetCode 第十五天
五子棋(二)
DL第五天
Simple listener
说一下接口
AMD RDNA 3 Navi 31旗舰GPU据称采用3D V-Cache封装以及最高384MB缓存
JS knowledge points
LeetCode 刷题 第八天
DL第六天
多个else if嵌套时的作用域
数组扁平化实现
Dynamic changes based on arrays and nodes (addition, deletion, modification and query)
LeetCode 刷题 第十一天
(一)OSI模型