开放定址散列法
- 分离链表法缺点:需要指针,给新单元分配地址需要时间,导致算法速度减慢,同时还需要实现另一种数据结构。
- 开放定址法:如果有冲突发生,尝试选择另外得单元,直到找出空的单元为止。
开放定址散列法数据结构
- 散列表单元不是链表,而是一个个散列项:包含关键字和相关信息(是否为空),数据结构声明如下:
typedef struct Entry {
ElemType data;
KindOfEntry Info;
}HashEntry;
- 散列表的数据结构包含:表大小,一个散列项类型的数组(头指针),结构声明如下
typedef struct HashTb {
int tablesize;
HashEntry* TableList;
}*HashTable;
使用平方探测法散列法查找散列表
Index Find(HashTable H, ElemType key) // 使用平方探测散列法,在哈希表中查找指定关键字,返回一个位置下标
{
Index pos = Hash(key, H->tablesize); // 借助哈希函数,求出包含给定关键字的位置
int collnum = 0; // 初始化冲突数
while (H->TableList[pos].Info != Empty && H->TableList[pos].data != key)
{
pos += 2 * ++collnum - 1;
if (pos >= H->tablesize)
pos -= H->tablesize;
}
return pos;
}
使用平方探测法散列表的插入操作
- 定理:使用平方探测法,如果表大小是素数,则当表至少有一半是空的时候,总能插入一个新的元素
void insert(HashTable H, ElemType key)
{
Index pos = Find(H, key);
if (H->TableList[pos].Info != Legitimate)
{
H->TableList[pos].data = key;
H->TableList[pos].Info = Legitimate;
}
}
再散列
- 对于平方探测的开放定址散列法,如果表的元素填得太满,操作运行时间将开始消耗过长,且insert可能失败。
- 一种解决方法是建立大约两倍大的表(使用一个相关的新散列函数),扫描原散列表,计算表中元素新散列值将它们插入到新表中。这种操作称为再散列。
HashTable Rehash(HashTable H)
{
int oldtablesize = H->tablesize;
HashEntry *oldTableList = H->TableList;
H = InitHashTable(2 * oldtablesize);
for (int i = 0;i < oldtablesize;i++)
{
if (oldTableList[i].Info == Legitimate)
insert(H, oldTableList[i].data);
}
delete oldTableList;
return H;
}
附平方探测开放定址散列表及相关操作C/C++
#include<iostream>
#define Index int
using namespace std;
typedef int ElemType;
enum KindOfEntry {Empty, Legitimate};
const int Mintablesize = 5;
typedef struct Entry {
ElemType data;
KindOfEntry Info;
}HashEntry;
typedef struct HashTb {
int tablesize;
HashEntry* TableList;
}*HashTable;
bool isPrime(int x)
{
if (x == 1)
return false;
if (x == 2)
return true;
for (int i = 3;i < x / 2;i++)
{
if (x%i == 0)
return false;
}
return true;
}
int NextPrime(int x)
{
while (1)
{
x++;
if (isPrime(x))
return x;
}
}
int Hash(ElemType key, int tablesize)
{
return key % tablesize;
}
HashTable InitHashTable(int tablesize)
{
if (tablesize < Mintablesize)
{
cout << "Table size too small.\n";
exit(1);
}
HashTable H = new HashTb;
H->tablesize = NextPrime(tablesize);
H->TableList = new HashEntry [tablesize];
for (int i = 0;i < H->tablesize;i++)
{
H->TableList[i].Info = Empty;
}
return H;
}
Index Find(HashTable H, ElemType key)
{
Index pos = Hash(key, H->tablesize);
int collnum = 0;
while (H->TableList[pos].Info != Empty && H->TableList[pos].data != key)
{
pos += 2 * ++collnum - 1;
if (pos >= H->tablesize)
pos -= H->tablesize;
}
return pos;
}
void insert(HashTable H, ElemType key)
{
Index pos = Find(H, key);
if (H->TableList[pos].Info != Legitimate)
{
H->TableList[pos].data = key;
H->TableList[pos].Info = Legitimate;
}
}
HashTable Rehash(HashTable H)
{
int oldtablesize = H->tablesize;
HashEntry *oldTableList = H->TableList;
H = InitHashTable(2 * oldtablesize);
for (int i = 0;i < oldtablesize;i++)
{
if (oldTableList[i].Info == Legitimate)
insert(H, oldTableList[i].data);
}
delete oldTableList;
return H;
}
int main()
{
const int rawdata[] = { 19, 13, 9, 8, 23, 39, 4, 2, 75, 100, 43, 58 };
int tablesize = 12;
HashTable myTable = InitHashTable(tablesize);
for (int i = 0;i < sizeof(rawdata) / sizeof(int);i++)
{
insert(myTable, rawdata[i]);
}
cout << "Find the table : \n";
for (int i = 0;i < sizeof(rawdata) / sizeof(int);i++)
{
if (myTable->TableList[Find(myTable, rawdata[i])].Info == Legitimate)
{
cout << rawdata[i] << " Have been Found." << endl;
}
else
{
cout << rawdata[i] << " 404 Not Found." << endl;
}
}
int key;
cout << "Input an int number: "; cin >> key;
Index pos = Find(myTable, key);
if (myTable->TableList[pos].Info == Empty)
cout << key << " is not in the table." << endl;
delete myTable;
system("pause");
return 0;
}
Find the table :
19 Have been Found.
13 Have been Found.
9 Have been Found.
8 Have been Found.
23 Have been Found.
39 Have been Found.
4 Have been Found.
2 Have been Found.
75 Have been Found.
100 Have been Found.
43 Have been Found.
58 Have been Found.
Input an int number: 15
15 is not in the table.
请按任意键继续. . .