深圳大学数据结构OJ-哈希查找

深圳大学数据结构OJ-哈希查找

问题A:DS哈希查找—线性探测再散列

题目描述

定义哈希函数为H(key) = key%11,输入表长(大于、等于11)。输入关键字集合,用线性探测再散列构建哈希表,并查找给定关键字。

输入

测试次数t

每组测试数据为:

哈希表长m、关键字个数n

n个关键字

查找次数k

k个待查关键字

输出

对每组测试数据,输出以下信息:

构造的哈希表信息,数组中没有关键字的位置输出NULL

对k个待查关键字,分别输出:0或1(0—不成功,1—成功)、比较次数、查找成功的位置(从1开始)

输入样例

1
12 10
22 19 21 8 9 30 33 4 15 14
4
22
56
30
17

输出样例

22 30 33 14 4 15 NULL NULL 19 8 21 9
1 1 1
0 6
1 6 2
0 1

AC代码

#include <iostream>
using namespace std;
int m;//表长
int n;//关键字个数
int k;//查找个数
int arr[1000];
int check_arr[1000];
int hash_arr[1000];
//创建哈希表
void Creat_hash_arr()
{
	int index;
	for (int i = 0; i < n; i++)
	{
		index = arr[i] % 11;
		if (hash_arr[index] == 0)
		{
			hash_arr[index] = arr[i];
		}
		else
		{
			while (hash_arr[index] != 0)
			{
				index = (index + 1) % m;
			}
			hash_arr[index] = arr[i];
		}
	}
	//输出
	for (int i = 0; i < m; i++)
	{
		if (hash_arr[i] == 0) cout << "NULL";
		else cout << hash_arr[i];
		if (i != m - 1) cout << " ";
	}
	cout << endl;
}
//查找元素
void check()
{
	int flag;
	int check_num;
	int index;
	for (int i = 0; i < k; i++)
	{
		flag = 0;
		check_num = 0;
		index = check_arr[i] % 11;
		while (1)
		{
			//查找失败
			if (hash_arr[index] == 0)
			{
				check_num++;
				flag = 0;
				break;
			}
			//查找成功
			if (hash_arr[index] == check_arr[i])
			{
				check_num++;
				flag = 1;
				break;
			}
			check_num++;
			index = (index + 1) % m;
		}
		cout << flag << " " << check_num;
		if (flag)
		{
			cout << " " << index + 1 << endl;
		}
		else
		{
			cout << endl;
		}
	}
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> m >> n;
		for (int i = 0; i < n; i++)
		{
			cin >> arr[i];
		}
		cin >> k;
		for (int i = 0; i < k; i++)
		{
			cin >> check_arr[i];
		}
		//创建哈希表
		Creat_hash_arr();
		//查找元素
		check();
	}

	return 0;
}

问题B:DS哈希查找—二次探测再散列

题目描述

定义哈希函数为H(key) = key%11。输入表长(大于、等于11),输入关键字集合,用二次探测再散列构建哈希表,并查找给定关键字。

输入

测试次数t

每组测试数据格式如下:

哈希表长m、关键字个数n

n个关键字

查找次数k

k个待查关键字

输出

对每组测试数据,输出以下信息:

构造的哈希表信息,数组中没有关键字的位置输出NULL

对k个待查关键字,分别输出:

0或1(0—不成功,1—成功)、比较次数、查找成功的位置(从1开始)

输入样例

1
12 10
22 19 21 8 9 30 33 4 41 13
4
22
15
30
41

输出样例

22 9 13 NULL 4 41 NULL 30 19 8 21 33
1 1 1
0 3
1 3 8
1 6 6

AC代码

