前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >字典树原理与实现

字典树原理与实现

作者头像
yhlin
发布2023-02-27 16:57:22
5430
发布2023-02-27 16:57:22
举报
文章被收录于专栏:yhlin's blog

Trie 树


  据不完全统计,世界上现存英语单词的数量为 17 万到 100 万不等。假设现在要你写一个词典 APP,要求能够快速检索、删除、添加单词,。显然你很容易想到两种方案:

  1. 将所有单词按字典序排列,在按二分搜索来查询。
  2. 奖励首字母索引表,在各索引项表内按字典序排序单词,再在当中按二分搜索查询。 但无疑上述方案的要求略高,需要大量的连续空间来存储数据,而且不方便添加删除操作。

  这时 Trie 树便发挥作用了,我们可以用 Trie 树来存储单词数据,树结构不需要大量连续的存储空间而且查询、添加结点、删除结点的操作的时间复杂度很小为 O(\log_{2}{N})

举个例子:

  假设存储

[{"code","cook","five","file","fat"}]
字典树原理与实现
字典树原理与实现

Trie 树的实现


结点结构:


字典树原理与实现
字典树原理与实现
代码语言:javascript
复制
struct TrieNode {
    char nodeChar;// 该结点表示的字符
    int freq;// 出现的频率
    bool isWord; // 单词结点结束标记
    vector<TrieNode*> childNode;// 先一个结点的指针
    TrieNode()// 初始化结点
    {
        freq = 0;
        isWord = false;
        childNode = vector<TrieNode*>(26,NULL);
    }
};

树的大致结构:
字典树原理与实现
字典树原理与实现
  • 根节点的 nodeChar 不存储字符,其字符表示位于指针数组中,指针数组的某元素不空则表示存在以其为首字符的单词。

添加操作


代码语言:javascript
复制
// 添加操作
void addWord(TrieNode* root, string word, int k)
{if(k >= word.size()) return;

    // 将 word 的首字母插入到 root 的哪一个分叉中
    int index = word[k] - 'a';
    // 若该树为空,插入新结点
    if(root->childNode[index] == NULL)
    {root->childNode[index] = new TrieNode();
        root->childNode[index]->nodeChar = word[0];
        if(k == word.size()-1)
        {
            // 终端结点标记
            root->childNode[index]->isWord = true;
        }
        addWord(root->childNode[index], word, k+1);
    }
    else
    {if(k == word.size()-1)
        {root->childNode[index]->isWord = true;
        }
        // 递归添加结点
        addWord(root->childNode[index], word, k+1);
    }
}

查询操作


代码语言:javascript
复制
// 查询操作
bool searchWord(TrieNode* root, string word)
{
    TrieNode* p = root;
    int i;
    for(i = 0;i < word.size() && p != NULL;i++)
    {int index = word[i] - 'a';
        if(p->childNode[index] == NULL)
        {return false;}
        else
        {if(i == word.size()-1)
                p->childNode[index]->freq++;
            p = p->childNode[index];
        }
    }
    if(i == word.size() && p->isWord)
        return true;
    else return false;
}

删除操作


删除操作比较复杂,分三种情况:

删除整个单词(该单词的尾结点为叶子节点,且该单词独占一条路径)

删除前缀词(该单词的尾结点非叶子节点)

删除分支单词(该单词的尾结点为叶子节点但存在于其他单词共用的路径)

代码语言:javascript
复制
bool isLeave(TrieNode* node)
{for(int i = 0;i < 26;i++)
{if(node->childNode[i] != NULL)
    {return false;}
}
return true;
}
void deleteWord(TrieNode* root, string word, int k)
{if(k >= word.size()) return;
cout << "delete into " << word[k] << endl;
int index = word[k] - 'a';
if(root->childNode[index] == NULL) return;
else
{
    cout << 'd' << endl;
    deleteWord(root->childNode[index], word, k+1);
    if(isLeave(root) && !root->isWord)
    {
        cout << "dc" << endl;
        delete root;
        root = NULL;
    }
    else if(k == word.size()-1 && !isLeave(root))
    {
        root->isWord = false;
        cout << "dd" << endl;
    }
}
}
bool DeleteKey(TrieNode *root, string word)
{if(searchWord(root, word))
{deleteWord(root, word, 0);
    return true;
}
return false;
}
代码语言:javascript
复制
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-01-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Trie 树
    • 举个例子:
    • Trie 树的实现
      • 结点结构:
        • 树的大致结构:
      • 添加操作
        • 查询操作
          • 删除操作
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档