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

被折叠的 条评论
为什么被折叠?