#include <iostream>
using namespace std;
int m;//表长
int n;//关键字个数
int k;//待查关键字个数
int arr[1000];
int hash_arr[1000];
int check_arr[1000];
int d[20];
void Creat_hash_arr()
{
	//初始化增量序列
	d[0] = 0;
	for (int i = 1; i < 10; i++)
	{
		d[2 * i - 1] = i * i;
		d[2 * i] = -d[2 * i - 1];
	}
	int j;
	int index;
	for (int i = 0; i < n; i++)
	{
		j = 0;
		index = arr[i] % 11;
		if (hash_arr[index] == 0)
		{
			hash_arr[index] = arr[i];
		}
		else
		{
			while (hash_arr[index] != 0)
			{
				//temp临时保存index的值,如果此次修改index的值还不能把当前关键字加入哈希表,则需要把index恢复为修改前的值
				int temp = index;
                //特殊处理
				if (index + d[j] < 0)
				{
					index = m - index + d[j];
				}
				else
				{
					index = (index + d[j]) % m;
				}
				//要还原
				if (hash_arr[index] != 0)
				{
					index = temp;
					j++;
				}
			}
			hash_arr[index] = arr[i];
		}
	}
	for (int i = 0; i < m; i++)
	{
		if (hash_arr[i] == 0) cout << "NULL";
		else cout << hash_arr[i];
		if (i < m - 1) cout << " ";
	}
	cout << endl;
}
//查找元素
void check()
{
	//初始化增量序列
	d[0] = 0;
	for (int i = 1; i < 10; i++)
	{
		d[2 * i - 1] = i * i;
		d[2 * i] = -d[2 * i - 1];
	}
	int j;
	int check_num;
	int index;
	for (int i = 0; i < k; i++)
	{
		j = 1;
		check_num = 0;
		index = check_arr[i] % 11;
		int temp = index;
		while (1)
		{
			//查找失败
			if (hash_arr[index] == 0)
			{
				check_num++;
				cout << "0 " << check_num << endl;
				break;
			}
			//查找成功
			if (hash_arr[index] == check_arr[i])
			{
				check_num++;
				cout << "1 " << check_num << " " << index + 1 << endl;
				break;
			}
			check_num++;
			//修改index
			index = temp;
			if (index + d[j] < 0)
			{
				index = m - index + d[j];
			}
			else
			{
				index = (index + d[j]) % m;
			}
			j++;
		}
	}
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> m >> n;
		for (int i = 0; i < n; i++)
		{
			cin >> arr[i];
		}
		cin >> k;
		for (int i = 0; i < k; i++)
		{
			cin >> check_arr[i];
		}
		//创建哈希表
		Creat_hash_arr();
		//查找关键字
		check();
	}

	return 0;
}

问题C:DS哈希查找–链地址法(表头插入)

题目描述

给出一个数据序列,建立哈希表,采用求余法作为哈希函数,模数为11,哈希冲突用链地址法和表头插入

如果首次查找失败,就把数据插入到相应的位置中

实现哈希查找功能

输入

第一行输入n,表示有n个数据
第二行输入n个数据,都是自然数且互不相同,数据之间用空格隔开
第三行输入t,表示要查找t个数据
从第四行起,每行输入一个要查找的数据,都是正整数

输出

每行输出对应数据的查找结果

输入样例

6
11 23 39 48 75 62
6
39
52
52
63
63
52

输出样例

6 1
error
8 1
error
8 1
8 2

AC代码

#include <iostream>
using namespace std;
struct Node
{
	int data;
	Node* next;
	Node()
	{
		next = NULL;
	}
};
int n;
int arr[1000];
int check_num;
int check_arr[1000];
Node* hashtable[1000];
//创建哈希表
void Creat_hashtable()
{
	for (int i = 0; i < n; i++)
	{
		int index = arr[i] % 11;
		if (hashtable[index] == NULL)
		{
			hashtable[index] = new Node;
		}
		Node* s = new Node;
		s->data = arr[i];
		s->next = hashtable[index]->next;
		hashtable[index]->next = s;
	}
}
void check()
{
	for (int i = 0; i < check_num; i++)
	{
		int index = check_arr[i] % 11;
		int num = 0;
		if (hashtable[index] == NULL)
		{
			cout << "error" << endl;
			//插入
			if (hashtable[index] == NULL)
			{
				hashtable[index] = new Node;
			}
			Node* s = new Node;
			s->data = check_arr[i];
			s->next = hashtable[index]->next;
			hashtable[index]->next = s;
		}
		else
		{
			Node* p = hashtable[index]->next;
			int flag = 0;
			//查找该关键字是否存在
			while (p!=NULL)
			{
				num++;
				if (p->data == check_arr[i])
				{
					flag = 1;
					break;
				}
				else p = p->next;
			}
			//插入
			if (flag==0)
			{
				cout << "error" << endl;
				if (hashtable[index] == NULL)
				{
					hashtable[index] = new Node;
				}
				Node* s = new Node;
				s->data = check_arr[i];
				s->next = hashtable[index]->next;
				hashtable[index]->next = s;
			}
			else
			{
				cout << index << " " << num << endl;
			}
		}
	}
}
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> arr[i];
	}
	cin >> check_num;
	for (int i = 0; i < check_num; i++)
	{
		cin >> check_arr[i];
	}
	Creat_hashtable();
	check();

	return 0;
}

