设有一组关键字(19,14,23,1,68,20,84,27,56,11,10,79),建立一个哈希查找表。
(1)哈希函数采用: H(key)= key % P(其中P=13),若发生冲突后,用链地址法解决冲突。
(2)哈希函数采用: H(key)= key % P(其中P=13),若发生冲突后, 用线性探测再散列方法解决冲突。
编写程序建立哈希查找表,运行程序在表中查找68,99。
目录
1、哈希表结点结构与哈希函数
#define M 13 //除留余数法的除数
#define N 12 //元素个数
//哈希表结点结构
typedef struct HTNode {
int data; //值域
struct HTNode* next; //指针域,用于链地址法解决冲突
}*HTNode;
//哈希函数
int H(int n) {
return n % M;
}
2、链地址法
用一个HT数组存放关键字,如果有冲突,就把后面的关键字接在冲突位置的关键字的后面。
2.1、初始化
先把所有位置初始化为空,表示位置还没有被占用。
//链地址法
//初始化
void initHashTable(HTNode* HT) {
for (int i = 0; i < N; i++)
HT[i] = NULL;
}
2.2、插入
需要判断一下表里是否被占用了,如果被占用了就插入到链表上去。
//插入、创建
void createHashTable(HTNode* HT, int k) {
HTNode p = (HTNode)malloc(sizeof(struct HTNode));
p->data = k; //赋值
p->next = NULL; //初始化
int index = H(k);//下标
if (HT[index] == NULL)//表里没被占用
HT[index] = p;
else {//被占用了,就接在当前位置的next上
HTNode q = HT[index];
p->next = q->next;//头插法
q->next = p;
}
}
2.3、查找
先在线性表里挨个查找,当线性表里不为空时,就往当前元素的链表上查找,如果当前位置为空或者当前链表上找不到目标值,就继续往后面的位置查找。
//查找
bool FindHashTable(HTNode* HT, int k) {
for (int i = 0; i < N; i++) {
if (HT[i] == NULL)//该数组位置没值
continue;
if (HT[i]->data == k)//找到了
return true;
else { //当前位置不是要找的值但有值,就往他的链表上找
HTNode ht = HT[i];//这里要用个变量来代替查找,不然会改变原来的存储位置
while (ht->next) {//链表上的查找
ht = ht->next;
if (ht->data == k)
return true;
}
}
}
return false;
}
3、线性探测法
3.1、初始化
//线性探测法
//初始化
void initHashTable2(int* ht) {
for (int i = 0; i < N; i++) {
ht[i] = NULL;
}
}
3.2、创建
//创建表
void createHashTable2(int** ht, int k) {
int j = H(k);//数组下标
if (ht[j] == NULL) {//当前空间没被占用
ht[j] = k;
}
else {//当前空间被占了
while (ht[j] != NULL)//往后面空的地方找
j = (j + 1) % M;
ht[j] = k;
}
}
3.3、查找
//查找
int findHashTable2(int* ht, int k) {
for (int i = 0; i < N; i++) {
if (ht[i] == k)//返回下标
return i;
}
return 0;
}
4、完整测试源码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdbool.h>
#define M 13 //除留余数法的除数
#define N 12 //元素个数
/*
4.设有一组关键字(19,14,23,1,68,20,84,27,56,11,10,79),建立一个哈希查找表。
(1)哈希函数采用: H(key)= key % P(其中P=13),若发生冲突后,用链地址法解决冲突。
(2)哈希函数采用: H(key)= key % P(其中P=13),若发生冲突后, 用线性探测再散列方法解决冲突。
编写程序建立哈希查找表,运行程序在表中查找68,99。
*/
//哈希表结点结构
typedef struct HTNode {
int data;
struct HTNode* next;
}*HTNode;
//哈希函数
int H(int n) {
return n % M;
}
//链地址法
//初始化
void initHashTable(HTNode* HT) {
for (int i = 0; i < N; i++)
HT[i] = NULL;
}
//插入、创建
void createHashTable(HTNode* HT, int k) {
HTNode p = (HTNode)malloc(sizeof(struct HTNode));
p->data = k; //赋值
p->next = NULL; //初始化
int index = H(k);//下标
if (HT[index] == NULL)//表里没被占用
HT[index] = p;
else {//被占用了,就接在当前位置的next上
HTNode q = HT[index];
p->next = q->next;//头插法
q->next = p;
}
}
//输出
void printHashTable(HTNode* HT) {
int i = 0;
printf("序号:表头-----表体\n");
for (i = 0; i < N; i++) {
if (HT[i] == NULL)//有的数组空间没有值
continue;
printf("%2d: %2d", i, HT[i]->data);
if (HT[i]->next) {
printf("-------");
HTNode ht = HT[i];
while (ht->next) {
ht = ht->next;
printf("%2d ", ht->data);
}
}
printf("\n");
}
}
//查找
bool FindHashTable(HTNode* HT, int k) {
for (int i = 0; i < N; i++) {
if (HT[i] == NULL)//该数组位置没值
continue;
if (HT[i]->data == k)//找到了
return true;
else { //当前位置不是要找的值但有值,就往他的链表上找
HTNode ht = HT[i];
while (ht->next) {//链表上的查找
ht = ht->next;
if (ht->data == k)
return true;
}
}
}
return false;
}
//线性探测法
//初始化
void initHashTable2(int* ht) {
for (int i = 0; i < N; i++) {
ht[i] = NULL;
}
}
//创建表
void createHashTable2(int** ht, int k) {
int j = H(k);//数组下标
if (ht[j] == NULL) {//当前空间没被占用
ht[j] = k;
}
else {//当前空间被占了
while (ht[j] != NULL)//往后面空的地方找
j = (j + 1) % M;
ht[j] = k;
}
}
//输出
void printHashTable2(int* ht) {
for (int i = 0; i < N; i++) {
printf("%d ", ht[i]);
}
printf("\n");
}
//查找
int findHashTable2(int* ht, int k) {
for (int i = 0; i < N; i++) {
if (ht[i] == k)//返回下标
return i;
}
return 0;
}
void menu() {
printf("----------------\n1、链地址法查找\n");
printf("2、线性探测查找\n----------------\n");
}
void main() {
int K;
int chose;
int i;
//拉链法关键字数组
int k[N] = { 19,14,23,1,68,20,84,27,56,11,10,79 };//19,14,23,1,68,20,84,27,56,11,10,79
//线性探测法关键字数组
int ht[N];
//哈希表数组
HTNode HT[N];
printf("当前关键字序列为:\n");
for (int n = 0; n < N; n++) {
printf("%2d ", k[n]);
}
printf("\n");
while (1) {
menu();
scanf("%d", &chose);
switch (chose) {
case 1:
//先初始化哈希表
initHashTable(HT);
//创建哈希表
for (int i = 0; i < N; i++) {
createHashTable(&HT, k[i]);
}
//输出哈希表
printHashTable(HT);
printf("输入要查找的值:");
scanf("%d", &K);
if (FindHashTable(HT, K))
printf("查找成功!\n");
else
printf("查找失败!\n");
break;
case 2:
//先初始化
initHashTable2(ht);
//创建
for (int i = 0; i < N; i++) {
createHashTable2(&ht, k[i]);
}
printf("当前哈希表:");
printHashTable2(ht);
printf("输入要查找的值:");
scanf("%d", &K);
i = findHashTable2(ht, K);//保存下标
if (i)
printf("查找成功!%d的下标位置是:%d\n", K, i);
else
printf("查找失败!\n");
break;
default:return 0;
}
}
}