用哈希结构封装map和set
哈希表的改造
节点
数据类型改为模板
迭代器
成员
一个节点的指针,哈希表和下标用来++访问,哈希表需要支持修改,传入指针,const为了常迭代器可以传递哈希表
++
当前节点的next有内容,先遍历完当前桶。否则下标++,寻找下一个不为空的桶
self& operator++()
{
if (_node->_next)
{
//单个桶
_node = _node->_next;
}
else
{
//下一个桶
_hashi++;
while (_hashi < _pht->_table.size())
{
if (_pht->_table[_hashi])
{
_node = _pht->_table[_hashi];
break;
}
_hashi++;
}
//循环结束没有数据
if (_hashi == _pht->_table.size())
{
_node = nullptr;
}
}
return *this;
}
类
迭代器需要访问哈希表,带上友元
begin返回第一个不为空的桶,end返回空
凡是数据比较的地方都需要用仿函数
全
#pragma once
#pragma once
#include <string>
#include <iostream>
#include <vector>
template <class T>
struct HashNode
{
HashNode<T>* _next;
T _data;
HashNode(const T& data)
:_data(data), _next(nullptr)
{}
};
//hash int
template <class K>
struct HashFunc
{
size_t operator()(const K& key)
{
return (size_t)key;
}
};
//字符串模板特化,string
template <>
struct HashFunc<std::string>
{
size_t operator()(const std::string& key)
{
//BKDR方法
size_t hash = 0;
for (auto ch : key)
{
hash *= 31;
hash += ch;
}
return hash;
}
};
//前置声明
template <class K, class T, class KeyOfT, class Hash>
class HashBucket;
template <class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
struct __HashIterator
{
typedef HashNode<T> node;
typedef __HashIterator<K, T, Ref, Ptr, KeyOfT, Hash> self;
node* _node;
const HashBucket<K, T, KeyOfT, Hash>* _pht;
size_t _hashi;
__HashIterator(node* node, HashBucket<K, T, KeyOfT, Hash>* pht, size_t hashi)
:_node(node), _pht(pht), _hashi(hashi)
{}
__HashIterator(node* node, const HashBucket<K, T, KeyOfT, Hash>* pht, size_t hashi)
:_node(node), _pht(pht), _hashi(hashi)
{}
bool operator!=(const self& x)
{
return _node != x._node;
}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
self& operator++()
{
if (_node->_next)
{
//单个桶
_node = _node->_next;
}
else
{
//下一个桶
_hashi++;
while (_hashi < _pht->_table.size())
{
if (_pht->_table[_hashi])
{
_node = _pht->_table[_hashi];
break;
}
_hashi++;
}
//循环结束没有数据
if (_hashi == _pht->_table.size())
{
_node = nullptr;
}
}
return *this;
}
};
//unordered_set hashpackage<K, K>
//unordered_set hashpackage<K, pair<K ,V>>
//keyoft取出插入数据的key,hash将其他类型转为整形
template <class K, class T, class KeyOfT, class Hash>
class HashBucket
{
typedef HashNode<T> node;
//typedef __HashIterator<K, T, KeyOfT, Hash, const T&, const T*> const_iterator;
template <class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
friend struct __HashIterator;
public:
typedef __HashIterator<K, T, T&, T*, KeyOfT, Hash> iterator;
typedef __HashIterator<K, T, const T&, const T*, KeyOfT, Hash> const_iterator;
iterator begin()
{
for (size_t i = 0; i < _table.size(); i++)
{
if (_table[i])
{
return iterator(_table[i], this, i);
}
}
//如果都为空
return end();
}
iterator end()
{
return iterator(nullptr, this, -1);
}
const_iterator begin() const
{
for (size_t i = 0; i < _table.size(); i++)
{
if (_table[i])
{
return const_iterator(_table[i], this, i);
}
}
}
//const修饰this,传入const HashBucket对象
const_iterator end() const
{
return const_iterator(nullptr, this, -1);
}
public:
HashBucket()
{
_table.resize(10);
}
std::pair<iterator, bool> insert(const T& data)
{
KeyOfT kot;
iterator it = find(kot(data));
if (it != end())
{
return std::make_pair(it, false);
}
Hash hf;
//负载因子,1
if (_n == _table.size())
{
//扩容
size_t newsize = _table.size() * 2;
std::vector<node*> newtable;
newtable.resize(newsize, nullptr);
//遍历旧表
for (size_t i = 0; i < _table.size(); i++)
{
node* cur = _table[i];
while (cur)
{
node* next = cur->_next;
//挪动到新表
size_t hashi = hf(kot(cur->_data)) % newtable.size();
cur->_next = newtable[hashi];
newtable[hashi] = cur;
cur = next;
}
//旧表还指向节点,置空
_table[i] = nullptr;
}
_table.swap(newtable);
}
//Hash hf;
size_t hashi = hf(kot(data)) % _table.size();
node* newnode = new node(data);
//头插
newnode->_next = _table[hashi];
_table[hashi] = newnode;
_n++;
return std::make_pair(iterator(newnode, this, hashi), true);
}
iterator find(const K& key)
{
KeyOfT kot;
Hash hf;
//线性探测,字符串需要转整数
size_t hashi = hf(key) % _table.size();
node* cur = _table[hashi];
while (cur)
{
if (kot(cur->_data) == key)
{
return iterator(cur, this, hashi);
}
cur = cur->_next;
}
return end();
}
bool erase(const K& key)
{
KeyOfT kot;
Hash hf;
size_t hashi = hf(key) % _table.size();
node* prev = nullptr;
node* cur = _table[hashi];
while (cur)
{
//删除
if (kot(cur->_data) == key)
{
if (prev == nullptr)
{
_table[hashi] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
delete cur;
return true;
}
prev = cur;
cur = cur->_next;
}
return false;
}
void print()
{
for (size_t i = 0; i < _table.size(); i++)
{
if (_table[i])
{
node* cur = _table[i];
while (cur)
{
std::cout << "[" << i << "]->" << cur->_kv.first <<
":" << cur->_kv.second << " ";
cur = cur->_next;
}
std::cout << std::endl;
}
else
{
printf("[%d]->\n", i);
}
}
}
~HashBucket()
{
for (size_t i = 0; i < _table.size(); i++)
{
node* del = _table[i];
while (del)
{
node* next = del->_next;
delete del;
del = next;
}
_table[i] = nullptr;
}
}
//桶情况
void some()
{
/*size_t bucketsize = 0;
size_t maxbucketlen = 0;
size_t sum = 0;
double averagebucketlen = 0;
for (size_t i = 0; i < _table.size(); i++)
{
if (_table[i])
{
node* cur = _table[i];
int len = 0;
while (cur)
{
cur = cur->_next;
len++;
}
if (maxbucketlen < len)
{
maxbucketlen = len;
}
sum += len;
bucketsize++;
}
}
averagebucketlen = (double)sum / (double)bucketsize;
printf("哈希表大小:%d\n", _table.size());
printf("桶大小:%d\n", bucketsize);
printf("最大桶:%d\n", maxbucketlen);
printf("平均桶:%lf\n", averagebucketlen);*/
size_t bucketSize = 0;
size_t maxBucketLen = 0;
size_t sum = 0;
double averageBucketLen = 0;
for (size_t i = 0; i < _table.size(); i++)
{
node* cur = _table[i];
if (cur)
{
++bucketSize;
}
size_t bucketLen = 0;
while (cur)
{
++bucketLen;
cur = cur->_next;
}
sum += bucketLen;
if (bucketLen > maxBucketLen)
{
maxBucketLen = bucketLen;
}
}
averageBucketLen = (double)sum / (double)bucketSize;
printf("插入数据:%d\n", _n);
printf("all bucketSize:%d\n", _table.size());
printf("bucketSize:%d\n", bucketSize);
printf("maxBucketLen:%d\n", maxBucketLen);
printf("averageBucketLen:%lf\n\n", averageBucketLen);
}
private:
std::vector<node*> _table;
size_t _n = 0; //个数
};
unordset
K和V都传K,为了保证key不能修改,使用const迭代器,hash字符串转换模板在这一层传入
插入的返回值是pair,这里哈希表返回的是普通迭代器,需要构造成const迭代器返回
std::pair<const_iterator, bool> insert(const K& key)
{
auto ret = _ht.insert(key);
return std::pair<const_iterator, bool>(const_iterator(ret.first._node,
ret.first._pht, ret.first._hashi), ret.second);
}
全
#pragma once
#include "hashpackage.h"
template <class K, class Hash = HashFunc<K>>
class unordset
{
struct SetOfK
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename HashBucket<K, K, SetOfK, Hash>::const_iterator iterator;
typedef typename HashBucket<K, K, SetOfK, Hash>::const_iterator const_iterator;
const_iterator begin() const
{
return _ht.begin();
}
const_iterator end() const
{
return _ht.end();
}
std::pair<const_iterator, bool> insert(const K& key)
{
auto ret = _ht.insert(key);
return std::pair<const_iterator, bool>(const_iterator(ret.first._node,
ret.first._pht, ret.first._hashi), ret.second);
}
iterator find(const K& key)
{
return _ht.find(key);
}
bool erase(const K& key)
{
return _ht.erase(key);
}
private:
HashBucket<K, K, SetOfK, Hash> _ht;
};
unordsmap
提供[]运算,返回迭代器的数据
全
#pragma once
#include "hashpackage.h"
template <class K, class V, class Hash = HashFunc<K>>
class unordmap
{
struct SetOfV
{
const K& operator()(const std::pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename HashBucket<K, std::pair<const K, V>, SetOfV, Hash>::iterator iterator;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
std::pair<iterator, bool> insert(const std::pair<K, V>& kv)
{
return _ht.insert(kv);
}
V& operator[](const K& key)
{
std::pair<iterator, bool> ret = _ht.insert(std::make_pair(key, V()));
return ret.first->second;
}
const V& operator[](const K& key) const
{
std::pair<iterator, bool> ret = _ht.insert(std::make_pair(key, V()));
return ret.first->second;
}
iterator find(const K& key)
{
return _ht.find(key);
}
bool erase(const K& key)
{
return _ht.erase(key);
}
private:
HashBucket<K, std::pair<const K, V>, SetOfV, Hash> _ht;
};