C++ 散列表线性开型寻址

散列表线性开型寻址

问题描述

给定散列函数的除数D和操作数m,输出每次操作后的状态。

有以下三种操作:

  1. 插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。
  2. 查询x,若散列表不含有x,输出“-1”,否则输出x对应下标。
  3. 删除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)
  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值