【数据结构与算法】单词查找题解(直接查找 & 折半查找 & 有索引表的折半查找 & Hash查找)

题目大意

给定一个单词表“dictionary3000.txt”,单词表已经排好序,通过指定的方式,从下面四种方法查找出单词,输出找到与否并给出查找次数。

  1. 在单词表中以顺序查找方式查找,因为单词表已排好序,遇到相同的或第一个比待查找的单词大的单词,就要终止查找;
  2. 在单词表中以折半查找方式查找;
  3. 在单词表中通过索引表来获取单词查找范围,并在该查找范围中以折半方式查找。索引表构建方式为:以26个英文字母为头字母的单词在字典中的起始位置和单词个数来构建索引表,如:
字母起始位置单词个数
a0248
b248167

该索引表表明以字母a开头的单词在单词表中的开始下标位置为0,单词个数为248。

  1. 按下面给定的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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A91A981E

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值