C++哈希表:开散列与闭散列详解
C++ —— 哈希详解:开散列与闭散列
哈希表是一种高效的数据结构,用于存储键值对,支持快速查找、插入和删除。其核心是哈希函数,将键映射到索引位置。当多个键映射到同一位置时(冲突),需要处理策略。常见方法有闭散列(开放地址法)和开散列(链地址法)。下面我将详细解释这两种方法,包括工作原理、优缺点,并提供C++实现示例。
1. 哈希表基础
哈希表由数组和哈希函数组成。哈希函数 $h(k)$ 将键 $k$ 映射到数组索引,理想情况下均匀分布。冲突发生时,需解决:
- 闭散列:在数组内部通过探测序列寻找空位。
- 开散列:使用外部数据结构(如链表)存储冲突元素。
2. 闭散列(开放地址法)
闭散列在数组内部处理冲突,通过探测序列寻找下一个空槽。常见探测方法:
- 线性探测:冲突后,依次检查下一个位置 $h(k, i) = (h(k) + i) mod m$,其中 $i$ 是探测次数,$m$ 是数组大小。
- 二次探测:避免聚集,使用 $h(k, i) = (h(k) + c_1 cdot i + c_2 cdot i^2) mod m$,$c_1$ 和 $c_2$ 是常数。
- 双重哈希:使用第二个哈希函数 $h_2(k)$,序列为 $h(k, i) = (h(k) + i cdot h_2(k)) mod m$。
优点:
- 内存局部性好,访问速度快。
- 无需额外数据结构,节省空间。
缺点:
- 容易产生聚集现象,降低性能。
- 删除操作复杂,需标记删除位。
- 负载因子高时(如 $> 0.7$),性能下降快。
C++实现示例: 以下是一个使用线性探测的哈希表实现:
#include
#include
using namespace std;
class HashTable {
private:
vector table;
vector isOccupied;
int size;
int capacity;
int hash(int key) {
return key % capacity;
}
int probe(int key, int i) {
return (hash(key) + i) % capacity;
}
public:
HashTable(int cap) : capacity(cap), size(0) {
table.resize(cap, -1); // -1表示空位
isOccupied.resize(cap, false);
}
void insert(int key) {
if (size >= capacity) {
cout << "Table full!" << endl;
return;
}
int index = hash(key);
int i = 0;
while (isOccupied[index] && table[index] != key) {
i++;
index = probe(key, i);
}
if (!isOccupied[index]) {
table[index] = key;
isOccupied[index] = true;
size++;
}
}
bool search(int key) {
int index = hash(key);
int i = 0;
while (isOccupied[index]) {
if (table[index] == key) {
return true;
}
i++;
index = probe(key, i);
}
return false;
}
void remove(int key) {
int index = hash(key);
int i = 0;
while (isOccupied[index]) {
if (table[index] == key) {
isOccupied[index] = false; // 标记为删除
size--;
return;
}
i++;
index = probe(key, i);
}
}
};
int main() {
HashTable ht(10);
ht.insert(5);
ht.insert(15);
cout << "Search 15: " << ht.search(15) << endl; // 输出1 (true)
ht.remove(15);
cout << "Search 15: " << ht.search(15) << endl; // 输出0 (false)
return 0;
}
http://my.tv.sohu.com/us/438920216/698245475.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTQ3NS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245547.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU0Ny5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245550.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU1MC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245382.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTM4Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245553.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU1My5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245557.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU1Ny5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245388.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTM4OC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245640.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTY0MC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245717.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTcxNy5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245649.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTY0OS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245575.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU3NS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245807.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTgwNy5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245580.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU4MC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245583.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU4My5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245659.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTY1OS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245588.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU4OC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245590.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU5MC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245739.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTczOS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245815.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTgxNS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245825.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTgyNS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245674.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTY3NC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245600.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTYwMC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245828.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTgyOC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245679.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTY3OS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245760.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTc2MC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245838.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTgzOC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245843.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTg0My5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245923.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTkyMy5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245781.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTc4MS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245783.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTc4My5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245936.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTkzNi5zaHRtbA==.html
3. 开散列(链地址法)
开散列使用链表处理冲突:每个数组槽指向一个链表,冲突元素添加到链表中。哈希函数 $h(k)$ 映射到索引,然后在该索引的链表中操作。
优点:
- 处理冲突简单,性能稳定。
- 删除操作容易,直接移除链表节点。
- 高负载因子下仍高效。
缺点:
- 内存开销大,需额外链表空间。
- 链表遍历可能增加访问时间。
C++实现示例: 以下是一个使用链地址法的哈希表实现:
#include
#include
#include
using namespace std;
class HashTable {
private:
vector> table;
int capacity;
int hash(int key) {
return key % capacity;
}
public:
HashTable(int cap) : capacity(cap) {
table.resize(cap);
}
void insert(int key) {
int index = hash(key);
for (auto it = table[index].begin(); it != table[index].end(); ++it) {
if (*it == key) {
return; // 键已存在
}
}
table[index].push_back(key);
}
bool search(int key) {
int index = hash(key);
for (auto it = table[index].begin(); it != table[index].end(); ++it) {
if (*it == key) {
return true;
}
}
return false;
}
void remove(int key) {
int index = hash(key);
for (auto it = table[index].begin(); it != table[index].end(); ++it) {
if (*it == key) {
table[index].erase(it);
return;
}
}
}
};
int main() {
HashTable ht(10);
ht.insert(5);
ht.insert(15);
cout << "Search 15: " << ht.search(15) << endl; // 输出1 (true)
ht.remove(15);
cout << "Search 15: " << ht.search(15) << endl; // 输出0 (false)
return 0;
}
http://my.tv.sohu.com/us/438920216/698245475.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTQ3NS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245547.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU0Ny5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245550.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU1MC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245382.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTM4Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245553.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU1My5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245557.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU1Ny5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245388.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTM4OC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245640.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTY0MC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245717.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTcxNy5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245649.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTY0OS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245575.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU3NS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245807.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTgwNy5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245580.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU4MC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245583.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU4My5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245659.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTY1OS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245588.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU4OC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245590.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTU5MC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245739.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTczOS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245815.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTgxNS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245825.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTgyNS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245674.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTY3NC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245600.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTYwMC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245828.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTgyOC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245679.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTY3OS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245760.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTc2MC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245838.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTgzOC5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245843.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTg0My5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245923.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTkyMy5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245781.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTc4MS5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245783.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTc4My5zaHRtbA==.html
http://my.tv.sohu.com/us/438920216/698245936.shtml
https://tv.sohu.com/v/dXMvNDM4OTIwMjE2LzY5ODI0NTkzNi5zaHRtbA==.html
4. 闭散列 vs. 开散列比较
- 性能:开散列在高负载因子下更稳定;闭散列在低负载因子时更快。
- 内存:闭散列更节省空间;开散列有额外链表开销。
- 适用场景:闭散列适合内存受限环境;开散列适合高冲突率场景。
- C++标准库:
std::unordered_map通常使用开散列实现。
5. 总结
在C++中,哈希表实现需根据需求选择闭散列或开散列。闭散列简单但易聚集,开散列稳定但占用内存。实践中,C++的 std::unordered_map 基于开散列,提供高效操作。以上代码示例展示了核心逻辑,实际应用中需处理扩容、哈希函数优化等。





