哈希表的构造方法:
- 直接定址法
- 数字分析法
- 平方取中法
- 折叠法
- 除留余数法
- 随机数法
处理冲突的方法:
- 开放地址法
- 线性探测再散列
- 二次探测再散列
- 伪随机探测再散列
- 再哈希法
- 链地址法
- 建立一个公共溢出区
装填因子:
平均查找长度ASL跟哈希表构造方法和处理冲突的方法都有关。一般情况下,处理冲突方法相同的哈希表,其平均查找长度依赖于哈希表的装填因子:
α
=
表
中
填
入
的
记
录
数
哈
希
表
的
长
度
\alpha = \frac{表中填入的记录数}{哈希表的长度}
α=哈希表的长度表中填入的记录数
α标志哈希表的装满程度,越小发生冲突的可能性就越小。
可证明得出:
线性探测再散列的哈希表ASL:
S
n
l
≈
1
2
(
1
+
1
1
−
α
)
S_{nl} \approx \frac{1}{2} (1+\frac{1}{1-\alpha})
Snl≈21(1+1−α1)
随机探测再散列、二次探测再散列、再哈希的哈希表ASL:
S
n
r
≈
−
1
α
ln
(
1
−
α
)
S_{nr} \approx - \frac{1}{\alpha}\ln(1-\alpha)
Snr≈−α1ln(1−α)
链地址法的ASL:
S
n
c
≈
1
+
α
2
S_{nc} \approx 1 + \frac{\alpha}{2}
Snc≈1+2α
c++实现:
- 包含创建,插入,删除,查找,打印,扩充哈希表等操作。
hpp:
//
// HashTable.hpp
// HashTable
//
// Created by peiyu wang on 2019/3/28.
// Copyright © 2019 peiyu wang. All rights reserved.
//
#ifndef HashTable_hpp
#define HashTable_hpp
#include <iostream>
#include <stdio.h>
using namespace std;
/* 全局变量 */
// 哈希表容量递增表,一个合适的素数序列
const int hashsize[] = {7, 13, 17, 101, 211, 307, 401, 503, 601, 701, 809, 907, 997};
/* 宏定义 */
#define DUPLICATE -1 // 表中已存在关键字
#define NULLKEY -2 // 标记此处无关键字
#define FULL -3 // 表已满(冲突次数达上限就认为表满)
#define EVER -4 // 此位置上曾删除过元素
/*类型定义*/
typedef int KeyType;
struct HashTable
{
KeyType *elem; //数据元素存储基址
int count; //当前表中画关键字个数
int sizeindex; //当前容量
};
/* 函数列表 */
// 初始化一个空的哈希表
void InitHash(HashTable &H);
// 创建哈希表
int CreateHash(HashTable &H);
// 哈希表关键字搜索,p指向查找成功后的元素位置
int SearchHash(HashTable H, KeyType key, int *p);
// 哈希表关键字插入
int InsertHash(HashTable &H, KeyType key);
// 哈希表删除操作
int DeleHash(HashTable &H, KeyType key);
// 重建哈希表
int RecreateHashTable(HashTable &H);
// 哈希函数
int fHash(HashTable H, KeyType key);
// 开放地址法寻找下一个探查位置
void collision(HashTable H, int *p);
// 输出哈希表中的关键字
void PrintHash(HashTable H);
#endif
cpp:
//
// HashTable.cpp
// HashTable
//
// Created by peiyu wang on 2019/3/28.
// Copyright © 2019 peiyu wang. All rights reserved.
//
#include "HashTable.hpp"
#include <queue>
void InitHash(HashTable &H)
{
H.count = 0;
H.sizeindex = 0;
int newN = hashsize[H.sizeindex];
H.elem = new KeyType [newN];
for (int i = 0; i < newN; i++)
{
H.elem[i] = NULLKEY;
}
}
int CreateHash(HashTable &H)
{
InitHash(H);
int n = 0;
cout << "请输入哈希表元素个数: " << endl;
cin >> n;
while (n--)
{
KeyType k;
cin >> k;
InsertHash(H, k);
}
return 1;
}
int SearchHash(HashTable H, KeyType key, int *p)
{
int c = 0; // 记录冲突的次数
int sup = hashsize[H.sizeindex] / 2;
*p = fHash(H, key);
while (1)
{
if (H.elem[*p] == NULLKEY || H.elem[*p] == EVER)
return NULLKEY;
else if (H.elem[*p] == key)
return DUPLICATE;
else if (++c == sup)
return FULL;
else
collision(H, p); //重新定位p的位置
}
}
// 哈希表关键字插入
int InsertHash(HashTable &H, KeyType key)
{
int p;
int flag = SearchHash(H, key, &p);
if (flag == FULL)
{
queue<KeyType> tmp;
for (int i = 0; i < hashsize[H.sizeindex]; i++)
{
if (H.elem[i] != NULLKEY)
{
tmp.push(H.elem[i]);
}
}
if (RecreateHashTable(H))
{
while (!tmp.empty())
{
InsertHash(H, tmp.front());
tmp.pop();
}
InsertHash(H, key);
}
}
if (flag == NULLKEY || flag == EVER)
{
H.elem[p] = key;
H.count ++;
}
if (flag == DUPLICATE)
return 0;
return 1;
}
// 重建哈希表
int RecreateHashTable(HashTable &H)
{
H.count = 0;
H.sizeindex += 1;
int newN = hashsize[H.sizeindex];
if (H.elem)
{
delete H.elem;
}
H.elem = new KeyType [newN];
if (!H.elem)
{
return 0;
}
for (int i = 0; i < newN; i++)
{
H.elem[i] = NULLKEY;
}
return 1;
}
int DeleHash(HashTable &H, KeyType key)
{
int p = 0;
int flag = SearchHash(H, key, &p);
if (flag == DUPLICATE)
{
H.elem[p] = EVER;
H.count--;
return 1;
}
else
{
return 0;
}
}
// 哈希函数
int fHash(HashTable H, KeyType key)
{
return ((key * 2654435769) >> 28) % hashsize[H.sizeindex];
}
// 开放地址法寻找下一个探查位置
void collision(HashTable H, int *p)
{
//简单的移位
*p = (*p + 1) % hashsize[H.sizeindex];
}
// 输出哈希表中的关键字
void PrintHash(HashTable H)
{
int i, v;
v = hashsize[H.sizeindex];
printf("哈希表容量为:%d,现有元素:%d 个,表中元素为:\n", v, H.count);
for(i=0; i<v; i++)
{
if(H.elem[i]!=NULLKEY && H.elem[i]!=EVER)
cout << H.elem[i] << " ";
}
printf("\n");
}
main:
//
// main.cpp
// HashTable
//
// Created by peiyu wang on 2019/3/28.
// Copyright © 2019 peiyu wang. All rights reserved.
//
#include "HashTable.hpp"
int main() {
HashTable H;
CreateHash(H);
int p = 0;
int r;
r = SearchHash(H, 20, &p);
if (r == DUPLICATE)
cout << "查找成功" << endl;
else
cout << "查找失败" << endl;
DeleHash(H, 20);
PrintHash(H);
r = SearchHash(H, 20, &p);
if (r == DUPLICATE)
cout << "查找成功" << endl;
else
cout << "查找失败" << endl;
InsertHash(H, 20);
r = SearchHash(H, 20, &p);
if (r == DUPLICATE)
cout << "查找成功" << endl;
else
cout << "查找失败" << endl;
return 0;
}