题目一: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
代码示例:
#include<iostream>
using namespace std;int swapCnt;class HashTable {
private:int* HT;int maxSize;int current;
public:HashTable(int n) {maxSize = n;HT = new int[maxSize];fill(HT, HT + maxSize, -1);current = 0;}~HashTable() { delete[] HT; }int H(int key);int HashSearch(int key);void HashInsert(int key);int getHT(int i);
};int HashTable::H(int key) { return key % 11; }int HashTable::getHT(int i) {return HT[i];
}
void HashTable::HashInsert(int key) {int d, j;d = H(key);if (HT[d] != -1) {j = d;d = (d + 1) % maxSize;while (d != j && HT[d] != -1) d = (d + 1) % maxSize;}if (HT[d] == -1) {HT[d] = key;current++;}
}int HashTable::HashSearch(int key) {int d = H(key);for (int i = 0; i < maxSize; i++) {swapCnt++;if (HT[d] == key) return d;if (HT[d] == -1) return -1;d = (d + 1) % maxSize;}return -1;
}int main() {int t;cin >> t;while (t--) {int m, n;cin >> m >> n;HashTable ht(m);for (int i = 0; i < n; i++) {int keyNumber;cin >> keyNumber;ht.HashInsert(keyNumber);}for (int i = 0; i < m; i++) {if (ht.getHT(i) != -1) cout << ht.getHT(i) << "";else cout << "NULL";if (i != m - 1) cout << " ";}cout << endl;int k;cin >> k;for (int i = 0; i < k; i++) {int keyNumber;swapCnt = 0;cin >> keyNumber;int result = ht.HashSearch(keyNumber);if (result != -1) {cout << "1 " << swapCnt << " " << result + 1 << endl;}else cout << "0 " << swapCnt << endl;}}
}
题目二: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
代码示例:
#include<iostream>
#include<iomanip>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;int swapCnt;class HashTable {
private:int* HT;int maxSize;int current;
public:HashTable(int n) {maxSize = n;HT = new int[maxSize];fill(HT, HT + maxSize, -1);current = 0;}~HashTable() { delete[] HT; }int H(int key);void HashSearch(int key);void HashInsert(int key);int getHT(int i);
};int HashTable::H(int key) { return key % 11; }int HashTable::getHT(int i) { return HT[i]; }void HashTable::HashInsert(int key) {int d, j;int sum = 0, count = 0;d = H(key);if (HT[d] != -1) {while (1) {int pos;count++;sum = (count + 1) / 2;if (count % 2 == 1) pos = (d + sum * sum) % maxSize;else pos = (d - sum * sum) % maxSize;while (pos < 0) pos += maxSize;if (HT[pos] == -1) {HT[pos] = key;break;}}}if (HT[d] == -1) {HT[d] = key;current++;}
}void HashTable::HashSearch(int key) {int sum = 0, flag = 0, c;int d = H(key);while (1) {flag++;if (flag >= 2 && flag % 2 == 0) sum++;if (flag % 2 == 0) c = 1;else c = -1;int p = (d + c * sum * sum) % maxSize;if (HT[p] == key) {cout << "1 " << flag << " " << p + 1 << endl;break;}else if (HT[p] == -1) {cout << "0 " << flag << endl;break;}}
}int main() {int t;cin >> t;while (t--) {int m, n;cin >> m >> n;HashTable ht(m);for (int i = 0; i < n; i++) {int keyNumber;cin >> keyNumber;ht.HashInsert(keyNumber);}for (int i = 0; i < m; i++) {if (ht.getHT(i) != -1) cout << ht.getHT(i) << "";else cout << "NULL";if (i != m - 1) cout << " ";}cout << endl;int k;cin >> k;for (int i = 0; i < k; i++) {int keyNumber;swapCnt = 0;cin >> keyNumber;ht.HashSearch(keyNumber);}}
}
题目三: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
代码示例:
#include<iostream>
using namespace std;int H(int key) { return key % 11; }struct Node {
public:int key;Node* next;
};class HashTable {
public:Node* HT[100];HashTable(int m) { for (int i = 0; i < m; i++) HT[i] = NULL; }void headInsert(Node* arr, int i) {if (HT[i] == NULL) HT[i] = arr;else {arr->next = HT[i];HT[i] = arr;}}void HashInsert(int key) {int index = H(key);Node* p = new Node;p->key = key;p->next = NULL;headInsert(p, index);}int HashSerach(int key) {int i = H(key);int sum = 0;Node* p = HT[i];while (1) {sum++;if (p == NULL) return 0;else {if (p->key == key) return sum;p = p->next;}}}
};
int main() {int t, n, key;cin >> n;HashTable ht(11);for (int i = 0; i < n; i++) {cin >> key;ht.HashInsert(key);}cin >> t;while (t--) {cin >> key;int sum = ht.HashSerach(key);if (sum == 0) {cout << "error" << endl;Node* p = new Node;p->key = key;p->next = NULL;ht.headInsert(p, H(key));}else cout << H(key) << " " << sum << endl;}return 0;
}
题目四: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
代码示例:
#include<iostream>
using namespace std;int H(int key) {return key % 11;
}struct Node {
public:int key;Node* next;
};class HashTable {
public:Node* HT[100];HashTable(int m) {for (int i = 0; i < m; i++) HT[i] = NULL;}void headInsert(Node* arr, int i) {if (HT[i] == NULL) HT[i] = arr;else {arr->next = HT[i];HT[i] = arr;}}void tailInsert(Node* arr, int idx) {Node* p;p = HT[idx];if (p == NULL) {HT[idx] = arr;return;}while (1) {if (p->next == NULL) {p->next = arr;return;}p = p->next;}}void HashInsert(int key) {int index = H(key);Node* p = new Node;p->key = key;p->next = NULL;tailInsert(p, index);}int HashSerach(int key) {int index = H(key);int sum = 0;Node* p = HT[index];while (1) {sum++;if (p == NULL) return 0;else {if (p->key == key) return sum;p = p->next;}}}
};
int main() {int t, n, key;cin >> n;HashTable ht(11);for (int i = 0; i < n; i++) {cin >> key;ht.HashInsert(key);}cin >> t;while (t--) {cin >> key;int sum = ht.HashSerach(key);if (sum == 0) {cout << "error" << endl;Node* p = new Node;p->key = key;p->next = NULL;ht.tailInsert(p, H(key));}else cout << H(key) << " " << sum << endl;}return 0;
}
题目五: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
代码示例:
#include<iostream>
#include<string>
#include<queue>
using namespace std;
int sum;
class Trie {
public:bool flag = false;Trie* next[26] = { NULL };void insertTrie(string str) {Trie* node = this;for (int i = 0; i < str.length(); i++) {char c = str[i];if (node->next[c - 'a'] == NULL) {node->next[c - 'a'] = new Trie();}node = node->next[c - 'a'];}node->flag = true;}int searchStart(string str) {Trie* node = this;sum = 0;for (int i = 0; i < str.length(); i++) {char c = str[i];if (node->next[c - 'a'] == NULL) return 0;node = node->next[c - 'a'];}DFS(node);return sum;}void DFS(Trie* Node) {Trie* tr = new Trie();tr = Node;int temp = 0;for (int i = 0; i < 26; i++) {if (tr->next[i]){DFS(tr->next[i]);temp = 1;}}if (temp == 0) {sum++;return;}}};void BFS(Trie* Tree) {queue<Trie*>q;q.push(Tree);while (!q.empty()) {Trie* t = q.front();q.pop();for (int i = 0; i < 26; i++) {if (t->next[i]) {cout << char('a' + i);q.push(t->next[i]);}}}}int main() {string str;Trie* tree = new Trie();int t;while (1) {cin >> str;if (str[0] >= '0' && str[0] <= '9') {t = str[0] - '0';break;}tree->insertTrie(str);}BFS(tree);cout << endl;while (t--) { cin >> str;cout << tree->searchStart(str) << endl;}
}
题目六:DS哈希查找 -- 逆散列问题
题目描述:
给定长度为 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
代码示例:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int m;
int main()
{cin >> m;vector<int>v(m);vector<int>temp;for (int i = 0; i < m; i++){cin >> v[i];if (v[i] != -1)temp.push_back(v[i]);}sort(temp.begin(), temp.end());int length = temp.size();vector<bool>finding_value(length, 0);vector<bool>hashtable(m, 0);int num = 0, index = 0;//length 为插入数据长度while (num != length){for (int i = 0; i < length; i++){if (!finding_value[i]) //如果这个值没有找到位置{int posi = temp[i] % m;//temp[i]的线性探测初始位置if (v[posi] == temp[i]){printf("%d ", temp[i]);finding_value[i] = 1;hashtable[posi] = 1;num++;break;}else{for (int t = 0; t < m; t++){int new_posi = (posi + t) % m;if (hashtable[new_posi])continue;if (!hashtable[new_posi] && v[new_posi] != temp[i])break;finding_value[i] = hashtable[new_posi] = 1;printf("%d ", temp[i]);num++;break;}}}}}
}