数据结构ky备战Day5 - 查找
注:本节我仅介绍主要代码为:线性探测再散列 + 除留余数法 + 查找成功记数 + 查找失败记数
- 连地址法构建与查找成功ASL 这个我就略了,因为就是多链表的概念,确定下标后就是尾插法的操作罢了。计算ASL就是遍历多了个计数器
- 二叉排序树 和 平衡二叉树 二叉排序树其实就是树的遍历的变形,我也不放这了,平衡二叉树旋转操作应用题会做就行 也略了
- 至于折半查找,二分思想,不用我多说了,就记住一点,一定必须得是顺序结构且有序,链表不行!
结构体定义
哈希表HashTable
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define Error -1
#define NULLKEY -1
#define KeyType int
typedef struct{
int key;
// 其他记录按需增加
}RecordType;
typedef RecordType HashTable[MAX_SIZE];
基础操作
除留余数法构建HashTable
// 除留余数法构建散列表
void createHash(HashTable ht){
int h0; // 计算初始hash值
int K;
RecordType r;
input(&r, &K); // 输入记录r,关键字为K
while(K != -1){
h0 = K % 7;
if(ht[h0].key == NULLKEY) ht[h0] = r; // 空域直接插入
else{ // 产生冲突 往后找空域
for(int i = 1; i <= MAX_SIZE - 1; i ++){
h0 = (h0 + i) % MAX_SIZE;
if(ht[h0].key == NULLKEY){
ht[h0] = r;
break; // 插入成功
}
}
}
input(&r, &K); // 继续输入记录r ,关键字K
}
}
HashTable查找元素
// 散列表查找基础操作
int hash_search(HashTable ht, KeyType K){
int h0 = K % 7;
if(ht[h0].key == NULLKEY) return Error; // 查找到了空域,查找失败
else if(ht[h0].key == K) return h0; // 直接无冲突 查找到关键字
else{ // 原先插入的时候 产生冲突 需要往后遍历查找
for(int i = 0; i <= MAX_SIZE - 1; i ++){ // 对剩余位置进行遍历
int hi = (h0 + i) % MAX_SIZE; // 往后找
if(ht[hi].key == NULLKEY) return Error; // 空域,查找失败
if(ht[hi].key == K) return hi; // 查找成功
}
}
return Error; // 在剩下的表中都没有找到
}
计算查找成功ASL
// 计算查找成功ASL
// 表长m 元素个数n,a[]是元素
int getASL(HashTable ht, int a[], int n, int m){
int count, h0; // count 记录查找成功的总次数 h0 记录计算得到的hash值
for(int i = 0; i < n; i ++){
count = 0;
h0 = a[i] % 7;
if(ht[h0].key == NULLKEY) return Error; // 哈希表没有存取完整的a[]元素,错误
else if(ht[h0].key == a[i]) count ++ ; // 查找成功,次数 + 1
else{ //出现冲突
for(int i = 1; i <= MAX_SIZE - 1; i ++){
h0 = (h0 + i) % MAX_SIZE; // h0往表后找
count ++; // 每往后一次查找,计数器加一
if(ht[h0].key == NULLKEY) return Error; // 查找元素失败
else if(ht[h0].key == a[i]) break;
}
}
}
return (double)count / n; // 查找成功总长度除以元素个数
}
计算查找失败ASL
// 计算查找失败ASL
// hash = x % p,一定要记住,这里的分母是什么?是你的hash值的范围!然后记住遍历的时候还是以表长为模!
getUnASL(HashTable ht, int p){
int cnt;
double asl = 0; // 记录总次数
for(int i = 0; i < p; i ++){
int j = i; // 冲突时记录数组下标
cnt = 1; // 初始值为1
while(ht[j].key != NULLKEY){
j = (j + 1) % MAX_SIZE;
cnt ++; // 每查找一次 计数器就加1
}
asl = asl + cnt; // 加上以下标i为起点的查找失败次数
}
return asl / p;
}