1.unordered_map和unordered_set对哈希桶的封装
1.1封装的准备
1.节点存放的是data;2.对于key的比较要使用仿函数KeyOfT类型的对象;
1.2迭代器的实现
1.2.1迭代器类成员设计
//由于++需要找到下一个桶位置,所以需要存一个哈希表指针方便查找桶的位置
node *node_;
HashTable<K, T, KeyOfT>* htptr_;
1.2.2++运算符的重载
1.如果当前位置的下一个不为空,node继续往下走;2.为空找下一个桶的位置,计算出当前key所映射的桶位置,从下一个桶开始,不断的往后++;3.如果桶不为空node指向此桶,为空向后++;4.如果最后表全部遍历完毕,没有找到就像红黑树一样,指向空;
1.2.3迭代器内部存放哈希表指针
会存在相互依赖的问题,即哈希表里面使用迭代器,迭代器里面使用哈希表,此时就需要用前置声明解决,但是前置声明不可以给缺省值,注意声明友元类时,对于g++会出现阴影模板参数,不允许模板参数名相同,解决方法就是修改模板参数名即可;
1.2.4对于const迭代器
注意要将哈希表指针改成const,因为unordered_set使用的都是const迭代器,需要传递this,但是*this不可以修改,所以要使用const接收指针;
1.2.5插入
不同的迭代器对象需要使用构造来解决;为了支持普通迭代器构造const迭代器,或者普通迭代器构造普通迭代器。insert返回pair类型
1.2.6operator[]
复用insert。
代码实现:
namespace HashBucket
{
template <class K>
struct Default // 仿函数强转为无符号整型
{
size_t operator()(const K &key)
{
return (size_t)key;
}
};
template <>
struct Default<std::string> // 模板的特化处理string字符串类型
{
size_t operator()(const std::string &key)
{
size_t i = 0;
for (const auto &ch : key)
{
i *= 131;
i += ch;
}
return i;
}
};
template <class T>
struct HashNode
{
HashNode(const T &data) : data_(data), next_(nullptr) {}
T data_;
HashNode<T> *next_;
};
template <class K, class T, class KeyOfT, class HashFunc = Default<K>>
class HashTable;
template <class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc>
struct __HashTableIterator
{
typedef HashNode<T> node;
typedef __HashTableIterator<K, T, Ptr, Ref, KeyOfT, HashFunc> Self;
typedef __HashTableIterator<K, T, T *, T &, KeyOfT, HashFunc> iterator;
__HashTableIterator(node *node, const HashTable<K, T, KeyOfT, HashFunc> *htptr) : node_(node), htptr_(htptr) {}
__HashTableIterator(const iterator &iter) : node_(iter.node_), htptr_(iter.htptr_) {}
Ref operator*()
{
return node_->data_;
}
Ptr operator->()
{
return &(node_->data_);
}
Self &operator++()
{
HashFunc func;
KeyOfT kot;
if (node_->next_)
{
node_ = node_->next_;
return *this;
}
else
{
size_t hashi = func(kot(node_->data_)) % htptr_->table_.size();
++hashi;
while (hashi < htptr_->table_.size())
{
if (htptr_->table_[hashi])
{
node_ = htptr_->table_[hashi];
return *this;
}
else
{
++hashi;
}
}
node_ = nullptr;
return *this;
}
}
bool operator!=(const Self &iterator) const
{
return node_ != iterator.node_;
}
bool operator==(const Self &iterator) const
{
return node_ == iterator.node_;
}
node *node_;
const HashTable<K, T, KeyOfT, HashFunc> *htptr_;
};
template <class K, class T, class KeyOfT, class HashFunc>
class HashTable
{
template <class K1, class T1, class Ptr1, class Ref1, class KeyOfT1, class HashFunc1>
friend struct __HashTableIterator;
typedef HashNode<T> node;
public:
typedef __HashTableIterator<K, T, T *, T &, KeyOfT, HashFunc> iterator;
typedef __HashTableIterator<K, T, const T *, const T &, KeyOfT, HashFunc> const_iterator;
public:
// 迭代器的实现
iterator begin()
{
for (size_t i = 0; i < table_.size(); ++i)
{
if (table_[i])
{
return {table_[i], this};
}
}
return {nullptr, this};
}
iterator end()
{
return {nullptr, this};
}
const_iterator begin() const
{
for (size_t i = 0; i < table_.size(); ++i)
{
if (table_[i])
{
return {table_[i], this};
}
}
return {nullptr, this};
}
const_iterator end() const
{
return {nullptr, this};
}
public:
HashTable() : size_(0)
{
table_.resize(10, nullptr);
}
~HashTable()
{
for (size_t i = 0; i < table_.size(); i++)
{
node *cur = table_[i];
while (cur)
{
node *next = cur->next_;
delete cur;
cur = next; //*cur被释放,cur->next就是野指针访问,所以需要记录next位置;
}
table_[i] = nullptr;
}
}
std::pair<iterator, bool> insert(const T &data)
{
KeyOfT kot;
HashFunc func;
iterator cur = find(kot(data));
if (cur != end())
{
return {cur, false};
}
// 扩容
if (size_ == 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 = func(kot(cur->data_)) % newsize;
cur->next_ = newtable[hashi];
newtable[hashi] = cur;
cur = cur->next_;
}
table_[i] = nullptr;
}
table_.swap(newtable);
}
size_t hashi = func(kot(data)) % table_.size();
// 头插 访问最新插入的元素较快
node *newnode = new node(data);
newnode->next_ = table_[hashi];
table_[hashi] = newnode;
++size_;
return {{newnode, this}, true};
}
iterator find(const K &key)
{
KeyOfT kot;
HashFunc func;
size_t hashi = func(key) % table_.size();
node *cur = table_[hashi];
while (cur)
{
if (kot(cur->data_) == key)
{
return {cur, this};
}
cur = cur->next_;
}
return {nullptr, this};
}
void print()
{
for (size_t i = 0; i < table_.size(); ++i)
{
KeyOfT kot;
printf("[%d] -> ", i);
node *cur = table_[i];
while (cur)
{
std::cout << kot(cur->data_) << " -> ";
cur = cur->next_;
}
if (!cur)
{
std::cout << "nullptr";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
bool erase(const K &key)
{
KeyOfT kot;
HashFunc func;
if (!find(key))
{
return false;
}
size_t hashi = func(key) % table_.size();
node *cur = table_[hashi];
node *prev = cur;
if (kot(cur->data_) == key)
{
table_[hashi] = cur->next_;
delete cur;
--size_;
return true;
}
else
{
while (cur)
{
if (kot(cur->data_) == key)
{
prev->next_ = cur->next_;
delete cur;
--size_;
return true;
}
prev = cur;
cur = cur->next_;
}
return false;
}
}
private:
std::vector<node *> table_;
size_t size_; // 记录存储了多少有效数据
};
}
namespace Unordered_map
{
template <class K, class V>
class unordered_map
{
struct MapKeyOfT
{
const K &operator()(const std::pair<K, V> &kv)
{
return kv.first;
}
};
public:
typedef typename HashBucket::HashTable<K, std::pair<const K, V>, MapKeyOfT>::iterator iterator;
typedef typename HashBucket::HashTable<K, std::pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;
iterator begin()
{
return hashtable_.begin();
}
iterator end()
{
return hashtable_.end();
}
const_iterator begin() const
{
return hashtable_.begin();
}
const_iterator end() const
{
return hashtable_.end();
}
public:
std::pair<iterator, bool> insert(const std::pair<const K, V> kv)
{
return hashtable_.insert(kv);
}
V &operator[](const K &key)
{
std::pair<iterator, bool> it = insert({key, V()});
return it.first->second;
}
private:
HashBucket::HashTable<K, std::pair<const K, V>, MapKeyOfT> hashtable_;
};
}
namespace Unordered_set
{
template <class K>
class unordered_set
{
struct SetKeyOfT
{
const K &operator()(const K &key)
{
return key;
}
};
public:
typedef typename HashBucket::HashTable<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename HashBucket::HashTable<K, K, SetKeyOfT>::const_iterator const_iterator;
iterator begin() const
{
return hashtable_.begin();
}
iterator end() const
{
return hashtable_.end();
}
public:
std::pair<iterator, bool> insert(const K &key)
{
std::pair<iterator, bool> it = hashtable_.insert(key);
return it;
}
private:
HashBucket::HashTable<K, K, SetKeyOfT> hashtable_;
};
}