经典前缀树(字典树)的实现c++

如果对你有帮助,可以给卑微的博主留个赞、关注、收藏   (不是) 

(骗一下数据,说不定以后面试就过了,拜谢)

关于前缀树的内容最好看看视频了解逻辑结构,然后代码实现一下

前缀树是一种树形数据结构,广泛用于字符串查找,思想上类似哈希。在字符串查找上有非常好的效果,但是消耗空间较大,下面给出前缀树的c++实现

#ifndef TRIE_H_INCLUDED
#define TRIE_H_INCLUDED

#include<string>
using namespace std;

//假设字符串都是小写字母

typedef struct TrieNode
    {   int pass = 0;     //有几个字符串经过此结点(前缀包含这个字符的字符串数量)

        int end = 0;      //以此结点结束的字符串的数量,如果不允许重复插入,可以改成bool

        TrieNode* next[26]{nullptr};     //26个空位,准备挂下一结点a-z ,没有时置为nullptr

    }TrieNode ;     //前缀树结点定义



//前缀树
class Trie {
public:

    TrieNode *root = nullptr;   //根节点



    Trie() {
        root = new TrieNode();    //构造函数初始化root
    }

    ~Trie() {
        deletememory(root);      //析构释放空间
    }


    /* 插入字符串 */
    void insert(string word) {

        TrieNode *temp = root;
        temp->pass++;        
        //根节点的pass代表树上有多少字符串以空字符串为前缀,也就是字符串总数

        for(unsigned int i = 0 ;i<word.size() ;i++)   //遍历字符串的每个字符
        {
            if(temp->next[word[i]-'a'] == nullptr)   //如果先前没有字符串经过此结点
                temp->next[word[i]-'a'] = new TrieNode();    //建出新结点
            temp = temp->next[word[i]-'a'];
            temp->pass++;
        }
        temp->end++;      //temp指向字符串最后一个结点,end++表示多了一个字符串以此结点结尾
    }

    /** 查找树上是否有字符串word ,也可以返回int 代表树上找到的word数量*/
    bool search(string word) {
        TrieNode *temp = root;
        for(char c : word)        //遍历字符串每个字符,也可以使用for i~word.size写法
        {
            if(temp->next[c-'a'] == nullptr )  //找的过程发现没路了,false
                return false;
            temp = temp->next[c-'a'];
        }
        return temp->end;
    }

    /** 查找树上是否有字符串含前缀prefix */
    bool startsWith(string prefix) {
        TrieNode *temp = root;
        for(unsigned int i = 0 ;i<prefix.size() ;i++)
        {
            if(temp->next[prefix[i]-'a'] == nullptr)
                return false;
            temp = temp->next[prefix[i]-'a'];
        }
        return true;
    }


    /* 递归释放空间*/
    void deletememory( TrieNode *temp) {
        for(int i = 0 ;i < 26; i++)   //对一个结点,将其next数组存放的后续节点全部释放
            if(temp->next[i])
               deletememory(temp->next[i]);
        delete temp;    //释放本结点空间
    }


    /*从树上删除字符串*/
    void remove(string word) {
        if(true == search(word))   //树上有这个字符串才需要删除
        {
            TrieNode *temp = root;
            temp->pass--;
            for(unsigned int i = 0 ; i< word.size() ;i++)
            {
                if( --temp->next[word[i]-'a']->pass  == 0)   //唯一经过该结点的字符串被删除
                {
                    deletememory(temp->next[word[i]-'a'] );  //递归释放此结点后面路径
                    temp->next[word[i]-'a'] = nullptr;   结点置nulptr
                    return ;
                }
                temp = temp->next[word[i] - 'a'];
            }
            temp->end--;     //如果字符串所有字符删除后,路径没变,还需要把最后结点end-1
        }
    }

};
#endif // TRIE_H_INCLUDED

上面所给出的实现要求字符串都是小写字母,但如果字符种类非常多,我们需要将存储下一结点的数据结构进行修改,因为定长数组的方式可能会造成空间巨大的浪费,我们可以使用哈希map的方式存储 <字符,下一结点>

猜你喜欢

转载自blog.csdn.net/ass133755/article/details/125880637