问题D:DS哈希查找与增补(表尾插入)

题目描述

给出一个数据序列,建立哈希表,采用求余法作为哈希函数,模数为11,哈希冲突用链地址法和表尾插入

如果首次查找失败,就把数据插入到相应的位置中

实现哈希查找与增补功能

输入

第一行输入n,表示有n个数据
第二行输入n个数据,都是自然数且互不相同,数据之间用空格隔开
第三行输入t,表示要查找t个数据
从第四行起,每行输入一个要查找的数据,都是正整数

输出

每行输出对应数据的查找结果,每个结果表示为数据所在位置[0,11)和查找次数,中间用空格分开

输入样例

6
11 23 39 48 75 62
6
39
52
52
63
63
52

输出样例

6 1
error
8 1
error
8 2
8 1

AC代码

#include <iostream>
using namespace std;
struct Node
{
	int data;
	Node* next;
	Node()
	{
		next = NULL;
	}
};
int n;
int arr[1000];
int check_num;
int check_arr[1000];
Node* hashtable[1000];
//创建哈希表
void Creat_hashtable()
{
	for (int i = 0; i < n; i++)
	{
		int index = arr[i] % 11;
		//记得开辟空间
		if (hashtable[index] == NULL)
		{
			hashtable[index] = new Node;
		}
		Node* p = hashtable[index];
        //让p指向尾结点
		while (p->next != NULL)
		{
			p = p->next;
		}
		Node* s = new Node;
		s->data = arr[i];
		p->next = s;
	}
}
void check()
{
	for (int i = 0; i < check_num; i++)
	{
		int index = check_arr[i] % 11;
		int num = 0;
		if (hashtable[index] == NULL)
		{
			cout << "error" << endl;
			//插入
			if (hashtable[index] == NULL)
			{
				hashtable[index] = new Node;
			}
			Node* p = hashtable[index];
			while (p->next != NULL)
			{
				p = p->next;
			}
			Node* s = new Node;
			s->data = check_arr[i];
			p->next = s;
		}
		else
		{
			Node* p = hashtable[index]->next;
			while (1)
			{
				if (p == NULL) break;
				else
				{
					num++;
					if (p->data == check_arr[i]) break;
					else p = p->next;
				}
			}
			//插入
			if (p == NULL)
			{
				cout << "error" << endl;
				if (hashtable[index] == NULL)
				{
					hashtable[index] = new Node;
				}
				Node* p = hashtable[index];
				while (p->next != NULL)
				{
					p = p->next;
				}
				Node* s = new Node;
				s->data = check_arr[i];
				p->next = s;
			}
			else
			{
				cout << index << " " << num << endl;
			}
		}
	}
}
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> arr[i];
	}
	cin >> check_num;
	for (int i = 0; i < check_num; i++)
	{
		cin >> check_arr[i];
	}
	Creat_hashtable();
	check();

	return 0;
}

问题E:DS哈希查找–Trie树

题目描述

Trie树又称单词查找树,是一种树形结构,如下图所示。

image-20250311113928572

它是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。

输入的一组单词,创建Trie树。输入字符串,计算以该字符串为公共前缀的单词数。

(提示:树结点有26个指针,指向单词的下一字母结点。)

输入

测试数据有多组

每组测试数据格式为:

第一行:一行单词,单词全小写字母,且单词不会重复,单词的长度不超过10

第二行:测试公共前缀字符串数量t

后跟t行,每行一个字符串

输出

每组测试数据输出格式为:

第一行:创建的Trie树的层次遍历结果

