PTA Hashing 思路分析及代码解析

本文详细介绍了使用开放地址法实现哈希表的过程,包括创建哈希表、正向平方探测法处理冲突以及插入元素的方法。文章通过实例代码解析了PTA/拼题A中的7-17Hashing题目,讨论了如何将数字插入哈希表并打印插入位置,同时提到了在实现过程中需要注意的细节,如素数表大小的选择。此外,还提供了完整的AC编码供参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前导

1. 需要掌握的知识

通过开放地址法实现Hash/哈希表

2. 题目信息

2.1 题目来源:PTA / 拼题A
2.2 题目地址: 7-17 Hashing

二、解题思路分析

1. 题意理解

将输入的数字插入Hash表中,并打印插入的位置

1. 1 输入数据

4 4  //用户给出的Hash表大小(若非素数需要调整) 待输入的数字个数
10 6 4 15 //具体的数字

1.2 输出数据

0 1 4 - //打印插入的位置,若无法插入,打印'-'
......

2. 思路分析

2.1 与何老师讲解的思路一致:首先创建Hash表(开发地址),然后将录入的数据存储在Hash表中,若发生冲突,通过正向平方探测法解决。这样的好处是:将学到的知识进行实际编码运用;缺点就是:代码量偏大,耗费时间较多
2.2 简便方法:不创建Hash表,用一个数组即可,数组元素初始值为0,插入元素 等价于 将对应数组下标的元素值置为1

三、具体实现

1. 弯路和bug

质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数:可能今天吃了脑残片了,鬼使神差的把2开除出素数了,导致最小值测试点无法正常通过

2. 代码框架

2.1 采用的数据结构

结构体,通过开放地址法构建Hash表/散列表

typedef int ElementType;
typedef int Position;
typedef enum {Occupied,Empty,Deleted} PositionStatus; //就本题来说,由于不涉及删除,Deleted状态是无用的

struct HashTableCell //Hash表中的一个单元
{
	ElementType Data;
	PositionStatus Status;
};
typedef HashTableCell Cell;


struct HashTableStructure //Hash表
{
	int TableSize;
	Cell *CellArray; //存放散列单元数据的数组
};
typedef HashTableStructure *HashTable;

2.2 程序主体框架

               程序伪码描述
int main()
{
	1.创建Hash表(开放地址)
	2.将录入的数字插入到Hash表中并打印插入的位置
}

2.3 各分支函数

2.3.1 CreateHashTable( ) 创建Hash表,注意:Hash表的大小在创建前已经确定,因此在创建时不需要处理

HashTable CreateHashTable(int TableSize)
{
	HashTable H;
	H = (HashTable)malloc(sizeof(struct HashTableStructure));
	//H->TableSize = NextPrime(TableSize);
	H->TableSize = TableSize;

	H->CellArray = (Cell*)malloc(sizeof(Cell) * H->TableSize);

	for (int i = 0; i < H->TableSize; i++)
		H->CellArray[i].Status = Empty;

	return H;
}

2.3.2 Find( ) 在Hash表中搜索元素,Find函数被Insert函数调用。这里注意两点:I.我们采用的是正向平分探测法解决冲突,有些数字可能无法插入到Hash表中,因此需要设定一个退出条件,冲突次数超过表的大小时,则插入失败 II.查找是为了找到空位,不需要找到对应的元素

		if (ConflictNumber > H->TableSize)
			return Null;	
Position Find(HashTable H, ElementType Key)
{
	Position CurrentPostion, NewPosition;
	int ConflictNumber=0;
	
	NewPosition = CurrentPostion = Hash(Key, H->TableSize);

	//当前位置的单元非空 且 不是要找的元素,触发冲突
	//while (H->CellArray[NewPosition].Status != Empty && H->CellArray[NewPosition].Data != Key)
	while (H->CellArray[NewPosition].Status != Empty )
	{
		ConflictNumber++;
		NewPosition = CurrentPostion + ConflictNumber * ConflictNumber;
		
		if (NewPosition > H->TableSize)
			NewPosition = NewPosition % H->TableSize;

		if (ConflictNumber > H->TableSize)
			return Null;	
	}
	return NewPosition;
}

2.3.3 Insert( ) 在Hash表中插入元素:找到空位就插入并返回插入的具体位置,否则返回 -1

