底层是哈希表,先介绍下什么是哈希表,前面的笔记有写,这里回忆一下
我上个笔记实现的哈希表指的是数组中存链表,而链表中存想要存的数据,而链表是自己实现的,
链表:前一个元素的地址,下一个元素地址,要存的数据(可以是pair<K,V>类型的数据,也可以是K类型的数据,这是要一一个hash表来封装两个容器,也就是说是公用一个hash表)
迭代器
要封装成容器,必不可少的就是迭代器iterator,所以要先实现迭代器
先实现底层hash表的迭代器,再在此基础上封装上层迭代器
先实现迭代器的什么功能
强调功能确定成员变量(在实现类的时候)
首先迭代器类创建出来,而里面的成员根据要实现的功能来确定,也就是说先确定大概的 功能
然后在功能基础上实现成员,大框架有后,剩下的就是填充
里面的成员根据自增(++)来确定,例如在表中的某个桶的某个位置,此时想要迭代到下一个元素,此时要分几种情况
其中一种情况是直接到此桶的下一个元素
另一种情况是此桶没有下个元素,此时就需要找到下个不为空的桶
我们在这里把list叫做 哈希表元素,而迭代器里面的成员包括list里的元素(节点)
而要解决第二种情况,找到下一个不为空,需要哈希表,这样就确定了另一个成员变量,而为了每次在查找下个不为空的桶的时候,需要知道走到空的的位置,也就是说是第几个桶,从第几个桶开始查找,确定查找的起始位置,
这就确定了另一个成员变量,当前桶的位置
这样就哈希表迭代器的成员变量1.节点2.哈希表3.桶的位置
迭代器的基本功能
能自增自减(++)(--)(->)(*)(!=)(==)
迭代器成员变量知道后这些功能就简单些
iterator和const_iterator
两种迭代器的区别就是那几个成员函数返回类型包括const,为了减少重复代码,可以把返回类型改成模板类型,
V(数据类型),Ptr(数据的指针类型),Ref(数据的引用),在哈希表中可以迭代器类(迭代器是在哈希表外部实现,在内部进行重命名,相当于在哈希表内部创建 迭代器类),根据模板参数来确定迭代器类型,
封装
以上完成的hash表就已经是unordered_map,而为了兼容unordered_set,需要更改哈希表存的类型,从pair<K,V>类型改成K类型,根据在这两个头文件来决定传的参数类型是pair<K,V>还是K类型,
这两个容器的区别就是存的数据类型不同
再取余数的时候,需要判断是pair类型的还是K类型的,这里就需要仿函数,在封装的头文件传仿函数,
这样模板参数多了一个判断类型的仿函数,
在哈希表内部使用对数据取余数的方式来确定存在哪个桶里,而如果这个数据不是整数,就需要先把数据映射成整数,这就需要另一个仿函数来映射,这样模板参数就又多一个,
总结
迭代器的成员变量需要根据功能来确定
减少代码冗余可以选用模板(例如iterator和const_iterator)
代码部分
#pragma once
#include<iostream>
#include<vector>
#include<string>
using namespace std;
template<class K, class V >
class HashElement;
template<class K,class V,class Ptr,class Ref,class fun >
class _iterator
{
public:
typedef _iterator<K ,V, Ptr, Ref,fun> Self;
typedef HashElement<K,V> HashElement;
public:
HashElement*_node;
vector<HashElement*>_arr;
int _bucketposition;
fun f;
public:
_iterator()
:_node(nullptr)
,_bucketposition(0)
{}
_iterator( HashElement*node,const int bucketposition,const vector<HashElement*>arr)
{
_node = node;
_arr = arr;
_bucketposition = bucketposition;
}
_iterator(const _iterator& it)
{
_node = it._node;
_arr = it._arr;
_bucketposition = it._bucketposition;
}
Self operator=(const _iterator& it)
{
_node = it._node;
_arr = it._arr;
_bucketposition = it._bucketposition;
return *this;
}
Self operator++()
{
if (_node != nullptr&&_node->_next==nullptr&&_bucketposition<_arr.capacity())
{
_bucketposition++;
if (_bucketposition == _arr.capacity())
{
_node = nullptr;
return *this;
}
while (_bucketposition < _arr.capacity())
{
if (_arr[_bucketposition] != nullptr)
{
_node = _arr[_bucketposition];
return *this;
}
_bucketposition++;
}
_node = nullptr;
return *this;
}
if(_node!=nullptr)
_node = _node->_next;
return *this;
}
Self operator--()
{
if (_node != nullptr && _node->_pre == nullptr)
{
_bucketposition--;
while (_bucketposition >= 0)
{
if (_arr[_bucketposition] != nullptr)
{
_node = _arr[_bucketposition];
return *this;
}
_bucketposition--;
}
//return _iterator(nullptr);
}
_node = _node->_pre;
return *this;
}
Ptr operator->()
{
return &f(_node->_data);
}
Ref operator*()
{
return f(_node->_data);
}
bool operator!=(Self it)
{
return _node != it._node;
}
};
template<class K,class V>
class HashElement
{
public:
typedef HashElement<K,V> HahsElement;
public:
HashElement() = default;
K _data;
HahsElement* _next = nullptr;
HashElement* _pre = nullptr;
//State _state = Empty;
HashElement(K data)
{
_data = data;
_next = nullptr;
_pre = nullptr;
}
};
class _relation
{
int operator()(int data)
{
return data;
}
};
//fun代表数据类型
template<class K,class V, class fun ,class relation >
class HashTable
{
public:
typedef HashElement<K,V> HashElement;
typedef _iterator<K, V,V*,V&,fun> Iterator;
typedef _iterator<K, V, const V*, const V&,fun> const_Iterator;
public:
vector<HashElement*> _arr;
int _size = 0;
public:
fun f;
relation r;
//迭代器
Iterator begin()
{
int i = 0;
for (i = 0; i < _arr.size(); i++)
{
if(_arr[i]!=nullptr)
return Iterator(_arr[i],i,_arr);
}
return Iterator(nullptr,i,_arr);
}
Iterator end()
{
return Iterator(nullptr, _arr.capacity(), _arr);
}
const_Iterator cbegin()const
{
int i = 0;
for (i = 0; i < _arr.size(); i++)
{
if (_arr[i] != nullptr)
return const_Iterator(_arr[i], i, _arr);
}
return const_Iterator(nullptr, i, _arr);
}
const_Iterator cend()const
{
return const_Iterator(nullptr, _arr.capacity(), _arr);
}
pair<Iterator,bool> Insert(K data)
{
//判断扩容
if (_size * 10 / _arr.size() >= 7)
{
int i = 0;
vector<HashElement*> newtable;
newtable.resize(2 * _arr.size());
for (i = 0; i < _arr.size(); i++)
{
HashElement* cur = _arr[i];
while (cur)
{
int remainer = r(f(cur->_data)) % newtable.size();
if (newtable[remainer] == nullptr)
{
newtable[remainer] = cur;
HashElement*next = cur->_next;
newtable[remainer]->_next = nullptr;
cur = next;
}
else
{
HashElement* next = cur->_next;
cur->_next = newtable[remainer];
cur->_pre = nullptr;
newtable[remainer]->_pre = cur;
newtable[remainer] = cur;
cur = next;
}
}
}
swap(_arr, newtable);
int remainer = r(f(data)) % _arr.size();
if (_arr[remainer] == nullptr)
{
_arr[remainer] = new HashElement(data);
}
else
{
HashElement* newnode = new HashElement(data);
newnode->_next = _arr[remainer];
newnode->_pre = nullptr;
_arr[remainer]->_pre = newnode;
_arr[remainer] = newnode;
}
_size++;
return make_pair(Iterator(_arr[remainer], remainer, _arr), 1);
}
int remainer = r(f(data)) % _arr.size();
if (_arr[remainer] == nullptr)
{
_arr[remainer] = new HashElement(data);
}
else
{
HashElement* newnode = new HashElement(data);
newnode->_next = _arr[remainer];
newnode->_pre = nullptr;
_arr[remainer]->_pre = newnode;
_arr[remainer] = newnode;
}
_size++;
return make_pair(Iterator(_arr[remainer],remainer,_arr), 1);
}
Iterator Find(K key)
{
int remainer = r(f(key)) % _arr.size();
if (_arr[remainer] != nullptr)
{
HashElement* cur = _arr[remainer];
while (cur)
{
if (r(f(cur->_data)) == key)
{
return make_pair(Iterator(cur, remainer, _arr), true);
}
cur = cur->_next;
}
return make_pair(end(), false);
}
return make_pair(end(), false);
}
HashTable()
{
_arr.resize(10);
}
bool Erase(K key)
{
int remainer = r(f(key)) % _arr.size();
if (_arr[remainer] != nullptr)
{
HashElement* cur = _arr[remainer];
while (cur)
{
if (r(f(cur->_data)) == key)
{
if (cur->_pre == nullptr)
{
HashElement* next = cur->_next;
delete cur;
if(next)
next->_pre = nullptr;
_arr[remainer] = next;
_size--;
return true;
}
else
{
HashElement* next = cur->_next;
HashElement* pre = cur->_pre;
pre->_next = next;
if(next)
next->_pre = pre;
_arr[remainer] = next;
delete cur;
_size--;
return true;
}
}
cur = cur->_next;
}
return false;
}
return false;
}
};
#pragma once
#include"Hash.h"
class _SetFun
{
public:
int& operator()(int data)
{
return data;
}
};
class _Relation
{
public:
int operator()(int data)
{
return data;
}
};
template<class K,class SetFun=_SetFun,class Relation=_Relation>
class unorderedSet
{
public:
typedef HashElement<K, K> HahsElement;
typedef _iterator<K, K, K*, K&, SetFun> iterator;
typedef _iterator<K, K,const K*,const K&, SetFun> const_iterator;
private:
HashTable<K, K, SetFun, Relation> unordered_Set;
public:
pair<iterator, bool> Isert(K data)
{
return unordered_Set.Insert(data);
}
bool Erase(K data)
{
return unordered_Set.Erase(data);
}
iterator begin()
{
return unordered_Set.begin();
}
iterator end()
{
return unordered_Set.end();
}
const_iterator cbegin()
{
return unordered_Set.cbegin();
}
const_iterator cend()
{
return unordered_Set.cend();
}
};
#pragma once
#include"Hash.h"
template<class K,class V>
class _MapFun
{
public:
int &operator()(pair<K,V> data)
{
return data.first;
}
};
class _MapRelation
{
public:
int operator()(int data)
{
return data;
}
};
template<class K,class V,class MapFun=_MapFun<K,V>,class MapRelation=_MapRelation>
class Unordered_map
{
public:
typedef _iterator<pair<K,V>, V, V*, V&,MapFun> iterator;
typedef _iterator<pair<K,V>, V,const V*,const V&,MapFun> const_iterator;
private:
HashTable<pair<K, V>, V, MapFun, MapRelation> unorderedMap;
public:
pair<iterator, bool> Insert(pair<K,V> data)
{
return unorderedMap.Insert(data);
}
bool Erase(pair<K,V> key)
{
return unorderedMap.Erase(key);
}
iterator begin()
{
return unorderedMap.begin();
}
iterator end()
{
return unorderedMap.end();
}
const_iterator cbegin()
{
return unorderedMap.cbegin();
}
const_iterator cend()
{
return unorderedMap.cend();
}
};