引子:哈希表作为一种重要的,那他余数取模法的闭散列与开散列在底层是如何实现的呢?今天我们来一探究竟!由于前一篇我们已经讲过什么是闭散列与开散列,所以我们不再过多赘述,直接进入主题,上代码!(代码中已经包含了测试代码)
优化:我们实现的并不排除全部数据集中在一个桶内,这样时间复杂度看,没有达到我们想要的效果,对此,我们可以用vector<红黑树>来进行封装,这样查找的次数会被限制在log_2 N,详见红黑树,请看我前二篇!
前提:由于哈希要求key能转换为整形,对于string类我们需要用到特化,来进行处理!如下:
#pragma once
#include<iostream>
#include<string>
#include<vector>
using namespace std;
//key要求有转整形的作用
template<class K>
class Hash_to_int
{
public:
size_t operator()(const K& key)
{
return (size_t)key;
}
};
//对于string类的转换--特化
template<>
class Hash_to_int<string>
{
public:
//仿函数
size_t operator()(const string& key)
{
size_t numi = 0;
for (auto e : key)
{
numi *= 131;
numi += e;
}
return numi;
}
};
闭散列:
//闭散列
namespace hash_close
{
enum State
{
FULL,
EMPTY,
DELETE
};
template<class K,class V>
class hashData
{
public:
pair<K, V> _kv;
State _state = EMPTY;
};
template<class K,class V,class hash= Hash_to_int<K>>
class hashTable
{
public:
typedef hashData<K, V> Data;
hashTable()
:_number(0)
{
_table.resize(10);
}
//除留余数法--(常用)
//寻找
Data* Find(const K& key)
{
hash to_int;
size_t numi = to_int(key) % _table.size();
while (_table[numi]._state != EMPTY)
{
if (_table[numi]._state!=DELETE && _table[numi]._kv.first==key)
{
return &_table[numi];
}
numi++;
numi %= _table.size();
}
return nullptr;
}
//删除
bool Erase(const K&key)
{
Data* cmp = Find(key);
if (cmp)
{
cmp->_state = DELETE;
return true;
}
else
return false;
}
//insert
bool insert(const pair<K, V>& kv)
{
//在原有的数据里面已经有这个了,要确保唯一性
if (Find(kv.first))
return false;
//扩容问题--负载因子
int n = _number * 10 / _table.size();
if (n >= 7)
{
hashTable<K, V, hash> newTable;
newTable._table.resize(_table.size() * 2);
for (size_t i = 0; i < _table.size(); i++)
{
if (_table[i]._state == FULL)
{
newTable.insert(_table[i]._kv);
}
}
_table.swap(newTable._table);
}
hash to_int;
size_t numi = to_int(kv.first) % _table.size();
while (_table[numi]._state == FULL)
{
numi++;
numi %= _table.size();
}
_table[numi]._kv = kv;
_table[numi]._state = FULL;
_number++;
return true;
}
// 新增遍历函数
void Traverse()
{
for (auto& data : _table) {
if (data._state == FULL) {
cout << data._kv.first<<" "<< data._kv.second << endl;
}
}
}
private:
vector<Data> _table;
size_t _number;
};
void TestHT1()
{
hashTable<int, int> ht;
int a[] = { 11,21,4,14,24,15,9 };
for (auto e : a)
{
ht.insert({ e,e });
}
ht.insert({ 19,19 });
ht.insert({ 19,190 });
ht.insert({ 19,1900 });
ht.insert({ 39,1900 });
ht.Traverse();
}
void TestHT2()
{
hashTable<string, string> ht;
ht.insert({ "sort", "排序" });
ht.insert({ "left", "左边" });
ht.Traverse();
}
}
开散列
//开散列
namespace hash_openess
{
//悬挂的节点
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 hash = Hash_to_int<K>>
class HashTable
{
typedef HashNode<K, V> Node;
public:
HashTable()
:_number(0)
{
_tables.resize(10, nullptr);
}
//插入
bool insert(const pair<K, V>& kv)
{
hash to_int;
size_t numi = to_int(kv.first) % _tables.size();
//负载因子为1时进行扩容
//即size与数据点相等
if (_number == _tables.size())
{
vector<Node*> newTable(_tables.size()*2);
//挪动数据
for (size_t i = 0; i < _tables.size(); i++)
{
Node* current = _tables[i];
while (current)
{
Node* next = current->_next;
size_t numii = to_int(current->_kv.first) % newTable.size();
// 头插到新表
current->_next = newTable[numii];
newTable[numii] = current;
current = next;
}
_tables[i] = nullptr;
}
_tables.swap(newTable);
}
//进行头插
Node* cmp = new Node(kv);
cmp->_next = _tables[numi];
_tables[numi] = cmp;
_number++;
return true;
}
//删除
bool Erase(const K& key)
{
hash to_int;
//找出位置
size_t numi = to_int(key) % _tables.size();
Node* prev = nullptr;
Node* cur = _tables[numi];
while (cur)
{
if (cur->_kv.first == key)
{
if (prev == nullptr)
{
_tables[numi] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
delete cur;
_number--;
return true;
}
prev = cur;
cur = cur->_next;
}
return false;
}
//查找
Node* Find(const K& key)
{
hash to_int;
//找出位置
size_t numi = to_int(key) % _tables.size();
Node* cur = _tables[numi];
while (cur)
{
if (cur->_kv.first == key)
{
return cur;
}
cur = cur->_next;
}
return nullptr;
}
// 新增遍历函数
void Traverse()
{
for (size_t i = 0; i < _tables.size(); i++)
{
Node* current = _tables[i];
while (current)
{
cout << current->_kv.first << " " << current->_kv.second << endl;
current = current->_next;
}
}
}
private:
vector<Node*> _tables;
size_t _number;
};
void TestHT1()
{
HashTable<int, int> ht;
int a[] = { 11,21,4,14,24,15,9 };
for (auto e : a)
{
ht.insert({ e,e });
}
ht.insert({ 19,19 });
ht.insert({ 19,190 });
ht.insert({ 19,1900 });
ht.insert({ 39,1900 });
ht.Traverse();
cout << ht.Find(19) << endl;
ht.Erase(19);
ht.Traverse();
}
void TestHT2()
{
HashTable<string, string> ht;
ht.insert({ "sort", "排序" });
ht.insert({ "left", "左边" });
ht.Traverse();
}
}