问题描述
请设计一个整型闭散列表,散列函数为除留余数法,处理冲突时的探查方法为线性探查法,其中散列表的长度、除留余数法的模和关键码的个数由键盘输入,再根据输入由键盘输入所有的关键码。分别对三个待查值在散列表中进行查找,如果找到了输出位置,如果没找到,输出“none”并把该待查值插入到散列表中,如果散列表满输出“full”。
输入描述
各个命令以及相关数据的输入格式如下:
第一行输入闭散列表的长度n
第二行输入除留余数法的模m
第三行输入关键码的个数num
第四行输入num个整型关键码
第五行输入三个待查整型值
输出描述
输出三行,每行格式为:
如果找到待查值,输出找到待查值的位置,如果没找到,输出“none”,并将待查值插入到散列表中,如果散列表满,则输出“full”,每个待查值占一行
输入样例
11 11 9
2 6 8 9 13 17 10 12 20
3 7 11
输出样例
none
none
full
问题分析
首先要清楚什么是散列查找,散列查找所用的储存形式是线性的,同样是用数组储存,但是与折半查找和顺序查找不同的是,散列查找是通过唯一指定的地址进行查找,比如 关键码是8,散列函数是f(x) = x%10,这样的话,这个关键码储存的位置就是数组中小标为8的地址,但是如果还存在除十取余等于8的关键码,那么他的储存位置就是上一个余数是8的关键码逻辑地址加一的地方,当然,如果那个位置已经有关键码存在了,那么就接着向下找下一个没有存关键码的地址。这样的话就减少查找的次数,提高了效率。
代码
#include<iostream>
const int MaxSize = 100;
using namespace std;
class HashTabel
{
public:
HashTabel(int, int, int, int*);
void Search(int); //查找函数
private:
int H(int); //散列函数
int ht[MaxSize]; //用来储存关键码
int mod;
int length;
};
HashTabel::HashTabel(int m, int num, int len, int *a)
{
int k, j;
mod = m;
length = len;
for (int i = 0; i < length; i++) //将关键码初始化为0
{
ht[i] = 0;
}
for (int i = 0; i < num; i++)
{
k = H(a[i]); //通过散列函数来计算关键码应该储存的位置
if (!ht[k]) //判断此位置是否已经存在关键码,如果不存在,则将关键码储存在这个位置
{
ht[k] = a[i];
}
else //否则逻辑地址 加一
{
j = (k + 1) % length;
while (ht[j] && j != k)
{
j = (j + 1) % length;
}
if (!ht[j]) //重新找到储存的地址之后,将关键码储存
{
ht[j] = a[i];
}
}
}
}
int HashTabel::H(int k)
{
return k % mod; //散列函数
}
void HashTabel::Search(int k)
{
int j = H(k);
if (ht[j] == k) //如果查找到,直接输出关键码
{
cout << j << endl;
}
else if (!ht[j]) //如果关键码应该储存的位置没有此关键码,说明在已有数据中没有此关机那么
{
ht[j] = k;
cout << "none" << endl;
}
else //如果前面两种情况都不符合,逻辑地址加一,继续查找
{
j = (j + 1) % length;
while (ht[j] && j != H(k))
{
if (ht[j] == k)
{
cout << j << endl;
return ;
}
else
{
j = (j + 1) % length;
}
}
if (!ht[j])
{
ht[j] = k;
cout << "none" << endl;
}
else
{
cout << "full" << endl;
}
}
}
int main()
{
int n, mod, num, x, *a;
cin >> n >> mod >> num;
a = new int[n];
for (int i = 0; i < num; i++)
{
cin >> a[i];
}
HashTabel h(mod, num, n, a);
for (int i = 0; i < 3; i++)
{
cin >> x;
h.Search(x);
}
delete a;
return 0;
}