实验8.1 线性开型寻址
要求
使用线性开型寻址实现
描述
给定散列函数的除数D和操作数m,输出每次操作后的状态。
有以下三种操作:
- 插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。
- 查询x,若散列表不含有x,输出“-1”,否则输出x对应下标。
- 删除x,若散列表不含有x,输出“Not Found”,否则输出删除x过程中移动元素的个数。
格式
输入格式
第一行两个整数D,m。分别代表散列函数的除数D和操作数m。
接下来m行,每行两个整数opt和x,分别代表操作类型和操作数。
若opt为0,代表插入x。
若opt为1,代表查询x。
若opt为2,代表删除x。
输出格式
按要求输出。
思路与探讨
散列表线性探查
整体思路描述
-
主要是散列表描述字典中线性探查的应用,包括哈希表的类定义及搜索、查询、插入、删除等功能函数的定义与实现。
本次实验几乎全是基本数据结构模型应用,在课本相关功能基础上,在输出上做了细微调整。
细节思路描述
方法search
搜索一个公开地址散列表,查找关键字为theKey的数对;
如果匹配的数对存在,返回它的位置
否则,如果散列表不满,则返回关键字为theKey的数对可以插入的位置
-
首先搜索关键字为k的起始桶f(k)
-
接着对表中后继桶进行搜索,直到发生以下情况:
- (1)存有关键字为k的桶已找到,即找到了要搜索的数对
- (2)到达一个空桶
- (3)又回到起始桶f(k)。
-
若发生情况(2)和(3),则说明表中没有关键字为k的数对。
方法insert
插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。
- 用
search
搜索散列表,查找匹配的数对 - 检查匹配的数对是否存在
- 若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标(
search
会返回可以插入的位置)。
方法find
查询x,若散列表不含有x,输出“-1”,否则输出x对应下标。
- 用
search
搜索散列表,查找匹配的数对 - 检查匹配的数对是否存在
- 若散列表不含有x(含有的要求是严格的对应键就是theKey),输出“-1”,否则输出x对应下标
方法earse
散列表不含有x,输出“Not Found”,否则输出删除x过程中移动元素的个数。
-
用
search
搜索散列表,查找匹配的数对 -
检查匹配的数对是否存在
-
若散列表不含有x(含有的要求是严格的对应键就是theKey),输出“Not Found”,否则输出输出删除x过程中移动元素的个数。
-
关键点提示:
-
signal = table[point]->first % divisor;
-
m
是移动辅助变量,point
是当前元素位置,signal
是当前元素的理想位置。 -
移动的三种情况:
(signal <= m && m < point) || (point < signal && signal <= m) || (point < signal && m < point)
-
具体情况流程举例
-
方法补充
把类型k映射到一个非负整数(不加这个OJ也能过,但是这是哈希表处理重点)
template <class K> class Hash;
template<>
class Hash<int>
{
public:
size_t operator()(const int theKey) const
{
return size_t(theKey);
}
};
//原文链接:https://blog.csdn.net/SunnySantino/article/details/112688024
若已看懂思路,试着自己写~
实现代码
#include <string>
#include <iostream>
using namespace std;
template<class K, class E>
class hashTable
{
public:
hashTable(int theDivisor = 11);
~hashTable() { delete[] table; }
//插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。
void insert(const pair<const K, E>&);
//查询x,若散列表不含有x,输出“-1”,否则输出x对应下标。
void find(const K& theKey) const;
//删除x,若散列表不含有x,输出“Not Found”,否则输出删除x过程中移动元素的个数。
void erase(K& theKey);
protected:
int search(const K&) const;
pair<const K, E>** table;//散列表
int dSize;//字典中数对的个数
int divisor;//散列函数的除数
};
//构造函数
template<class K, class E>
hashTable<K, E>::hashTable(int theDivisor)
{
divisor = theDivisor;
dSize = 0;
//分配和初始化散列表数组
table = new pair<const K, E> * [divisor];
for (int i = 0; i < divisor; i++)
table[i] = NULL;
}
//方法search
template<class K, class E>
int hashTable<K, E>::search(const K& theKey) const
{//搜索一个公开地址散列表,查找关键字为theKey的数对;
//如果匹配的数对存在,返回它的位置
//否则,如果散列表不满,则返回关键字为theKey的数对可以插入的位置
int i = theKey % divisor;//起始桶
int j = i;//从起始桶开始
do
{
if (table[j] == NULL || table[j]->first == theKey)
return j;
j = (j + 1) % divisor;//下一个桶
} while (j != i);//结束条件判断:是否返回到起始桶
return j;//表满
}
//插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。
template<class K, class E>
void hashTable<K, E>::insert(const pair<const K, E>& thePair)
{
//搜索散列表,查找匹配的数对
int b = search(thePair.first);
//检查匹配的数对是否存在
if (table[b] == NULL)
{
table[b] = new pair<const K, E>(thePair);
dSize++;
cout << b << endl;
}
else
{
if (table[b]->first == thePair.first)
{
cout << "Existed" << endl;
}
}
}
//若散列表不含有x,输出“-1”,否则输出x对应下标
template<class K, class E>
void hashTable<K, E>::find(const K& theKey) const
{
int b = search(theKey);
if (table[b] == NULL || table[b]->first != theKey)
{
cout << -1 << endl;
return;
}
cout << b << endl;
return;
}
//若散列表不含有x,输出“Not Found”,否则输出删除x过程中移动元素的个数。
template <class K, class E>
void hashTable<K, E>::erase(K& theKey)
{
//搜索散列表,查找匹配的数对
int b = search(theKey);
if (table[b] == NULL || table[b]->first != theKey)
cout << "Not Found" << endl;
else
{
table[b] = NULL;
int flag = 0;//记录移动元素的个数
int point = b, m = b, signal;
//从欲删除的数对开始逐个检查每个桶以确定要移动的数对
do
{
point = (point + 1) % divisor;//下一个桶
if (table[point] == NULL)
break;
signal = table[point]->first % divisor;
if ((signal <= m && m < point) || (point < signal && signal <= m) || (point < signal && m < point))
{
table[m] = table[point];
table[point] = NULL;
m = point;
flag++;
}
} while (table[(point + 1) % divisor] != NULL && point != b);
cout << flag << endl;
}
}
int main()
{
int D, m;//散列函数的除数D和操作数m
cin >> D >> m;
hashTable<int, int> a(D);
pair<int, int> q;
for (int i = 0; i < m; i++)
{
int opt, number;
cin >> opt >> number;
if (opt == 0)
{
q.first = number;
q.second = number;
a.insert(q);
}
else if (opt == 1)
{
q.first = number;
q.second = number;
a.find(q.first);
}
else
{
q.first = number;
q.second = number;
a.erase(q.first);
}
}
return 0;
}