数据结构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;
}


posted @ 2023-10-24 22:01  yuezi2048  阅读(11)  评论(0编辑  收藏  举报