开放定址散列法:是另一种不用链表解决冲突的方法,在开放定址散列算法系统中,如果有冲突发生,那么就要尝试选择另外的单元,直到找出空的单元为止。
公式 : hi ( X ) = ( hash(X)+F(i) ) mod TableSize
关键字X的位置等于 Hash函数返回的位置在加上F(i)的位置 Mod TableSize
线性探测法:F(i) = i ,这相当于逐个探测每个单元(必要时可以绕回)以查找出一个空单元。
平方探测法: F(i) = i²,平方探测法冲突函数为二次函数的探测方法。F(i) = i²,防止多次冲突,形成一次聚集。
以下代码是 平方探测法的实现:
数据结构和主要函数声明
#include<stdio.h>
#include <stdlib.h>
#include <math.h>
#include<string.h>
typedef unsigned int Index;
typedef Index Postion;
typedef char* ElementType;
enum KindOfEntry { Legitimate, Empty, Deleted }; //标记表中单元的状态
struct HashEntry {
char element[20]; //实体
KindOfEntry Inof; //存储状态
};
typedef struct HashEntry Cell;
struct HashTbl { //哈希表结构
int TableSize;
Cell* TheCells; //用链表存储表结构
};
typedef struct HashTbl *HashTable;
//函数声明
HashTable InitializeTable(int Table); //初始化哈希表
void DestroyTable(HashTable H); //销毁哈希表
Postion Find(ElementType key, HashTable H); //查找
void Insert(ElementType key, HashTable H); //插入
void Delete(ElementType key,HashTable H); //删除
int NextPrime(int TableSize); //寻找素数函数
int Hash(const char *key, int tableSize); //哈希函数
主要函数:哈希函数与素数函数
int Hash(const char *key, int tableSize) {
//哈希函数
unsigned int hashVal = 0;
while (*key != NULL) {
hashVal = (hashVal << 5) + *key++;
}
return hashVal % tableSize;
}
int NextPrime(int TableSize) {
//寻找素数函数
int i, j, flag;
i = TableSize;
while (1) {
flag = 1;
for (j = 2; j <= sqrt(i); j++) {
if (i%j == 0) {
flag = 0;
break;
}
}
if (flag == 1) {
break;
}
i++;
}
return i;
}
初始化函数:对每个单元记录一个标记,方便编程,初始化时,把每个单元的标记置为Empty
HashTable InitializeTable(int TableSize) { //初始化
HashTable H;
int i;
H = (HashTable)malloc(sizeof(struct HashTbl));
H->TableSize = NextPrime(TableSize);
H->TheCells = (Cell*)malloc(sizeof(struct HashEntry)*H->TableSize);
for (i = 0; i < H->TableSize; i++) { //把每一个单元标记为空。
H->TheCells[i].Inof = Empty;
}
return H;
}
查找函数Find
Postion Find(ElementType key,HashTable H) {
//从哈希表中查找一个元素,若存在,返回位置,不存在,返回要下一个空的位置
Postion CurrentPos;
int CollisionNum; //相当于i
CollisionNum = 0;
CurrentPos = Hash(key, H->TableSize); //获取哈希函数散列的位置
while (H->TheCells[CurrentPos].Inof != Empty && strcmp(H->TheCells[CurrentPos].element,key)) {
//如果位置的元素为空或者位置元素等于要查找的关键字,返回该位置。
//否则,平方探测 hash(X)+F(i),F(i) = i²
CurrentPos += 2 * ++CollisionNum - 1;
if (CurrentPos >= H->TableSize) {
CurrentPos %= H->TableSize;
}
}
return CurrentPos; //返回位置
}
插入函数,删除函数,销毁函数
void Insert(ElementType key, HashTable H) { //插入一个元素到哈希表中
Postion Pos;
Pos = Find(key, H); //如果哈希表中没有该关键字,则找到要插入的位置,否则,返回已存在的位置。
if (H->TheCells[Pos].Inof != Legitimate) { //如果未插入,则进行插入
strcpy_s(H->TheCells[Pos].element, strlen(key) + 1, key);
H->TheCells[Pos].Inof = Legitimate; //标记设为Legitimate,表示存在数据
}
}
void Delete(ElementType key, HashTable H) { //从哈希表中删除一个元素
Postion Pos;
Pos = Find(key, H);
if (H->TheCells[Pos].Inof == Legitimate) {
//懒惰删除,如果要查找的关键字存在,则把该单元标记为空
H->TheCells[Pos].Inof = Empty;
}
}
void DestroyTable(HashTable H) { //销毁哈希表
free(H->TheCells); //将哈希节点中的存储数据的空间释放
free(H); //将哈希节点释放空间,完成删除操作。
}