实验五 哈希表的算法实现

发布时间:2023年12月27日

目录

一 实验目的

二 实验内容及要求

三 实验过程及运行结果

实验一:完成哈希表的建立,使用线性探测法避免冲突,输出哈希表内容,计算ASL,进行查找操作。

一 算法设计思路

二 源程序代码

四 调试情况、设计技巧及体会


一 实验目的

掌握哈希表的构造,以及解决冲突的方法——开放冲突法、链地址法等。

二 实验内容及要求

实验内容:

采用除留余数法实现哈希表的创建,任意采用一种处理冲突的方法解决冲突,计算哈希表的平均查找长度。编程实现以下功能:

已知一组关键字(19,14,23,1,68,20,84,27,55,11,10,79),哈希函数定义为:H(key)=key MOD 13, 哈希表长为m=16。实现该哈希表的散列,并计算平均查找长度(设每个记录的查找概率相等)。

(1)哈希表定义为定长的数组结构;

(2)使用线性探测再散列或链地址法解决冲突;

(3)散列完成后在屏幕上输出数组内容或链表;

(4)输出等概率查找下的平均查找长度;

(5)完成散列后,输入关键字完成查找操作,要分别测试查找成功与查找不成功两种情况。

实验要求:

1.键盘输入数据;

2.屏幕输出运行结果。

3.要求记录实验源代码及运行结果。

4.运行环境:CodeBlocks/Dev c++/VC6.0等C编译环境

三 实验过程及运行结果

实验一:完成哈希表的建立,使用线性探测法避免冲突,输出哈希表内容,计算ASL,进行查找操作。

一 算法设计思路

共有四个功能函数:InitialTable(Table &t,int n)、OutPut(Table t,int n)、ASL(Table t,int n)、SearchHash(Table t,int n)和一个main函数

InitialTable(Table &t,int n)函数的主要目的是使用除留余数法实现哈希表,并采用线性探测法解决冲突,通过输入的关键字数组来初始化哈希表。

首先,函数接受一个哈希表对象 t 和关键字数量 n 作为参数函数要求输入关键字数组,并将输入的关键字存储在一个名为 arr 的数组中。然后创建一个辅助数组 a,用于标记哈希表中的槽位是否已被占用。初始时,所有槽位都标记为未占用(0)。然后使用一个循环遍历关键字数组 arr 中的每个关键字。对于每个关键字 arr[i],计算其哈希值 index,通过将关键字取模 mod 来实现除留余数法。进入一个无限循环,用于处理冲突。在循环中,检查哈希表中索引为 index 的槽位是否已被占用。如果槽位未被占用(a[index] 等于 0),则将关键字插入到该槽位中,并更新相关信息:如果槽位已被占用,则继续线性探测,将 index 值递增,并递增 count 值,直到找到一个未被占用的槽位。

循环结束后,所有关键字都已经插入到哈希表中,并且每个关键字的索引、查找次数和关键字本身都已经存储在哈希表对象 t 的相应成员变量中。

OutPut(Table t,int n)函数,用于输出哈希表的索引、元素和查找次数。函数接受一个哈希表对象 t 和哈希表长度 n 作为参数。首先,函数使用循环遍历哈希表的索引,从0到 TableLen-1(假设 TableLen 是哈希表的长度)。在每次循环中,输出当前索引的值,使用 printf 函数打印索引。完成索引的输出后,换行并输出一个空行。接下来,函数使用两层循环遍历哈希表中的元素。外层循环遍历哈希表的索引,内层循环遍历哈希表对象 t 中的元素。在内层循环中,检查当前元素的索引是否与外层循环的索引相等。如果相等,则输出当前元素的关键字,使用 printf 函数打印关键字,并将 flag 设置为1,表示找到了对应的元素。如果内层循环结束后,flag 的值仍然为0,表示当前索引没有对应的元素,则输出一个空格。

最后,函数使用类似的方式输出哈希表中每个元素的查找次数。