第2~t+1行:对每行字符串,输出树中以该字符串为公共前缀的单词数。

输入样例

abcd abd bcd efg hig
3
ab
bc
abcde

输出样例

abehbcficddggd
2
1
0

AC代码

#include <iostream>
#include <queue>
using namespace std;
string str;//接收单词
int check_num;//要测试的公共前缀数
int leaf_num;
struct Node
{
	char data;
	Node* next[30];
	Node()
	{
		for (int i = 0; i < 30; i++)
		{
			next[i] = NULL;
		}
	}
};
int get_index(char data)
{
	return (int)data - 96;
}
//层序遍历
void LevelOrder(Node*& root)
{
	queue<Node*> q;
	q.push(root);
	while (!q.empty())
	{
		Node* temp = q.front();
		q.pop();
		if (temp != root)
		{
			cout << temp->data;
		}
		for (int i = 1; i <= 26; i++)
		{
			if (temp->next[i] != NULL)
			{
				q.push(temp->next[i]);
			}
		}
	}
	cout << endl;
}
//求叶子结点数
void get_LeafNum(Node*& t)
{
	if (t == NULL) return;
	int flag = 0;
	for (int i = 1; i <= 26; i++)
	{
		if (t->next[i] != NULL)
		{
			flag = 1;
			break;
		}
	}
	if (flag == 0)
	{
		leaf_num++;
	}
	else
	{
		for (int i = 1; i <= 26; i++)
		{
			get_LeafNum(t->next[i]);
		}
	}
}
//创建树
void CreatTree(Node*& root)
{
	root = new Node();
	while (cin >> str)
	{
		//如果输入的是数字就退出循环
		if (str[0] >= '0' && str[0] <= '9')
		{
			check_num = str[0] - '0';
			break;
		}
		//如果输入的不是数字就加入到tree中
		int len = str.size();
		Node* temp = root;
		for (int i = 0; i < len; i++)
		{
			int index = get_index(str[i]);
			//需要把该字母加入到树中
			if (temp->next[index] == NULL)
			{
				Node* s = new Node;
				s->data = str[i];
				temp->next[index] = s;
			}
			temp = temp->next[index];
		}
	}
	//调用层序遍历
	LevelOrder(root);
}
//查找公共前缀数
void check(Node*& root)
{
	for (int i = 0; i < check_num; i++)
	{
		int flag = 1;
		string s = "";
		cin >> s;
		int len = s.size();
		Node* temp = root;
		//得到要查找的公共前缀的最后一个字母的指针,如s="ab",则经过下面循环后temp=该单词上b的指针
		for (int i = 0; i < len; i++)
		{
			int index = get_index(s[i]);
			if (temp->next[index] == NULL)
			{
				flag = 0;
				break;
			}
			else
			{
				temp = temp->next[index];
			}
		}
		if (!flag)
		{
			cout << "0" << endl;
		}
		//查找以temp为根结点的树有多少个叶子结点,即为所求
		else
		{
			leaf_num = 0;
			get_LeafNum(temp);
			cout << leaf_num << endl;
		}
	}
}
int main()
{
	Node* root = NULL;
	CreatTree(root);
	check(root);

	return 0;
}

问题F:逆散列问题

题目描述

给定长度为 N 的散列表,处理整数最常用的散列映射是 H(x)=x%N。如果我们决定用线性探测解决冲突问题,则给定一个顺序输入的整数序列后,我们可以很容易得到这些整数在散列表中的分布。例如我们将 1、2、3 顺序插入长度为 3 的散列表HT[]后,将得到HT[0]=3,HT[1]=1,HT[2]=2的结果。

但是现在要求解决的是“逆散列问题”,即给定整数在散列表中的分布,问这些整数是按什么顺序插入的?

输入

输入的第一行是正整数 N(≤1000),为散列表的长度。第二行给出了 N 个整数,其间用空格分隔,每个整数在序列中的位置(第一个数位置为0)即是其在散列表中的位置,其中负数表示表中该位置没有元素。题目保证表中的非负整数是各不相同的。

输出