int Insert(HashTable H, ElementType Key)
{
	Position Pos = Find(H, Key);

	if (Pos == Null)
		return Null;
	else
	{
		H->CellArray[Pos].Status = Occupied;
		H->CellArray[Pos].Data = Key;

		return Pos;
	}
}

3. 完整AC编码

如有建议或问题,欢迎留言

#include <iostream>
#include <cstdlib>
#include <cmath>
using namespace std;

#define MAX 100000
#define Null -1

typedef int ElementType;
typedef int Position;
typedef enum {Occupied,Empty,Deleted} PositionStatus;

struct HashTableCell
{
	ElementType Data;
	PositionStatus Status;
};
typedef HashTableCell Cell;


struct HashTableStructure
{
	int TableSize;
	Cell *CellArray; //存放散列单元数据的数组
};
typedef HashTableStructure *HashTable;

HashTable CreateHashTable(int TableSize);
Position Find(HashTable H, ElementType Key);
int Hash(int Key, int TableSize);
int Insert(HashTable H, ElementType Key);
int NextPrime(int n);
bool JudgePrime(int n);


int main()
{
	int Size, Number,Data,Pos;
	cin >> Size >> Number;

	if (!JudgePrime(Size))
		Size = NextPrime(Size);

	HashTable H;
	H = CreateHashTable(Size);


	cin >> Data;
	Pos = Insert(H, Data);

	if (Pos == Null)
		cout << '-';
	else
		cout << Pos;

	for (int i = 1; i < Number; i++)
	{
		cin >> Data;
		Pos = Insert(H, Data);

		if (Pos == Null)
			cout <<" -";
		else
			cout<<' '<< Pos;
	}


	return 0;
}

int Insert(HashTable H, ElementType Key)
{
	Position Pos = Find(H, Key);

	if (Pos == Null)
		return Null;
	else
	{
		H->CellArray[Pos].Status = Occupied;
		H->CellArray[Pos].Data = Key;

		return Pos;
	}

	/*if (H->CellArray[Pos].Status != Occupied)
	{
		H->CellArray[Pos].Status = Occupied;
		H->CellArray[Pos].Data = Key;

		cout << Pos << ' ';

		return true;
	}
	else
		return false;*/
}

Position Find(HashTable H, ElementType Key)
{
	Position CurrentPostion, NewPosition;
	int ConflictNumber=0;
	
	NewPosition = CurrentPostion = Hash(Key, H->TableSize);

	//当前位置的单元非空 且 不是要找的元素,触发冲突
	//while (H->CellArray[NewPosition].Status != Empty && H->CellArray[NewPosition].Data != Key)
	while (H->CellArray[NewPosition].Status != Empty )
	{
		ConflictNumber++;
		NewPosition = CurrentPostion + ConflictNumber * ConflictNumber;
		
		if (NewPosition > H->TableSize)
			NewPosition = NewPosition % H->TableSize;

		if (ConflictNumber > H->TableSize)
			return Null;	
	}
	return NewPosition;
}

HashTable CreateHashTable(int TableSize)
{
	HashTable H;
	H = (HashTable)malloc(sizeof(struct HashTableStructure));
	//H->TableSize = NextPrime(TableSize);
	H->TableSize = TableSize;

	H->CellArray = (Cell*)malloc(sizeof(Cell) * H->TableSize);

	for (int i = 0; i < H->TableSize; i++)
		H->CellArray[i].Status = Empty;

	return H;
}

int Hash(int Key, int TableSize)
{
	return Key % TableSize;
}

bool JudgePrime(int n)
{
	if (n == 1)
		return false;

	for (int i = 2; i * i <= n; i++)
	{
		if (!(n % i))
			return false;
	}
	return true;
}

int NextPrime(int n)
{
	if (n == 1) return 2;
	
	int i, next;

	next = (n % 2) ? n + 2:n+1; //next为大于n的奇数

	while (next < MAX)
	{
		for (i = 3; i * i <= next; i += 2)
			if (next % i == 0)
				break;

		if (i * i > next)
			return next;
		else
			next += 2;
	}
	return next;
}

四、参考

浙江大学 陈越、何钦铭老师主讲的数据结构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值