散列表线性开型寻址
问题描述
给定散列函数的除数D和操作数m,输出每次操作后的状态。
有以下三种操作:
- 插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。
- 查询x,若散列表不含有x,输出“-1”,否则输出x对应下标。
- 删除x,若散列表不含有x,输出“Not Found”,否则输出删除x过程中移动元素的个数。
输入格式
第一行两个整数D(1≤\leq≤ D ≤\leq≤ 3000)和m(1≤\leq≤ m ≤\leq≤ 3000),其中D为散列函数的除数,m为操作数。
接下来的m行,每行两个整数opt和x,分别代表操作类型和操作数。
若opt为0,则代表向散列表中插入x;
若opt为1,代表查询散列表中x是否存在;
若opt为2,(如果散列表中含有x),删除x。
数据保证散列表不会溢出。
输出格式
m行,每行一个整数,代表对应查询的答案。
样例输入1
7 15
2 10
0 10
0 10
2 10
1 10
0 10
1 10
0 17
0 2
0 16
0 11
2 2
2 10
1 11
1 17
样例输出2
Not Found
3
Existed
0
-1
3
3
4
2
5
6
2
2
4
3
首先是建立的散列表类:通过散列表实现,此程序把关键词和值看作相等,来简化操作(可以使用pair类型的数组,first代表Key,Second代表value)ht[]数组的下标位置是通过 k%D来算出来,并把值储存在ht[]中,然后还初始化一个empty[]布尔类型的数组,来看是否为空,首先全部初始化
template<class E, class K>
class HashTable {
public:
HashTable(int divisor = 11);
~HashTable()
{
delete[]ht;
delete[]empty;
}
int Search(const K&k, E& e) const;
HashTable<E, K>& Insert(const E& e);
void NewSearch(const K& k) const;
void Delete(const E &e);
private:
int hSearch(const K&k) const;
int D; //散列函数的除数
E *ht; //散列数组
bool * empty; //看是否为空的一维数组
};
然后写构造函数的实现方法:
template<class E,class K>
HashTable<E, K>::HashTable(int divisor) {
D = divisor;
ht = new E[D];
empty = new bool[D];
for (int i = 0; i < D; i++) {
empty[i] = true;
}
}
hSearch方法,通过K%D得出下标i,若为空即empty[i]=true(位置为空)或者ht[i]=k(已经找到),则返回下标,没有找到,说明被挤走了应该在后面。则i+1,继续循环,继续判断empty[i]=true(位置为空)或者ht[i]=k(已经找到)直到又回到最初的位置i为止。
template<class E, class K>
int HashTable<E, K>::hSearch(const K& k) const {
int i = k % D; //找 k对应散列表的位置
int j = i;
do {
if (empty[j] || ht[j] == k) return j; //找到或者为空,则返回
j = (j+1) % D;
} while (j != i); //若又回到i,则退出循环
return j;
}
Search得到下标,判断是否为空或者不等于关键词,则返回-1,否则返回true
template<class E, class K>
void HashTable<E, K>::NewSearch(const K& k) const {
int b = hSearch(k);
if (empty[b] || ht[b] != k)
cout << -1 << endl; //为空或者找到了起始桶即hSearch中i的位置
else {
cout << b << endl;
}
}
插入:Insert方法,通过hSearch方法,得到返回的下标,若为空,则加入,否则输出 Existed
template<class E, class K>
HashTable<E, K>& HashTable<E, K>::Insert(const E & e) {
K k = e;
int b = hSearch(k);
if (empty[b]) {
empty[b] = false;
ht[b] = e;
cout << b << endl;
}
else{
cout <<"Existed"<< endl;
}
return *this;
}
删除:先判断要删除的元素是否为空,若为空,则输出“Not Found“
不为空,判断是否为以下两种情况,其余情况则不需要移。先 将 i移到下一个,判断是否为空,若为空则break,不需要移动,否则
来判断这两种情况,进入if语句,进行移动,然后判断循环条件,while,下一个是否为空或者回到最初的位置b则结束
template<class E,class K>
void HashTable<E, K>::Delete(const E&e) {
K k = e;
int b = hSearch(k);
int Count = 0;
if (empty[b]) {
cout << "Not Found" << endl;
}
else if (ht[b] == k) {
empty[b] = true;
int i = b;
int z = b;
int x;
do {
i = (i + 1) % D; //当前元素的实际位置
if (empty[i]) { //看下一个是否为空
break;
}
x = ht[i] % D;
//cout << "x的值为:"<<x << endl; //当前元素本应该在的位置
if (i != x && x<=z &&i>z) { //被挤走
empty[z] = false;
ht[z] = ht[i];
empty[i] = true;
Count++;
z = i;
//cout << "good" << endl;
}
else if ((i != x && i < x && z < i)||(i!=x && i<x && z >=x)) {
empty[z] = false;
ht[z] = ht[i];
empty[i] = true;
Count++;
z = i;
}
} while (!empty[i+1] && (i+1)!= b);
cout << Count << endl;
}
}
接下来:是主函数按照实验要求接收输入:
int main()
{
int d, m, a,b;
cin >> d >> m;
HashTable<int,int> h(d);
for (int i = 1; i <= m; i++) {
cin >> a >> b;
switch (a)
{
case 0:
h.Insert(b);
break;
case 1:
h.NewSearch(b);
break;
case 2:
h.Delete(b);
break;
default:
break;
}
}
return 0;
}
完整代码:
#include <iostream>
using namespace std;
template<class E, class K>
class HashTable {
public:
HashTable(int divisor = 11);
~HashTable()
{
delete[]ht;
delete[]empty;
}
int Search(const K&k, E& e) const;
HashTable<E, K>& Insert(const E& e);
int Search(const K& k) const;
void NewSearch(const K& k) const;
void Delete(const E &e);
private:
int hSearch(const K&k) const;
int D; //散列函数的除数
E *ht; //散列数组
bool * empty; //看是否为空的一维数组
};
template<class E,class K>
HashTable<E, K>::HashTable(int divisor) {
D = divisor;
ht = new E[D];
empty = new bool[D];
for (int i = 0; i < D; i++) {
empty[i] = true;
}
}
template<class E, class K>
int HashTable<E, K>::hSearch(const K& k) const {
int i = k % D; //找 k对应散列表的位置
int j = i;
do {
if (empty[j] || ht[j] == k) return j; //找到或者为空,则返回
j = (j+1) % D;
} while (j != i); //若又回到i,则退出循环
return j;
}
template<class E, class K>
int HashTable<E, K>::Search(const K& k, E & e) const {
int b = hSearch(k);
if (empty[b] || ht[b] != k) return -1; //为空或者找到了起始桶即hSearch中i的位置
e = ht[b];
return b;
}
template<class E, class K>
int HashTable<E, K>::Search(const K& k) const {
int b = hSearch(k);
if (empty[b] || ht[b] != k) return -1; //为空或者找到了起始桶即hSearch中i的位置
return b;
}
template<class E, class K>
void HashTable<E, K>::NewSearch(const K& k) const {
int b = hSearch(k);
if (empty[b] || ht[b] != k)
cout << -1 << endl; //为空或者找到了起始桶即hSearch中i的位置
else {
cout << b << endl;
}
}
template<class E, class K>
HashTable<E, K>& HashTable<E, K>::Insert(const E & e) {
K k = e;
int b = hSearch(k);
if (empty[b]) {
empty[b] = false;
ht[b] = e;
cout << b << endl;
}
else{
cout <<"Existed"<< endl;
}
return *this;
}
template<class E,class K>
void HashTable<E, K>::Delete(const E&e) {
K k = e;
int b = hSearch(k);
int Count = 0;
if (empty[b]) {
cout << "Not Found" << endl;
}
else if (ht[b] == k) {
empty[b] = true;
int i = b;
int z = b;
int x;
do {
i = (i + 1) % D; //当前元素的实际位置
if (empty[i]) { //看下一个是否为空
break;
}
x = ht[i] % D; //x为起始桶
//cout << "x的值为:"<<x << endl; //当前元素本应该在的位置
if (i != x && x<=z &&i>z) { //被挤走
empty[z] = false;
ht[z] = ht[i];
empty[i] = true;
Count++;
z = i;
//cout << "good" << endl;
}
else if ((i != x && i < x && z < i)||(i!=x && i<x && z >=x)) {
empty[z] = false;
ht[z] = ht[i];
empty[i] = true;
Count++;
z = i;
}
} while (!empty[i+1] && (i+1)!= b);
cout << Count << endl;
}
}
int main()
{
int d, m, a,b;
cin >> d >> m;
HashTable<int,int> h(d);
for (int i = 1; i <= m; i++) {
cin >> a >> b;
switch (a)
{
case 0:
h.Insert(b);
break;
case 1:
h.NewSearch(b);
break;
case 2:
h.Delete(b);
break;
default:
break;
}
}
return 0;
}
下面为散列表用链表描述的完整代码:
#include <iostream>
#include<limits.h>
using namespace std;
template<class E, class K>
class SortedChain;
template<class E, class K> //E:链表元素的数据类型,K:关键字。
class SortedChainNode {
friend SortedChain<E, K>;
public :
void set(int a){
data = a;
}
private:
E data;
SortedChainNode< E, K > *link;
};
template<class E, class K>
class SortedChain {
public:
SortedChain() { first = 0; }
~SortedChain();
bool IsEmpty() const { return first == 0; }
bool Search(const K& k) const;
SortedChain<E, K>& Delete(const K& k);
SortedChain<E, K>& DistinctInsert(const E& e);//不允许关键词相同
private:
SortedChainNode<E, K> *first;
};
template<class E, class K>
SortedChain<E, K>::~SortedChain() {
SortedChainNode<E, K> * current;
while (first) {
current = first->link;
delete first;
first = current;
}
}
template<class E, class K>
bool SortedChain<E, K>::Search(const K& k) const
{
SortedChainNode<E, K> *p = first;
SortedChainNode<E, K> *current = first;
int Count = 0;
for (; p && p->data < k; p = p->link);
for (; current; current = current->link) {
Count++;
}
if (p && p->data == k) // 与k相匹配
{
cout <<--Count << endl;
return true;
}
else {
cout << "Not Found" << endl;
}
return false; // 不存在相匹配的元素
}
template<class E, class K>
SortedChain<E, K>& SortedChain<E, K>::Delete(const K& k)
{
SortedChainNode<E, K> *p = first, *tp = 0; //p 指向匹配的节点,tp 指向p 前面的节点。
int Count = 0; SortedChainNode<E, K> *current = first;
for (; p && p->data < k; tp = p, p = p->link); // 搜索与k相匹配的元素
for (; current; current = current->link) {
Count++;
}
// 验证是否与k匹配
if (p && p->data == k) {// 找到一个相匹配的元素
if (tp) tp->link = p->link; // 从链表中删除p所指向的元素
else first = p->link; // p是链首节点
delete p;
Count--;
cout <<--Count << endl;
}
else {
cout << "Delete Failed" << endl;
}
return *this;
}
template<class E, class K>
SortedChain<E, K>& SortedChain<E, K>::DistinctInsert(const E& e)
{// 如果表中不存在关键值与e相同的元素,则插入e
//否则引发异常BadInput
SortedChainNode<E, K> *p = first, *tp = 0; // 跟踪p
// 移动tp 以便把e 插入到tp之后
for (; p && p->data < e; tp = p, p = p->link);
if (p && p->data == e)
{
cout << "Existed" << endl;
}
else {
// 若没有出现重复关键值, 则产生一个关键值为e的新节点
SortedChainNode<E, K> *q = new SortedChainNode<E, K>;
q->data = e;
q->link = p;
if (tp) tp->link = q; // 将新节点插入到t p之后
else
{
first=new SortedChainNode<E, K>;
first->data = INT_MAX;
first->link= q;
}
}
return *this;
}
template<class E, class K>
class ChainHashTable {
public:
ChainHashTable(int divisor = 11)//divisor(除数)
{
D = divisor;
ht = new SortedChain<E, K>[D];
}
//head pointer array, each ht[i] has a Sorted chain.
~ChainHashTable() { delete[] ht; }
bool Search(const K& k) const
{
return ht[k%D].Search(k);
}
ChainHashTable<E, K>& Insert(const E& e)
{
ht[e%D].DistinctInsert(e);
return *this;
}
ChainHashTable<E, K>& Delete(const K& k)
{
ht[k%D].Delete(k);
return *this;
}
private:
int D; // 位置数
SortedChain<E, K> *ht; // 链表数组
};
int main()
{
int d, m, a, b;
cin >> d >> m;
ChainHashTable<int, int> ch(d);
for (int i = 1; i <= m; i++) {
cin >> a >> b;
switch (a)
{
case 0:
ch.Insert(b);
break;
case 1:
ch.Search(b);
break;
case 2:
ch.Delete(b);
break;
default:
break;
}
}
return 0;
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20181129090944482.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RpbmdfcHJvZ3JhbW1lcg==,size_16,color_FFFFFF,t_70)