按照插入的顺序输出这些整数,其间用空格分隔,行首尾不能有多余的空格。注意:对应同一种分布结果,插入顺序有可能不唯一。例如按照顺序 3、2、1 插入长度为 3 的散列表,我们会得到跟 1、2、3 顺序插入一样的结果。在此规定:当前的插入有多种选择时,必须选择最小的数字,这样就保证了最终输出结果的唯一性。

输入样例

11
33 1 13 12 34 38 27 22 32 -1 21

输出样例

1 13 12 21 33 34 38 27 22 32

AC代码

/*
思路:
①将输入的数值序列从小到大排序
②新建哈希表,每次都从未填入的数值中选取最小的数值,判断它应填入哈希表中的位置,如果与给定的位置相同,则输出该数字、标记为已访问并将其填入哈希表
*/
#include <iostream>
using namespace std;
struct Node
{
	int data;
	int flag;
	Node()
	{
		flag = -1;
	}
};
int n;//表长
Node hashtable[1005];//给定的哈希表,此时flag表示的是数值在哈希表中的下标
Node arr[1005];//从小到大重新排序,此时flag表示的是是否已经被访问(-1表示未被访问,1表示已经被访问)
Node newhashtable[1005];//此时flag表示的是是否已经被访问(-1表示未被访问,1表示已经被访问)
//从小到大排序
void mysort()
{
	for (int i = 0; i < n - 1; i++)
	{
		for (int j =0; j < n - i - 1; j++)
		{
			if (arr[j].data > arr[j + 1].data)
			{
				swap(arr[j], arr[j + 1]);
			}
		}
	}
}
//得到指定数值在哈希表中的下标
int get_hashtable_index(int data)
{
	for (int i = 0; i < n; i++)
	{
		if (hashtable[i].data == data)
		{
			return hashtable[i].flag;
		}
	}
}
//得到指定数值应填入哈希表的下标
int get_newhashtable_index(int data)
{
	int index = data % n;
	while (1)
	{
		if (newhashtable[index].flag == -1)
		{
			return index;
		}
		index = (index + 1) % 11;
	}
}
void func()
{
	mysort();
	//num为哈希表中实际表长
	int num = n;
	for (int i = 0; i < n; i++)
	{
		if (arr[i].data < 0)
		{
			arr[i].flag = 1;
			num--;
		}
	}
	while (num--)
	{
		int i = 0;
		while (1)
		{
			if (arr[i].flag == -1)
			{
				if (get_newhashtable_index(arr[i].data) == get_hashtable_index(arr[i].data))
				{
					cout<<arr[i].data;
					if (num != 0) cout << " ";
					arr[i].flag = 1;
					newhashtable[get_newhashtable_index(arr[i].data)].data = arr[i].data;
					newhashtable[get_newhashtable_index(arr[i].data)].flag = 1;
					break;
				}
			}
			i++;
		}
	}
	cout << endl;
}
int main()
{
	//输入数据
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> hashtable[i].data;
		hashtable[i].flag = i;
		arr[i].data = hashtable[i].data;
	}
	func();

	return 0;
}

< n; i++)
{
if (hashtable[i].data == data)
{
return hashtable[i].flag;
}
}
}
//得到指定数值应填入哈希表的下标
int get_newhashtable_index(int data)
{
int index = data % n;
while (1)
{
if (newhashtable[index].flag == -1)
{
return index;
}
index = (index + 1) % 11;
}
}
void func()
{
mysort();
//num为哈希表中实际表长
int num = n;
for (int i = 0; i < n; i++)
{
if (arr[i].data < 0)
{
arr[i].flag = 1;
num–;
}
}
while (num–)
{
int i = 0;
while (1)
{
if (arr[i].flag == -1)
{
if (get_newhashtable_index(arr[i].data) == get_hashtable_index(arr[i].data))
{
cout<<arr[i].data;
if (num != 0) cout << " ";
arr[i].flag = 1;
newhashtable[get_newhashtable_index(arr[i].data)].data = arr[i].data;
newhashtable[get_newhashtable_index(arr[i].data)].flag = 1;
break;
}
}
i++;
}
}
cout << endl;
}
int main()
{
//输入数据
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> hashtable[i].data;
hashtable[i].flag = i;
arr[i].data = hashtable[i].data;
}
func();

return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值