ASL(Table t,int n)函数,用于计算哈希表的平均查找长度。函数接受一个哈希表对象 t 和哈希表长度 n 作为参数。首先,声明一个变量 ASL 并初始化为0,用于累加哈希表中每个元素的查找次数。使用循环遍历哈希表的索引,从0到 TableLen-1(假设 TableLen 是哈希表的长度)。在每次循环中,将当前索引的元素的查找次数累加到 ASL 中。循环结束后,ASL 中存储的是哈希表中所有元素的查找次数的总和。将 ASL 除以哈希表的长度 n,得到平均查找长度,并将结果赋值给 ASL 变量。

SearchHash(Table t,int n)函数,用于在哈希表中进行关键字的查找。函数接受一个哈希表对象 t 和哈希表长度 n 作为参数。首先,声明一个变量 choice 并初始化为1,用于控制循环。进入一个循环,循环条件是 x 不等于-1。循环中的代码会不断询问用户要查找的关键字,直到用户输入-1 为止。然后在每次循环中,首先输出提示信息,要求用户输入要查找的关键字。使用 cin 从用户输入中获取关键字,并将其存储在变量 x 中。

根据哈希函数的定义,计算关键字 x 的哈希值,即 x % mod,并将结果存储在变量 index 中。声明一个变量 flag 并初始化为0,用于标记是否找到了关键字。使用循环从计算得到的索引位置开始,依次遍历哈希表中的元素。在循环中,检查当前元素的关键字是否等于 x,如果相等,则输出该元素在哈希表中的位置,并将 flag 设置为1,表示找到了关键字。

如果当前索引超过了哈希表的长度,则跳出循环。

循环结束后,检查 flag 的值,如果为0,则表示没有找到关键字,输出相应的提示信息。

二 源程序代码

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <algorithm>

using namespace std;
#define MAXSIZE 1000
#define TableLen 16
#define mod 13
typedef struct
{
	int key;
	int index;//位置
	int count=0;//比较次数
}Table[MAXSIZE];

void InitialTable(Table &t,int n)
{
	cout << "请输入表中关键字:" << endl;
	int arr[MAXSIZE];
	for (int i = 0; i < n; i++)
	{
		cin >> arr[i];
	}
	int a[MAXSIZE] = { 0 };
	for (int i = 0; i < n; i++)
	{
		int count = 0;
		int index = arr[i] % mod;
		while (1)
		{
			if (a[index] == 0)
			{
				t[index].index = index;
				a[index] = 1;
				t[index].count++;
				t[index].count += count;
				t[index].key = arr[i];
				break;
			}
			else
			{

				index++;

				count++;
			}
		}
		
	}
	
}
void OutPut(Table t,int n)
{
	printf("表的索引为:");

	for (int i = 0; i < TableLen; i++)
		printf("%5d", i);
	cout << "\n" << endl;
	printf("表的元素为:");

	for (int i = 0; i < TableLen; i++)
	{
		int flag = 0;
		for (int j = 0; j < TableLen; j++)
			if (t[j].index == i)
			{
				printf("%5d", t[j].key); flag = 1; break;
			}
		if (flag == 0)
			printf("%4c",' ');
	}
	cout << "\n"<<endl;

	printf("查找次数为:");
	for (int i = 0; i < TableLen; i++)
	{
		int flag = 0;
		for (int j = 0; j < TableLen; j++)
			if (t[j].index == i)
			{
				printf("%5d", t[j].count); flag = 1; break;
			}
		if (flag == 0)
			printf("%4c",' ');
	}
	cout << "\n"<<endl;


}
void ASL(Table t,int n)
{
	double ASL=0;
	for (int i = 0; i < TableLen; i++)
	{
		ASL += t[i].count;
	}
	ASL /= n;
	cout << "平均查找长度为:" << ASL << endl;
}
void SearchHash(Table t,int n)
{
	int choice = 1;

		int x=1;
	while (x!=-1)
	{
		cout << "请输入要查找的关键字,以-1退出!" << endl;
		cin >> x;
		int index = x % mod;
		int flag = 0;
		for (; index < TableLen; index++)
		{
			if (t[index].key == x && index < TableLen)
			{
				cout << "位置在 " << index << endl;
				flag = 1;
				break;
			}

			if (index > TableLen - 1)
				break;
		}

		if (flag == 0)
			cout << "未找到此元素!" << endl;

	}
}

