【id:134】【15分】D. DS哈希查找--Trie树

题目描述

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

它是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。

它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。

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

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

输入

测试数据有多组

每组测试数据格式为:

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

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

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

输出

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

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

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

输入输出样例

输入样例1 <-复制
abcd abd bcd efg hig
3
ab
bc
abcde

输出样例1
abehbcficddggd
2
1
0

解题思路

这道题说简单点就是建了一个目录树,按照输入输出样例画个图就很容易明白了。

 在这个树中,你可以找到输入的所有样例,即abcd abd bcd efg hig。

层次遍历就是一层一层的往下遍历,abeh-bcfi-cddgg-d,即输出样例的abehbcficddggd。

首先就是建立目录树,然后bfs搜索输出层次遍历结果。

最后dfs查找前缀出现次数,就是以某个节点为根节点,搜索有多少个叶子结点。

例如dfs查找前缀ab出现次数,相当于以第一分支的b为根节点,寻找叶子结点,即abcd的d、abd的d,叶子结点有两个,故出现次数为2。

理清了思路,实现就很简单了。

AC代码

#include<iostream>
#include<string>
#include<queue>
using namespace std;

// 定义前缀树的节点结构
struct node
{
    char fu;                // 当前节点的字符
    int shu = 0;            // 当前节点字符的出现次数
    node* next[26] = { NULL };  // 指向下一个节点的指针数组,包含 26 个小写字母
};

node* root;  // 根节点指针

// 创建前缀树
void create(string str)
{
    int len = size(str);
    int i, k;
    node* p = root;
    for (i = 0; i < len; i++)
    {
        k = str[i] - 'a';  // 计算当前字符对应的索引
        if (p->next[k] == NULL)
        {
            node* s = new node;
            s->fu = str[i];
            p->next[k] = s;
        }
        p->next[k]->shu++;
        p = p->next[k];
    }
}

// 广度优先搜索遍历前缀树
void bfs(node* root)
{
    node* p = root;
    queue<node*>q;
    int i;
    for (i = 0; i < 26; i++)
    {
        if (p->next[i] != NULL)
            q.push(p->next[i]);
    }
    while (!q.empty())
    {
        p = q.front();
        q.pop();
        cout << p->fu; // 输出当前节点的字符

        for (i = 0; i < 26; i++)
        {
            if (p->next[i] != NULL)
                q.push(p->next[i]);
        }

    }
    cout << endl;
}

// 深度优先搜索遍历前缀树
void dfs(string str)
{
    int len = size(str);
    int i, k;
    node* p = root;
    for (i = 0; i < len; i++)
    {
        k = str[i] - 'a';  // 计算当前字符对应的索引
        p = p->next[k];
        if (p == NULL)
        {
            cout << "0" << endl;  // 如果遍历到空节点,说明前缀不存在,输出 0
            return;
        }
        if (i == len - 1)
        {
            cout << p->shu << endl;  // 输出当前节点的出现次数
            return;
        }

    }
}

int main()
{
    string str;
    root = new node;
    int t;
    while (1)
    {
        cin >> str;
        if (str[0] >= '0' && str[0] <= '9')
        {
            t = str[0] - '0';
            break;
        }
        create(str);  // 构建前缀树
    }
    bfs(root);  // 广度优先搜索输出层次遍历结果
    while (t--)
    {
        cin >> str;
        dfs(str);  // 深度优先搜索,输出前缀的出现次数
    }
    return 0;
}

(by 归忆) 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

归忆_AC

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

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

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

打赏作者

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

抵扣说明:

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

余额充值