1.什么是哈希表
哈希表是一种数据结构,用来存放数据的,哈希表存放的数据是无序的,可以实现增删查,当时不能修改数据。可以不经过任何比较,一次直接从表中得到要搜索的元素。如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)。
unordered_map是存储键值对的关联式容器,其允许通过keys快速的索引到与其对应的value。
在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同。
在内部,unordered_map没有对按照任何特定的顺序排序, 为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。
unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。
unordered_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。
它的迭代器至少是前向迭代器。unorder_set是用来存储
的关联式容器,可以用来快速的查找和去重,在内部是按照无序的方式排列的,它的迭代器和unorder_map的使用相同,其他的特性和unorder_map的特性差不多。
2.哈希冲突
对于两个数据元素的关键字$k_i$和 $k_j$(i != j),有$k_i$ != $k_j$,但有:Hash($k_i$) ==
Hash($k_j$),即:不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”。解决哈希冲突:
引起哈希冲突的一个原因可能是:哈希函数设计不够合理。
哈希函数设计原则:
哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值
域必须在0到m-1之间;哈希函数计算出来的地址能均匀分布在整个空间中;哈希函数应该比较简单。解决哈希冲突两种常见的方法是:闭散列和开散列
闭散列:
线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
通过哈希函数获取待插入元素在哈希表中的位置,如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突,使用线性探测找到下一个空位置,插入新元素。
开散列:
开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地
址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链
接起来,各链表的头结点存储在哈希表中。开散列与闭散列比较:
应用链地址法处理溢出,需要增设链接指针,似乎增加了存储开销。事实上:
由于开地址法必须保持大量的空闲空间以确保搜索效率,如二次探查法要求装载因子a <=
0.7,而表项所占空间又比指针大的多,所以使用链地址法反而比开地址法节省存储空间。
3.哈希表的实现
闭散列的实现:
#include
#include
#include
//usng namespace std;
using std::cout;
using std:: endl;
using std::cin;
//闭散列
namespace open_address
{
//处理不是整形的字符
template
struct DefaultHashFunc
{
size_t operator()(const T& t)
{
return size_t(value(t));
}
};
//特殊化处理字符串
template<>
struct DefaultHashFunc
{
const size_t operator()(const string& t)
{
//KeyofT value;
size_t num=1;
for (auto e : t)
{
num *= 131;
num +=e;
}
return num;
}
};
//枚举三种状态
enum State
{
Empty,
Exist,
Delete
};
//哈希节点
template
struct HashDateNode
{
private:
T _kv;
State _state=Empty;
};
//哈希表
template
class HashTable
{
typedef HashDateNode Node;
HashTable()//初始化,开辟10个空间
{
_Date.resize(10);
}
//插入数值
bool insert(const T& Date)
{
DefaultHashFunc Func;//处理字符串问题
KeyofT value;//处理set和map的数值问题函数
//扩容
if (n * 10 > _Date.size() * 7)//负载因子
{
int newsize = _Date.size() * 2;
vector newHT;
newHT.resize(newsize);//开辟空间
for (int i = 0; i < _Date.size(); i++)
{
if (_Date._state == Exist)//讲旧数据写入新空间中
{
newHT.insert(KetofT(_Date));
}
_Date.swap(newHT._Date);//交换数据
}
}
//插入哈希表
size_t hashi =Func(value(Date))% _Date.size();
while (_Date[hashi]._state == Exist)//存在就++
{
++hashi;
hashi %= _Date.size();
}
_Date[hashi]._kv = Date;
_Date[hashi]._state = Exist;
n++;//存放个数加一
return true;
}
//查找函数
vector Find(const K& t)
{
DefaultHashFunc Func;
KeyofT value;
size_t hashi = Func(value(t)) % _Date.size();
while (_Date[hashi]._state != Empty)
{
if (_Date[hashi]._state == Exist
&& value(_Date[hashi]) == t)
{
return _Date[hashi];
}
++hashi;
hashi %= _Date.size();
}
return nullptr;
}
//删除
bool erash(const K& key)
{
vector ret = Find(key);//查找是否存在
if (ret)
{
ret._state= Exist;
n--;
return true;
}
return false;
}
private:
vector _Date;//数据
size_t n;//存储有效个数
};
}
开散列的实现
#include
#include
#include
using namespace std;
//处理字符
template
struct DefaultHashFunc
{
size_t operator()(const T& t)
{
return size_t(t);
}
};template<>
struct DefaultHashFunc
{
size_t operator()(const string& t)
{
size_t num = 0;
for (auto e : t)
{
num *= 131;
num += e;
}
return num;
}
};
//哈希桶,闭散列
namespace hash_bucket
{
template
struct HashDateNode
{
T _Date;
HashDateNode* _next;
HashDateNode(const T& Date)
:_Date(Date)
,_next(nullptr)
{}
};
template
class HashDate;//前置声明
//迭代器
//template//旧版
template//新版
struct HashIterator
{
typedef HashDateNode Node;
typedef HashIterator Self;
typedef HashIterator iterator;
Node* _node;
const HashDate* _pht; //设置位const ,防止普通类型无法转化为const类型
//初始化
/*const HashIterator(Node* node, HashDate* pht)
:_node(node)
, _pht(pht)
{}*/
//const初始化
HashIterator(Node* node, const HashDate* pht)
:_node(node)
, _pht(pht)
{}
// 普通迭代器时,他是拷贝构造
// const迭代器时,他是构造函数
HashIterator(const iterator& it)//防止set类型的const类型与非const类型的转换(模板不同)
:_node(it._node)
, _pht(it._pht)
{}
Ref operator*()
{
return _node->_Date;
}
Ptr operator->()
{
return &_node->_Date;
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
bool operator==(const Self& s)
{
return _node == s._node;
}
Self& operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
HashFunc Func;
KeyofT value;
size_t hashi = Func(value(_node->_Date)) % _pht->_table.size(); //该用仿函数
//从下一个哈希桶查找
hashi++;
while (hashi < _pht->_table.size())
{
if (_pht->_table[hashi])//不为空
{
_node = _pht->_table[hashi];
return *this;
}
else//为空
{
++hashi;
}
}
_node = nullptr;
}
return *this;
}
};
template>
class HashDate
{
typedef HashDateNode Node;
//
//友元
template
friend struct HashIterator;//可以使用迭代器
public:
typedef HashIterator iterator;
typedef HashIterator const_iterator;
iterator begin()
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
if (cur)
{
return iterator(cur,this);
}
}
return iterator(nullptr, this);
}
const_iterator begin() const
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
if (cur)
{
return iterator(cur, this);
}
}
return iterator(nullptr, this);
}
iterator end()
{
return iterator(nullptr, this);
}
const_iterator end() const
{
return iterator(nullptr, this);
}
HashDate()
{
_table.resize(10, nullptr);
}
~HashDate()
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
_table[i] = nullptr;
}
}
pair Insert(const T& date)
{
KeyofT value;
HashFunc Func;
iterator it = Find(value(date));
//it!=end()
if(it != end())
{
return make_pair(it,false);
}
if (n == _table.size())//扩容
{
int newsize = _table.size() * 2;
vector newHash;
newHash.resize(newsize);
for (size_t i = 0; i < _table.size(); i++)//旧数据
{
Node* cur = _table[i];
while (cur)
{
Node* next = cur->_next;
size_t hashi = Func(value(cur->_Date))% newsize;
cur->_next = newHash[hashi];
newHash[hashi] = cur;
cur = next;
}
_table[i] = nullptr;
}
_table.swap(newHash);//交换数据
}
//插入
size_t hashi = Func(value(date))% _table.size();//改变
//Node* cur = _table[hashi];
//尾插
//Node* newNode = new Node(date);
//while (cur)
//{
// cur = cur->_next;
//}
//cur = newNode;
//头插
Node* newNode = new Node(date);//新节点
newNode->_next = _table[hashi];//头结点
_table[hashi] = newNode;//尾节点
n++;
return make_pair(iterator(newNode,this),true);
}
//查找
iterator Find(const K& key)//Find为K类型的只用一个数值,T类型的在map中为pair类型
{
HashFunc Func;
KeyofT value;
size_t hashi = Func(key) % _table.size();
//size_t hashi = Func(value(key)) % _table.size();//不能使用这个
Node* cur = _table[hashi];
while (cur)
{
if (value(cur->_Date) == key)//?
{
return iterator(cur,this);
}
cur = cur->_next;
}
return iterator(nullptr,this);
}
//删除
bool Erase(const K& key)
{
HashFunc Func;
KeyofT value;
iterator ret=Find(key);
if (ret == end())
return true;
size_t x = Func(value(key))% _table.size();
Node* cur = _table[x];
Node* prev = nullptr;
while (cur)
{
if (value(cur->_Date) == key)
{
if (prev == nullptr)
{
_table[x] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
}
prev = cur;
cur = cur->_next;
delete cur;
return true;
}
return false;
}
//打印
void Print()
{
for (int i = 10; i < _table.size(); i++)
{
Node* cur = _table[i];
while (cur)
{
std::cout << cur->_Date.first<<" " << cur->_Date.second <<" " << std::endl;
cur = cur->_next;
}
}
std::cout << std::endl;
}
private:
vector _table; //存储数据
size_t n=0; //记录容器中的个数
};
}
4.Unorderset和Unordermap的实现
4.1 Unorderset
#pragma once
#include "HashTable.h"
using namespace hash_bucket;
//using namespace open_address;
template
class Unorderset
{
struct SetKeyofT
{
const K& operator()(const K& k)
{
return k;
}
};
public:
typedef typename hash_bucket::HashDate::const_iterator iterator;
typedef typename hash_bucket::HashDate::const_iterator const_iterator;
//typedef typename hash_bucket::HashDate Hash;
public:
const_iterator begin() const
{
return _ht.begin();
}
const_iterator end() const
{
return _ht.end();
}
pair insert(const K& k)
{
return _ht.Insert(k);
}
iterator find(const K& kk)
{
return _ht.Find(kk);
}
bool erase(const K& kk)
{
return _ht.Erase(kk);
}
private:
HashDate _ht;
};
4.2 Unordermap
#pragma once
#include "HashTable.h"
using namespace hash_bucket;
template
class Unordermap
{
struct MapkeyofT
{
const K& operator()(const pair& kt)
{
return kt.first;
}
};
public:
typedef typename hash_bucket::HashDate, MapkeyofT>::iterator iterator;//普通迭代器
typedef typename hash_bucket::HashDate, MapkeyofT>::const_iterator const_iterator;//const迭代器
//typedef typename hash_bucket::HashDate, MapkeyofT> Hash;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
const_iterator begin() const
{
return _ht.begin();
}
const_iterator end() const
{
return _ht.end();
}
//插入
pair insert(const pair& kt)
{
return _ht.Insert(kt);
}
//查找
iterator find(const K& kk)
{
return _ht.Find(kk);
}
//重载[]
T& operator[](const K& kk)
{
pair ret = insert(make_pair(kk, T()));
return ret.first->second;
}
//删除
bool eraser(const K& kk)
{
return _ht.Erase(kk);
}
private:
HashDate, MapkeyofT> _ht;
};
4.3 完整代码
Ps:具体实现中建议分开写
#pragma once
#include "HashTable.h"
using namespace hash_bucket;
using namespace open_address;
//set实现
template
class Unorderset
{
struct SetKeyofT
{
const K& operator()(const K& k)
{
return k;
}
};
public:
typedef typename hash_bucket::HashDate::const_iterator iterator;
typedef typename hash_bucket::HashDate::const_iterator const_iterator;
//typedef typename hash_bucket::HashDate Hash;
public:
const_iterator begin() const
{
return _ht.begin();
}
const_iterator end() const
{
return _ht.end();
}
pair insert(const K& k)
{
return _ht.Insert(k);
}
iterator find(const K& kk)
{
return _ht.Find(kk);
}
bool erase(const K& kk)
{
return _ht.Erase(kk);
}
private:
HashDate _ht;
};
//map实现
template
class Unordermap
{
struct MapkeyofT
{
const K& operator()(const pair& kt)
{
return kt.first;
}
};
public:
typedef typename hash_bucket::HashDate, MapkeyofT>::iterator iterator;//普通迭代器
typedef typename hash_bucket::HashDate, MapkeyofT>::const_iterator const_iterator;//const迭代器
//typedef typename hash_bucket::HashDate, MapkeyofT> Hash;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
const_iterator begin() const
{
return _ht.begin();
}
const_iterator end() const
{
return _ht.end();
}
//插入
pair insert(const pair& kt)
{
return _ht.Insert(kt);
}
//查找
iterator find(const K& kk)
{
return _ht.Find(kk);
}
//重载[]
T& operator[](const K& kk)
{
pair ret = insert(make_pair(kk, T()));
return ret.first->second;
}
//删除
bool eraser(const K& kk)
{
return _ht.Erase(kk);
}
private:
HashDate, MapkeyofT> _ht;
};
//底层实现
#pragma once//防止头文件重复引用
#include
#include
#include
using namespace std;
//处理不是整形的字符
template
struct DefaultHashFunc
{
size_t operator()(const T& t)
{
return size_t(value(t));
}
};
//特殊化处理字符串
template<>
struct DefaultHashFunc
{
const size_t operator()(const string& t)
{
//KeyofT value;
size_t num=1;
for (auto e : t)
{
num *= 131;
num +=e;
}
return num;
}
};
//开散列
namespace open_address
{
//枚举三种状态
enum State
{
Empty,
Exist,
Delete
};
//哈希节点
template
struct HashDateNode
{
private:
T _kv;
State _state=Empty;
};
//哈希表
template
class HashTable
{
typedef HashDateNode Node;
HashTable()//初始化,开辟10个空间
{
_Date.resize(10);
}
//插入数值
bool insert(const T& Date)
{
DefaultHashFunc Func;//处理字符串问题
KeyofT value;//处理set和map的数值问题函数
//扩容
if (n * 10 > _Date.size() * 7)//负载因子
{
int newsize = _Date.size() * 2;
vector newHT;
newHT.resize(newsize);//开辟空间
for (int i = 0; i < _Date.size(); i++)
{
if (_Date._state == Exist)//讲旧数据写入新空间中
{
newHT.insert(KetofT(_Date));
}
_Date.swap(newHT._Date);//交换数据
}
}
//插入哈希表
size_t hashi =Func(value(Date))% _Date.size();
while (_Date[hashi]._state == Exist)//存在就++
{
++hashi;
hashi %= _Date.size();
}
_Date[hashi]._kv = Date;
_Date[hashi]._state = Exist;
n++;//存放个数加一
return true;
}
//查找函数
vector Find(const K& t)
{
DefaultHashFunc Func;
KeyofT value;
size_t hashi = Func(value(t)) % _Date.size();
while (_Date[hashi]._state != Empty)
{
if (_Date[hashi]._state == Exist
&& value(_Date[hashi]) == t)
{
return _Date[hashi];
}
++hashi;
hashi %= _Date.size();
}
return nullptr;
}
//删除
bool erash(const K& key)
{
vector ret = Find(key);//查找是否存在
if (ret)
{
ret._state= Exist;
n--;
return true;
}
return false;
}
private:
vector _Date;//数据
size_t n;//存储有效个数
};
}
//哈希桶,闭散列
namespace hash_bucket
{
template
struct HashDateNode
{
T _Date;
HashDateNode* _next;
HashDateNode(const T& Date)
:_Date(Date)
,_next(nullptr)
{}
};
template
class HashDate;//前置声明
//迭代器
//template//旧版
template//新版
struct HashIterator
{
typedef HashDateNode Node;
typedef HashIterator Self;
typedef HashIterator iterator;
Node* _node;
const HashDate* _pht; //设置位const ,防止普通类型无法转化为const类型
//初始化
/*const HashIterator(Node* node, HashDate* pht)
:_node(node)
, _pht(pht)
{}*/
//const初始化
HashIterator(Node* node, const HashDate* pht)
:_node(node)
, _pht(pht)
{}
// 普通迭代器时,他是拷贝构造
// const迭代器时,他是构造函数
HashIterator(const iterator& it)//防止set类型的const类型与非const类型的转换(模板不同)
:_node(it._node)
, _pht(it._pht)
{}
Ref operator*()
{
return _node->_Date;
}
Ptr operator->()
{
return &_node->_Date;
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
bool operator==(const Self& s)
{
return _node == s._node;
}
Self& operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
HashFunc Func;
KeyofT value;
size_t hashi = Func(value(_node->_Date)) % _pht->_table.size(); //该用仿函数
//从下一个哈希桶查找
hashi++;
while (hashi < _pht->_table.size())
{
if (_pht->_table[hashi])//不为空
{
_node = _pht->_table[hashi];
return *this;
}
else//为空
{
++hashi;
}
}
_node = nullptr;
}
return *this;
}
};
template>
class HashDate
{
typedef HashDateNode Node;
//
//友元
template
friend struct HashIterator;//可以使用迭代器
public:
typedef HashIterator iterator;
typedef HashIterator const_iterator;
iterator begin()
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
if (cur)
{
return iterator(cur,this);
}
}
return iterator(nullptr, this);
}
const_iterator begin() const
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
if (cur)
{
return iterator(cur, this);
}
}
return iterator(nullptr, this);
}
iterator end()
{
return iterator(nullptr, this);
}
const_iterator end() const
{
return iterator(nullptr, this);
}
HashDate()
{
_table.resize(10, nullptr);
}
~HashDate()
{
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
_table[i] = nullptr;
}
}
pair Insert(const T& date)
{
KeyofT value;
HashFunc Func;
iterator it = Find(value(date));
//it!=end()
if(it != end())
{
return make_pair(it,false);
}
if (n == _table.size())//扩容
{
int newsize = _table.size() * 2;
vector newHash;
newHash.resize(newsize);
for (size_t i = 0; i < _table.size(); i++)//旧数据
{
Node* cur = _table[i];
while (cur)
{
Node* next = cur->_next;
size_t hashi = Func(value(cur->_Date))% newsize;
cur->_next = newHash[hashi];
newHash[hashi] = cur;
cur = next;
}
_table[i] = nullptr;
}
_table.swap(newHash);//交换数据
}
//插入
size_t hashi = Func(value(date))% _table.size();//改变
//Node* cur = _table[hashi];
//尾插
//Node* newNode = new Node(date);
//while (cur)
//{
// cur = cur->_next;
//}
//cur = newNode;
//头插
Node* newNode = new Node(date);//新节点
newNode->_next = _table[hashi];//头结点
_table[hashi] = newNode;//尾节点
n++;
return make_pair(iterator(newNode,this),true);
}
//查找
iterator Find(const K& key)//Find为K类型的只用一个数值,T类型的在map中为pair类型
{
HashFunc Func;
KeyofT value;
size_t hashi = Func(key) % _table.size();
//size_t hashi = Func(value(key)) % _table.size();//不能使用这个
Node* cur = _table[hashi];
while (cur)
{
if (value(cur->_Date) == key)//?
{
return iterator(cur,this);
}
cur = cur->_next;
}
return iterator(nullptr,this);
}
//删除
bool Erase(const K& key)
{
HashFunc Func;
KeyofT value;
iterator ret=Find(key);
if (ret == end())
return true;
size_t x = Func(value(key))% _table.size();
Node* cur = _table[x];
Node* prev = nullptr;
while (cur)
{
if (value(cur->_Date) == key)
{
if (prev == nullptr)
{
_table[x] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
}
prev = cur;
cur = cur->_next;
delete cur;
return true;
}
return false;
}
//打印
void Print()
{
for (int i = 10; i < _table.size(); i++)
{
Node* cur = _table[i];
while (cur)
{
std::cout << cur->_Date.first<<" " << cur->_Date.second <<" " << std::endl;
cur = cur->_next;
}
}
std::cout << std::endl;
}
private:
vector _table; //存储数据
size_t n=0; //记录容器中的个数
};
}