文章目录
哈希概念:
- 顺序结构以及平衡树中,查找一个元素需要时间复杂度为O( l o g 2 N log2N log2N),搜索效率较低
- 理想搜索状态:不经过任何比较,通过某种函数使元素的存储位置和它的关键码之间建立一 一映射的关系,则查找通过该函数很快可以找到元素位置
- 哈希表是一种以空间换时间的思想
闭散列(开放定址法):
- 底层使用数组存储元素
- 映射关系:通过对元素 关键字(key) 取模数组容量,计算哈希地址
- 哈希冲突:映射到的位置有不同 key 值元素
- 线性探测:每次向后偏移一个位置,直到找到一个空位置,进行插入
- 缺点:如果出现冲突次数较多,则冲突的元素都会向后偏移,则造成数据的堆积
- 二次探测: 为了避免数据堆积,找下一个元素位置方法: p o s = p o s + i 2 pos = pos + i^2 pos=pos+i2
- 线性探测:每次向后偏移一个位置,直到找到一个空位置,进行插入
哈希节点:
enum state
{
EMPTY,
EXIST,
DELETE
};
template <class K, class V>
struct HashNode
{
pair<K, V> _value;
state _state;
HashNode(const pair<K, V>& value = pair<K, V>())
:_value(value)
, _state(EMPTY)
{}
};
- 哈希函数:除留余数法:
key % _table.size()
- 解决哈希冲突:线性探测
- 通过哈希函数找到哈希地址,如果发生了哈希冲突,则向后偏移到第一个空位置
- 扩容时机:负载因子 > 0.7 的时候,将容量增至 2 倍,并将原始数据插入到新哈希中
- 负载因子: 哈希表中存在的值 / 哈希表的容量
- 扩容方法:
- 将数组容量增至2倍,并将原始哈希表中的元素插入新的哈希表
- 删除一个元素:
- 将元素的属性设置为 delete,并将size- -
- 原因:在哈希表中寻找一个键值对是通过该位置状态向后偏移的,如果遇到EMPTY还没有直到,则返回 nullptr ,因此删除一个元素时不能直接将状态设置为EMPTY
哈希表的操作:
template <class K, class V>
class HashTable
{
public:
HashTable(size_t n = 10)
{
// 这里必须使用resize!
_table.resize(n);
_size = 0;
}
bool Insert(const pair<K, V>& value)
{
// 1.先检查容量
checkCapacity();
// 2.通过哈希函数计算位置
int index = value.first % _table.size();
// 3.找第一个空位置
while (_table[index]._state == EXIST)
{
// 当前key值已存在
if (_table[index]._value.first == value.first)
return false;
index = (index + 1) % _table.size();
}
_table[index]._value = value;
_table[index]._state = EXIST;
++_size;
return true;
}
void checkCapacity()
{
// 1.计算负载因子
if (_size * 10 / _table.size() >= 7)
{
HashTable ht(2 * _table.size());
// 将旧表中元素插入新表
for (int i = 0; i < _table.size(); ++i)
{
if (_table[i]._state == EXIST)
ht.Insert(_table[i]._value);
}
swap(_table, ht._table);
}
}
HashNode<K, V>* find(const K& key)
{
int index = key % _table.size();
while (_table[index]._state == !EMPTY)
{
if (_table[index]._state == EXIST && _table[index]._value.first == key)
return &_table[index];
index = (index + 1) % _table.size();
}
return nullptr;
}
bool erase(const K& key)
{
HashNode<K, V>* ptr = find(key);
if (ptr)
{
ptr->_state = DELETE;
--_size;
return true;
}
return false;
}
private:
vector<HashNode<K, V>> _table;
size_t _size;
};