int main()
{
	Table Hash; int n;
	cout<<  "请输入要建立的哈希表长度" << endl;
	cin >> n;
	InitialTable(Hash,n);
	OutPut(Hash,n);
	ASL(Hash,n);
	SearchHash(Hash,n);
	return 0;
}

四 调试情况、设计技巧及体会

冲突处理方法选择错误:

? 错误:在线性探测再散列中,没有正确处理已占用槽位的情况,导致关键字无法正确插入或查找失败。

修改方法:在线性探测再散列中,当遇到已占用的槽位时,需要继续探测下一个槽位,直到找到一个空槽位或达到哈希表的末尾。确保在插入操作和查找操作中正确处理已占用槽位的情况。

平均查找长度计算错误:

? 错误:在计算平均查找长度时,没有正确累加每个关键字的查找次数或没有使用正确的公式计算平均值。

? 修改方法:在每次查找操作中,根据关键字的查找次数更新累加和,确保正确累加每个关键字的查找次数。在计算完毕后,使用公式 ASL = (累加和 / 关键字数量) 来计算平均查找长度。

查找操作实现错误:

? 错误:在查找操作中,没有根据关键字的散列值进行正确的查找操作,导致无法找到关键字或找到错误的关键字。

? 修改方法:根据关键字的散列值,从哈希表的对应槽位开始进行查找操作。如果槽位为空,则表示关键字不存在;如果槽位不为空,则需要比较关键字是否匹配。如果匹配,则找到了关键字;如果不匹配,则需要继续探测下一个槽位,直到找到关键字或达到哈希表的末尾。

哈希表插入操作错误:

? 错误:在插入关键字时,没有正确处理哈希表已满的情况,导致无法插入新的关键字。

? 修改方法:在插入操作之前,需要检查哈希表是否已满。如果哈希表已满,无法插入新的关键字。可以考虑使用动态哈希表,当哈希表达到一定负载因子时,进行扩容操作。

哈希表查找操作错误:

? 错误:在查找操作中,没有正确处理哈希表中不存在该关键字的情况,导致错误地返回了一个不存在的关键字。

? 修改方法:在查找操作中,首先需要根据关键字的散列值进行查找操作。如果槽位为空,则表示要查找的关键字不存在。只有在找到关键字后才能返回结果。

通过这次实验,我学到以下几点:

1. 哈希表的实现和使用:通过实验,我学会了如何实现一个哈希表,并了解哈希表的基本原理和操作。我学会了选择合适的哈希函数、处理冲突的方法以及如何插入、查找和删除元素等操作。

2. 冲突处理方法:在实验中,我学习了不同的冲突处理方法,例如线性探测法。我了解到冲突处理方法的优缺点,并学会根据具体情况选择合适的方法。

3. 平均查找长度(ASL)的计算:通过实验,我学习了如何计算哈希表的平均查找长度(ASL)。我了解到ASL是衡量哈希表性能的重要指标之一,可以通过ASL来评估哈希表的效率和性能。

4. 调试和错误修复:在实验过程中,我可能会遇到一些错误和问题,例如哈希函数选择不当、冲突处理方法有误等。通过调试和修复这些错误,我可以学会分析和解决问题的能力,提高我的调试技巧和问题解决能力。

5. 实践和应用能力:通过实验,我将理论知识应用到实际的编程任务中,提高我的实践和应用能力。通过编写代码、进行实验和分析结果来加深对哈希表的理解,并将所学知识应用到其他类似的问题中。

文章来源:https://blog.csdn.net/qq_73625278/article/details/135043226
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。