要求
使用线性开型寻址实现
描述
给定散列函数的除数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。
输出格式
按要求输出。
样例1
输入
7 12
1 21
0 1
0 13
0 5
0 23
0 26
0 33
1 33
1 33
1 13
1 5
1 1
输出
-1
1
6
5
2
0
3
3
3
6
5
1
样例二
输入
20 30
0 84
0 15
0 54
2 15
2 84
1 54
2 54
0 89
1 89
0 13
0 48
2 89
0 60
0 24
1 13
0 6
1 24
0 31
2 60
2 48
0 49
0 9
1 6
1 13
0 33
2 49
0 60
1 6
2 9
1 60
输出
4
15
14
0
0
14
0
9
9
13
8
0
0
4
13
6
4
11
0
0
9
10
6
13
14
1
0
6
0
0
限制
1s, 1024KiB for each test case.
#include <iostream>
#include <cstdlib>
using namespace std;
template<class K, class E>
class hashTable{
public:
~hashTable(){delete []table;} // 析构函数
hashTable(int theDivisor = 11); // 构造函数
int size(){return dSize;} // 返回长度
pair<K, E>* find(const K&); // 寻找
void insert(const pair<const K, E>&); // 插入
void erase(const K& ); // 删除
protected:
int search(const K&) const; // 查询
pair<const K, E>**table; // 散列表
int divisor; // 散列函数的除数
int dSize; // 字典中数对的个数
};
// 构造函数
template<class K, class E>
hashTable<K, E>::hashTable(int Divisor){
divisor = Divisor;
dSize = 0;
// 分配和初始化散列表数组
table = new pair<const K, E>* [divisor];
// 将所有桶置空
for(int i = 0; i < divisor; i++){
table[i] = NULL;
}
}
// 查询
template<class K, class E>
int hashTable<K, E>::search(const K& theKey)const{
int i = (int)theKey % divisor; // 起始桶
int j = i; // 从起始桶开始
do{
if(table[j] == NULL || table[j]->first == theKey){ // 检测直到桶为空或者遍历一遍
return j;
}
else{
j = (j + 1) % divisor;
}
}while(j != i); // 又回到起始桶
return j; // 表已经满
}
// 寻找
template<class K, class E>
pair<K, E> *hashTable<K, E>::find(const K& theKey){
int b = search(theKey);
if(table[b] == NULL || table[b]->first != theKey){
cout << -1 << endl;
return NULL; // 未找到匹配的数对
}
else{
cout << b << endl;
}
}
// 插入
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){ // 找到之后进行输出为第几个
table[b]->second = thePair.second;
cout << b << endl;
}
else{
cout << "Existed" << endl;
}
}
// 删除
template<class K, class E>
void hashTable<K, E>::erase(const K& theKey){
int b = search(theKey);
if(table[b] == NULL || table[b]->first != theKey){
cout << "Not Found" << endl;
}
else{
table[b] = NULL; // 删除
int n = b, a = b; // 设置删除点,便于遍历
b = (b+1) % divisor; // 从删除的后一位开始遍历
int x = 0; // 记录移动个数
while(table[b]!= NULL && b != n){ // 没有遇到空桶或者没有遍历一遍的话继续执行
int m = (int)table[b]->first % divisor; // b索引中数字应该在的索引位置
// 三种情况进行移动
// 1.空桶在b索引之前,而b索引对应的数字应该在的索引大于b,实现左移一位(循环)
// 2.b索引小于b中对应数字应该在的索引,且空桶大于等于b中数字应该对应的索引,实现左移一位(循环)
// 3.b中数字应该对应的索引小于等于空桶且b在空桶之后,实现左移一位
// 下面表达式可以理解为
// a: 空桶(上一次移动的元素对应的数组索引(第a个桶))
// b: 指针指向的数组索引(即第b个桶)
// m: 第b个桶中数字原本应该在的数组索引(原本应该在的第m个桶)
if((a < b && b < m) || (b < m && m <= a) || (m <= a && a < b)){
table[a] = table[b];
a = b;
x++;
}
b = (b+1)%divisor; // 指针移动
}
table[a] = NULL; // 最后进行删除,使其等于空
cout << x << endl;
}
}
int main(){
int D, m;
cin >> D >> m;
hashTable<int,int> a(D);
for(int i = 0; i < m; i++){
int r, t;
cin >> r >> t;
switch(r){
case 0: {pair<int, int>p(t, 0); a.insert(p);}
break;
case 1: {pair<int, int> *p = a.find(t);}
break;
case 2: a.erase(t);
break;
}
}
return 0;
}