深圳大学数据结构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树又称单词查找树,是一种树形结构,如下图所示。
它是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。
输入的一组单词,创建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;
}