TIRE 前缀树(字典树)

在计算机科学中,前缀树又称字典树(tire—源自于retrieval),是一种有序树。它用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。
举例说明:一个保存了8个键的 tire 树结构,“a”、 “ab”、“abc”、“to”、“tea”、“ten”、“ted”、“B”,这8个键所形成的字典树如下图所示:
在这里插入图片描述
前缀树的3个基本性质:
1、根节点不包含字符,除根节点外每一个节点都只包含一个字符。
2、从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
3、每个节点的所有子节点包含的字符都不相同。

tire 树的应用:
常用于搜索提示。如当输入一个网址,可以自动搜索出可能的选择。当没有完全匹配的搜索结果,可以返回前缀最相似的可能。

c++ 实现 tire 树结构:
1、树结构的定义

const int MaxBranchNum = 26;
class TrieNode{
public:
    string word;
    int path;
    int End; 
    TrieNode* nexts[MaxBranchNum];
    TrieNode()
    {
        word = "";
        path = 0;
        End = 0;
        memset(nexts,NULL,sizeof(TrieNode*) * MaxBranchNum);
    }
}

其中,MaxBranchNum 表示 trie 树的最大分支数量(这里设置为26,如果有需要可以扩展),path 表示以当前单词结尾的单词数量,用以统计该字符串作为前缀的字符串的个数;End 表示该节点之前的字符串为前缀的单词数量。

2、trie 树的创建

class TrieTree{
private:
    TrieNode *root;
public:
    TrieTree();
    void insert(string str);
    int search(string str);
    void Delete(string str);
    void destory(TrieNode* root);
    void printPre(string str);
    void Print(TrieNode* root);
    int prefixNumbers(string str);
};
TrieTree::TrieTree()
{
    root = new TrieNode();
}

其中,void insert(string str) 该函数为插入字符串 str;
int search(string str) 该函数为查询字符串str是否出现过,并返回作为前缀几次;
void Delete(string str) 该函数为删除字符串str;
void destory(TrieNode* root) 该函数为销毁 trie 树;
void printPre(string str) 该函数为打印以str作为前缀的单词;
void Print(TrieNode* root) 该函数为按照字典顺序输出以root为根的所有单词;
int prefixNumbers(string str) 该函数为返回以str为前缀的单词的个数。每个函数具体功能实现如下:

  • 插入字符串 str
void TrieTree::insert(string str)
{
    if(str == "")
        return ;
    char buf[str.size()];
    strcpy(buf, str.c_str());
    TrieNode* node = root;
    int index = 0;
    for(int i=0; i<strlen(buf); i++)
    {
        index = buf[i] - 'a';
        if(node->nexts[index] == nullptr)
        {
            node->nexts[index] = new TrieNode();
        }
        node = node->nexts[index];
        node->path++;//有一条路径划过这个节点
    }
    node->End++;
    node->word = str;
}
  • 查询字符串str是否出现过
int TrieTree::search(string str)
{
    if(str == "")
        return 0;
    char buf[str.size()];
    strcpy(buf, str.c_str());
    TrieNode* node = root;
    int index = 0;
    for(int i=0;i<strlen(buf);i++)
    {
        index = buf[i] - 'a';
        if(node->nexts[index] == nullptr)
        {
            return 0;
        }
        node = node->nexts[index];
    }
    if(node != nullptr)
    {
        return node->End;
    }else
    {
        return 0;
    }
}
  • 删除字符串str
void TrieTree::Delete(string str)
{
    if(str == "")
        return ;
    char buf[str.size()];
    strcpy(buf, str.c_str());
    TrieNode* node = root;
    TrieNode* tmp;
    int index = 0;
    for(int i = 0 ; i<str.size();i++)
    {
        index = buf[i] - 'a';
        tmp = node->nexts[index];
        if(--node->nexts[index]->path == 0)
        {
            delete node->nexts[index];
        }
        node = tmp;
    }
    node->End--;
}
  • 销毁 trie 树
void TrieTree::destory(TrieNode* root)
{
    if(root == nullptr)
        return ;
    for(int i=0;i<MaxBranchNum;i++)
    {
        destory(root->nexts[i]);
    }
    delete root;
    root = nullptr;
}
  • 打印以str作为前缀的单词
void TrieTree::printPre(string str)
{
    if(str == "")
        return ;
    char buf[str.size()];
    strcpy(buf, str.c_str());
    TrieNode* node = root;
    int index = 0;
    for(int i=0;i<strlen(buf);i++)
    {
        index = buf[i] - 'a';
        if(node->nexts[index] == nullptr)
        {
            return ;
        }
        node = node->nexts[index];
    }
    Print(node);
}
  • 按照字典顺序输出以root为根的所有单词
void TrieTree::Print(TrieNode* node)
{
    if(node == nullptr)
        return ;
    if(node->word != "")
    {
        cout<<node->word<<" "<<node->path<<endl;
    }
    for(int i = 0;i<MaxBranchNum;i++)
    {
        Print(node->nexts[i]);
    }
}
  • 返回以str为前缀的单词的个数
int TrieTree::prefixNumbers(string str)
{
    if(str == "")
        return 0;
    char buf[str.size()];
    strcpy(buf, str.c_str());
    TrieNode* node = root;
    int index = 0;
    for(int i=0;i<strlen(buf);i++)
    {
        index = buf[i] - 'a';
        if(node->nexts[index] == nullptr)
        {
            return 0;
        }
        node = node->nexts[index];
    }
    return node->path;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值