题目大意
给定一个单词表“dictionary3000.txt”,单词表已经排好序,通过指定的方式,从下面四种方法查找出单词,输出找到与否并给出查找次数。
- 在单词表中以顺序查找方式查找,因为单词表已排好序,遇到相同的或第一个比待查找的单词大的单词,就要终止查找;
- 在单词表中以折半查找方式查找;
- 在单词表中通过索引表来获取单词查找范围,并在该查找范围中以折半方式查找。索引表构建方式为:以26个英文字母为头字母的单词在字典中的起始位置和单词个数来构建索引表,如:
字母 | 起始位置 | 单词个数 |
---|---|---|
a | 0 | 248 |
b | 248 | 167 |
… | … | … |
该索引表表明以字母a开头的单词在单词表中的开始下标位置为0,单词个数为248。
- 按下面给定的hash函数为字典中单词构造一个hash表,hash冲突时按字典序依次存放单词。hash查找遇到冲突时,采用链地址法处理,在冲突链表中找到或未找到(遇到第一个比待查找的单词大的单词或链表结束)便结束查找。
/* compute hash value for string */
#define NHASH 3001
#define MULT 37
unsigned int hash(char *str)
{
unsigned int h=0;
char *p;
for(p=str; *p!='\0'; p++)
h = MULT*h + *p;
return h % NHASH;
}
提示:hash表可以构建成指针数组,hash冲突的单词形成一有序链表。
单词表 ,提取码:aocp
【样例输入】
wins 1
wins 2
wins 3
wins 4
yes 1
yes 2
yes 3
yes 4
【样例输出】
0 3314
0 12
0 7
0 2
1 3357
1 10
1 4
1 1
分析
这道题主要是实现四种查找方式,然后根据输入的方式查找即可。直接查找(略)。折半查找利用二分原理,在一个有序空间内进行迭代查找。hash查找的关键是建立hash表。
创建Hash表
建立一个Hash表需要指定Hash块大小以及解决冲突的方法。在本题中,先调用函数计算字符串Hash值,如果这个值指向的地址为空,说明之前还没有单词存储到这个地方,那么我们就可以直接将这个单词放到这个位置。如果不是空,说明发生了冲突,在这个题中,使用建立链表解决。发生冲突的时候,依次向后查找,如果找到字典序的位置或者尾部,就执行插入操作。
代码
#include <bits/stdc++.h>
using namespace std;
#define NHASH 3001
#define MULT 37
typedef struct NODE
{
char word[25];
NODE *next;
} Node;
void init(vector<string> &dic, map<char, int> &m, vector<Node *> &node)
{
ifstream *ifs = new ifstream("dictionary3000.txt", ios::in);
string tmp;
if (!ifs->is_open())
exit(-1);
while (!ifs->eof())
{
(*ifs) >> tmp;
//getline(*ifs, tmp) 错误
m[tmp[0]]++;
dic.push_back(tmp);
}
ifs->close();
node.reserve(NHASH);
for (unsigned i = 0; i < NHASH; i++)
node[i] = nullptr;
}
unsigned hashf(const char *str)
{
unsigned h = 0;
for (unsigned i = 0; i < strlen(str); i++)
h = MULT * h + str[i];
return h % NHASH;
}
int bin_search(int from, int to, vector<string> &dic, char word[], bool &have)
{
int left = from, right = to, mid, res = 0;
while (left <= right)
{
res++;
mid = (left + right) >> 1;
if (strcmp(dic[mid].c_str(), word) == 0)
{
have = true;
return res;
}
else if (strcmp(dic[mid].c_str(), word) > 0)
right = mid - 1;
else
left = mid + 1;
}
return res;
}
int liner_search(vector<string> &dic, char word[], bool &have)
{
unsigned n = dic.size();
for (unsigned i = 0; i < n; i++)
{
if (dic[i] >= word)
{
if (strcmp(dic[i].c_str(), word) == 0)
have = true;
return i + 1;
}
}
return n;
}
void construct_hash_table(vector<string> &dic, vector<Node *> &node)
{
unsigned hash_val;
for (auto s : dic)
{
hash_val = hashf(s.c_str());
Node *tmp = new Node;
if (tmp == nullptr)
exit(-1);
strcpy(tmp->word, s.c_str());
tmp->next = nullptr;
if (node[hash_val] == nullptr)
node[hash_val] = tmp;
else
{
Node *cur = node[hash_val];
while (cur->next != nullptr && strcmp(tmp->word, cur->next->word) > 0)
cur = cur->next;
tmp->next = cur->next;
cur->next = tmp;
}
}
}
int hash_search(vector<Node *> &hash_table, char word[], bool &have)
{
unsigned hash_val = hashf(word);
int res = 0;
Node *cur = hash_table[hash_val];
while (cur != nullptr)
{
res++;
if (strcmp(cur->word, word) == 0)
{
have = true;
return res;
}
cur = cur->next;
}
cur = nullptr;
return res;
}
void delp(Node *p)
{
if (p->next != nullptr)
delp(p->next);
delete p;
p = nullptr;
}
void del(vector<Node *> &hash_table)
{
for (Node *p : hash_table)
delp(p);
hash_table.clear();
}
int main(int argc, char *argv[])
{
vector<string> dic;
vector<Node *> hash_table;
map<char, int> num;
char word[25] = {0};
short mode;
bool have = false;
int res;
init(dic, num, hash_table);
construct_hash_table(dic, hash_table);
cin >> word >> mode;
switch (mode)
{
case 1:
res = liner_search(dic, word, have);
cout << have << " " << res << endl;
break;
case 2:
res = bin_search(0, dic.size() - 1, dic, word, have);
cout << have << " " << res << endl;
break;
case 3:
{
int from = 0;
for (pair<char, int> p : num)
{
if (p.first == word[0])
break;
from += p.second;
}
res = bin_search(from, from + num[word[0]] - 1, dic, word, have);
cout << have << " " << res << endl;
break;
}
case 4:
res = hash_search(hash_table, word, have);
cout << have << " " << res << endl;
break;
default:
exit(-1);
}
return 0;
}