石 家 庄 铁 道 大 学
实 验 报 告
课程名称: 数据结构与算法设计 任课教师: 刘 丹 实验日期:2024.12.15
班 级: 信2305-3 姓 名: 徐戌 学 号: 20234316
实验项目名称:实验五
一、 实验目的
1.掌握散列表的建立
2.掌握散列查找算法的实现。
二、 实验内容
三、 设计文档
四、 源程序
6-2 线性探测法的查找函数
include <stdio.h>
define MAXTABLESIZE 100000 /* 允许开辟的最大散列表长度 */
typedef int ElementType; /* 关键词类型用整型 /
typedef int Index; / 散列地址类型 /
typedef Index Position; / 数据所在位置与散列地址是同一类型 /
/ 散列单元状态类型,分别对应:有合法元素、空单元、有已删除元素 */
typedef enum { Legitimate, Empty, Deleted } EntryType;
typedef struct HashEntry Cell; /* 散列表单元类型 /
struct HashEntry{
ElementType Data; / 存放元素 /
EntryType Info; / 单元状态 */
};
typedef struct TblNode HashTable; / 散列表类型 /
struct TblNode { / 散列表结点定义 /
int TableSize; / 表的最大长度 */
Cell Cells; / 存放散列单元数据的数组 */
};
HashTable BuildTable(); /* 裁判实现,细节不表 */
Position Hash( ElementType Key, int TableSize )
{
return (Key % TableSize);
}
define ERROR -1
Position Find( HashTable H, ElementType Key );
int main()
{
HashTable H;
ElementType Key;
Position P;
H = BuildTable();
scanf("%d", &Key);
P = Find(H, Key);
if (P==ERROR)
printf("ERROR: %d is not found and the table is full.\n", Key);
else if (H->Cells[P].Info == Legitimate)
printf("%d is at position %d.\n", Key, P);
else
printf("%d is not found. Position %d is returned.\n", Key, P);
return 0;
}
Position Find( HashTable H, ElementType Key )
{
Index hashAddr = Hash(Key, H->TableSize);
int curPos = hashAddr;
// 开始线性探测查找
while (1)
{
if (H->Cells[curPos].Info == Empty)
{
return curPos;
}
else if (H->Cells[curPos].Info == Legitimate && H->Cells[curPos].Data == Key)
{
return curPos;
}
curPos = (curPos + 1) % H->TableSize;
if (curPos == hashAddr)
{
// 说明转了一圈,表已满
return ERROR;
}
}
}
7-1 整型关键字的散列映射
include <stdio.h>
include <stdbool.h>
// 判断一个数是否为素数
bool isPrime(int num) {
if (num < 2) return false;
for (int i = 2; i * i <= num; i++) {
if (num % i == 0) return false;
}
return true;
}
// 找到大于等于n的最小素数
int findPrime(int n) {
while (!isPrime(n)) {
n++;
}
return n;
}
int main() {
int n, p;
scanf("%d %d", &n, &p);
// 获取合适的素数作为散列表长度
p = findPrime(p);
int hashTable[p];
// 初始化散列表,-1表示空位置
for (int i = 0; i < p; i++) {
hashTable[i] = -1;
}
int keys[n];
for (int i = 0; i < n; i++) {
scanf("%d", &keys[i]);
}
// 插入关键字到散列表
for (int i = 0; i < n; i++) {
int pos = keys[i] % p;
while (hashTable[pos]!= -1 && hashTable[pos]!= keys[i]) {
pos = (pos + 1) % p;
}
hashTable[pos] = keys[i];
}
// 输出各关键字在散列表中的位置
for (int i = 0; i < n; i++) {
int pos = keys[i] % p;
while (hashTable[pos]!= keys[i]) {
pos = (pos + 1) % p;
}
if (i > 0) {
printf(" ");
}
printf("%d", pos);
}
printf("\n");
return 0;
}
五、 个人体会
遇到的问题:
在实现线性探测法的查找函数时,对于循环结束条件的判断容易出错,一开始没有准确记录初始哈希地址,导致无法正确判断是否已经遍历完整个哈希表一圈都没找到元素的情况,出现死循环或者错误判断元素存在与否的问题。
对哈希表初始化时,没有考虑好合适的表示空位的默认值,导致插入和查找过程中逻辑混乱。
解决办法:
通过仔细分析线性探测的原理和流程,添加变量来记录初始哈希地址,在每次位置更新后与初始地址比较,以此准确判断是否遍历完一圈,完善了查找函数的循环结束条件判断逻辑。
对于哈希表初始化,参考相关资料和示例,根据实际插入元素的范围,选择了不会与正常元素值冲突的 -1 来表示空位,重新梳理了插入和查找过程基于这个空位表示的逻辑。
实验感想:
通过这次实验,深刻体会到了哈希表中线性探测法的原理和实现细节的重要性。一个看似简单的查找函数,却需要严谨地考虑各种边界情况和逻辑处理,小小的疏忽就可能导致功能出错。同时也明白了在遇到问题时,仔细分析原理、参考资料以及耐心调试是解决问题的关键,这让我对数据结构中的哈希相关知识有了更扎实的掌握。