#pragma once
//
开放定地址法/闭散列
//namespace OpenAddress
//{
//
// enum status
// {
// Empty,
// Exist,
// Delete
// };
//
// template <class K, class V>
// struct HashData
// {
// pair<K, V> _kv;
//
// status _status=Empty ;//为了不影响删除元素后面的探测,这里的删除是一种伪删除法,用status记录当前存储位置的状态;
//
//
// };
//
// template <class K, class V>
// class HashTable
// {
// public:
//
// bool Insert(const pair<K, V>& kv)
// {
// //去冗余
// if (Find(kv.first))
// {
// return false;
// }
//
// //刚开始Tables为空 或 负载因子超过0.7就扩容;
// if (Tables.size() == 0 || _n * 10 / Tables.size() >= 7)
// {
// size_t newsize = Tables.size() == 0 ? 10 : Tables.size() * 2;
// if (newsize > 10)
// {
// //构建一个新的哈希表对象
// HashTable<K, V> newht;
// //这个哈希表对象最初开始就扩容到原来的二倍;
// newht.Tables.resize(newsize);
// //遍历旧表映射到新表
// for (auto& data : Tables)
// {
// if (data._status == Exist)
// {
// newht.Insert(data._kv);
// }
// }
//
// //交换两个哈希表对象里面的底层结构Tables;
// // Tables.swap(newht.Tables);
// swap(Tables, newht.Tables);
// }
// //Tables.size()==0的情况,此时表内所有HashData都是默认构造的,状态自然为Empty;
// else
// {
// Tables.resize(newsize);
// }
//
// }
// //注意hashi是用什么计算的,如果Tables的size改变了,那么很有可能直接找不到原本可以找到的HashData了
// size_t hashi = kv.first % Tables.size();
// size_t i = 1;
// size_t index = hashi;
//
// //int flag = 0;
// while (Tables[index]._status == Exist)
// {
//
// index = hashi + i;
// index %= Tables.size();//当index==Tables.size()时,index又会从0开始;
// ++i;
//
// /* if (flag == 7)
// {
// int s = 0;
// }*/
// }
//
// Tables[index]._kv = kv;
// Tables[index]._status = Exist;
// _n++;
// return true;
// }
//
// HashData<K, V>* Find(const K& key)
// {
// if (Tables.size() == 0)
// return nullptr;
// size_t hashi = key % Tables.size();
// size_t i = 1;
// size_t index = hashi;
//
//
// //在插入前删除其中一部分数据,负载因子会减减,所以如果再插入几个数据刚好插入到Empty,并不会扩容,
// //那么再去调用find函数时除了Exist就是Delete,会陷入死循环;
// while (Tables[index]._status != Empty)
// {
// if (Tables[index]._status != Delete && Tables[index]._kv.first == key)
// {
// return &Tables[index];//返回这块的地址;
// }
//
// //index从hashi+1开始走;
// index = hashi + i;
// index %= Tables.size();
// ++i;
//
// //说明走了一圈,查找不到;
// if (hashi == index)
// break;
// }
// return nullptr;
// }
//
// bool Erase(const K& key)
// {
// HashData<K, V>* ret = Find(key);
// if (ret)
// {
// ret->_status = Delete;
// --_n;//负载因子
// return true;
// }
// else
// {
// return false;
// }
//
// }
//
// private:
// vector<HashData<K, V>> Tables;//自定义类型会默认构造;
// size_t _n;//存储的数据个数(用来计算负载因子)
// /*HashDate* Tables;
// size_t _size;
// size_t _capacity;*/
// };
//
//
// //测试1
// void test_Hash_Table1()
// {
// int arr[] = { 3,33,2,13,5,12,102 };
// HashTable<int, int> ht1;
//
// for (auto e : arr)
// {
// ht1.Insert(make_pair(e, e));
// }
//
// ht1.Insert(make_pair(679, 679));
// }
//}
//哈希桶 / 开散列
namespace HashBucket
{
//每个节点包括一个指向下一个同样节点的指针,和一个类型,可能是pair键值对也可能是key;
template<class T>
struct HashNode
{
T _data;//有可能是pair,也有可能是单纯的key;
HashNode<T>* _next;
HashNode(const T& data)
:_data(data)
, _next(nullptr)
{}
};
//配合string使用,这里特意使用仿函数来处理string不能取模的情况;
template<class K>
struct HashFunc
{
size_t operator()(const K& key)
{
//整形家族可以直接返回
return key;
}
};
//BKDR HASH(特化)
template<>
struct HashFunc<string>
{
size_t operator()(const string& str)
{
//把字符串中所有字符都加起来变成整型;
size_t ret = 0;
for (auto& ch : str)
{
ret += ch;
ret *= 31;//防止哈希冲突;
}
return ret;
}
};
//前置声明
template<class K, class T, class KeyOfT, class Hash>
class HashTable;
//迭代器
template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>
struct _HashIterator
{
typedef HashNode<T> Node;
typedef HashTable<K, T, KeyOfT, Hash> HT;
typedef _HashIterator<K, T, KeyOfT, Hash> Self;
Node* _node;
HT* _ht;
//构造迭代器需要节点指针和哈希表指针;
_HashIterator(Node* node,HT* ht)
:_node(node)
,_ht(ht)
{}
const T& operator* ()
{
return _node->_data;
}
T* operator->()
{
return &_node->_data;
}
bool operator!=(const Self& s)
{
return _node != s._node;//用两个迭代器里面的指针去比较;
}
Self& operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
//找下一个不为空的桶
//算出当前位置
KeyOfT kot;
Hash hash;
//算出当前桶位置;
size_t hashi = hash(kot(_node->_data)) % (_ht->_tables.size());
++hashi;
while (hashi < _ht->_tables.size())
{
if (_ht->_tables[hashi])
{
_node =_ht-> _tables[hashi];
return *this;
}
//直到找到不是空桶或者走完哈希表为止;
else
{
++hashi;
}
}
//没有找到,把迭代器里面的指针置为空,然后返回这个迭代器;
_node = nullptr;
return *this;
}
}
};
//底层数据结构--哈希表
template<class K,class T,class KeyOfT,class Hash=HashFunc<K>>
class HashTable
{
typedef HashNode<T> Node;
//为了让迭代器访问哈希表的私有成员变量,设置一个友元;
template<class K, class T, class KeyOfT, class Hash>
friend struct _HashIterator;
public:
//在哈希表里面重定义迭代器名称,便于操作;
typedef _HashIterator<K, T, KeyOfT, Hash> iterator;
typedef _HashIterator<const K&, const T&, KeyOfT, Hash> const_iterator;
iterator begin()
{
Node* cur = nullptr;
for (auto& e: _tables)
{
if (e)
{
return iterator(e,this);
}
}
return iterator(nullptr,this);
}
iterator end()
{
return iterator(nullptr,this);
}
~HashTable()
{
for (auto& first:_tables)
{
if (first)
{
Node* cur = first;
while (cur)
{
Node* tmp = cur;
cur = cur->_next;
delete tmp;
}
}
first = nullptr;
}
}
//如果data是个键值对,那么仿函数KeyOfT就是从Unordered_map传过来的,就一定是返回键值对的first;
//如果data是个单纯的值,说明仿函数KeyOfT就是从Unordered_set传过来的,就一定是直接返回该值;
pair<iterator,bool> Insert(const T& data)
{
KeyOfT kot;
iterator it=Find(kot(data));
if (it != end())
{
//说明找到了
//那么就返回一个pair,这个pair由迭代器和布尔值构成;
return make_pair(it,false);
}
//负载因子等于1时扩容
//即使刚开始_tables还没有初始化,这里的负载因子因为和_tables.size()相等都为0,所以也可以扩容;
if (_n==_tables.size())
{
//以下这种较为麻烦;
//size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
/* HashTable<K, V> newht;
newht._tables.resize(newsize);
for (auto& cur : _tables)
{
while(cur)
{
newht.Insert(cur->_kv);
cur = cur->_next;
}
}
_tables.swap(newht._tables);*/
size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
//创建一个新tables,全部初始化为nullptr;
vector<Node*> newtables(newsize,nullptr);
KeyOfT kot;
Hash hash;
//遍历旧tables,把旧tables的数据挪过来;
for (auto& cur:_tables)
{
while (cur)
{
//记录下一个节点;
Node* next=cur->_next;
size_t hashi = hash( kot(cur->_data) ) % newtables.size();
//头插
cur->_next=newtables[hashi];
newtables[hashi] = cur;
//更新cur
cur = next;
}
}
//交换新表与旧表
_tables.swap(newtables);
}
//正式插入
size_t hashi = hash(kot(data)) % _tables.size();
Node* newnode = new Node(data);
newnode->_next = _tables[hashi];
_tables[hashi] = newnode;
_n++;
//插入成功,返回键值对 pair<iterator,true>;
return make_pair(iterator(newnode,this), true);
}
iterator Find(const K& key)
{
//刚开始顺序表为空,说明没有任何数据,直接返回nullptr;
if (_tables.size() == 0)
return end();
KeyOfT kot;
Hash hash;
size_t hashi = hash(key) % _tables.size();
Node* cur = _tables[hashi];
while (cur)
{
if (hash(kot(cur->_data)) == hash(key))
return iterator(cur,this);
cur = cur->_next;
}
return end();
}
bool Erase(const K& key)
{
if (_tables.size() == 0)
return false;
KeyOfT kot;
Hash hash;
//开始找
size_t hashi = hash(key) % _tables.size();
Node* cur = _tables[hashi];
Node* prev =nullptr;
while (cur)
{
if (hash(kot(cur->_data)) == hash(key))
{
if (prev)
{
Node* next = cur->next;
prev->_next = next;
}
else//说明头结点就是
{
_tables[hashi] = cur->_next;
}
delete cur;
return true;
}
prev = cur;
cur = cur->_next;
}
return false;
}
private:
vector<Node*> _tables;//指针数组;
size_t _n=0;//存储数据的有效个数;
};
}
【数据结构】哈希表
最新推荐文章于 2024-03-19 18:15:41 发布