Trie树(字典树)

  如果以树的多重链表表示键树,则树的每个结点中应包含d个(d为关键字符的基,如:字符集由英文大写字母构成时,则d=26)指针域,此时的键树又称为Trie树。

关于Trie树的思想和优点:
  1、Trie树利用字符串的公共前缀来降低时空开销
  2、Trie树的典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计
  3、Trie树的优点是最大限度地减少无谓的字符串比较。
  4、Trie树的缺点是如果存在大量字符串且这些字符串基本没有公共前缀,则相应的Trie树将非常消耗内存。
const int branchNum = 26;  //26个英文字母
class Trie_node
{
public:
        Trie_node():isStr(false){ memset(next,NULL,sizeof(next)); } 
//初始结点是否到达一个字符串标记为false,指向各个结点的指针都为NULL
public:
        bool isStr;  //记录此处是否构成一个串
        Trie_node* next[branchNum];  //指向各个子树的指针,数组下标就相当于字母的值
};



如右图所示,每个结点包含一个isStr和一个next数组,如果isStr==true,就表示从_root结点到该结点之间的路径对应的数组下标就是一个存在的字符串,右图中 aa是一个存在的字符串

#include<iostream>
#include<string.h>
using namespace std;
const int branchNum = 26;  //26个英文字符

class Trie_node
{
public:
        Trie_node():isStr(false){ memset(next,NULL,sizeof(next)); }  
public:
        bool isStr;  
        Trie_node* next[branchNum]; 
};

class Trie
{
public:
        Trie():_root(new Trie_node())  {}
        void insert(const char* word);
        bool search(const char* word)const;
        void deleteTrie(Trie_node* root);
        Trie_node* getTrie()const{ return _root; }
private:
        Trie_node* _root;
};

//main文件测试
int main()
{
        Trie myTrie;
        const char* arr[] = {"mei","hao","hello","world"};
        for(int idx=0;idx!=4;++idx)
        {
                myTrie.insert(arr[idx]);
        }
        cout<<endl;
        for(int idx=0;idx!=4;++idx)
        {
                cout<<myTrie.search(arr[idx])<<" ";
        }
        cout<<endl;
        cout<<myTrie.search("meihao")<<endl;
        system("pause");
}


//类实现文件
void Trie::insert(const char* word)
{
        Trie_node* cur = getTrie();
        while(*word)
        {
                if(cur->next[*word - 'a']==NULL)
                {
                        Trie_node* node = new Trie_node();
                        cur->next[*word - 'a'] = node;
                }
                cur = cur->next[*word - 'a'];  //指向下一个
                ++word;
        }
        //插入完毕,字符串最后一个结点标记为true,表示到此已经是一个单词了
        cur->isStr = true;
}

bool Trie::search(const char* word)const
{
        Trie_node* cur = getTrie();
        while(*word&&NULL!=cur)  //单词还没匹配完,下一个字符存在,就接着向下匹配
        {
                cur = cur->next[*word - 'a'];
                ++word;
        }
        //判断是不是找到了这个字符串
        return (cur!=NULL && cur->isStr);  //注意这里的判断顺序,如果第一个满足,接着判断第二个;如果第一个不满足就直接返回;是一个开关语句
        // 如果cur==NULL,先判断cur->isStr就要段错误
}

void Trie::deleteTrie(Trie_node* root)
{
        if(NULL!=root)
        {
                for(int idx=0;idx!=branchNum;++idx)
                {
                        deleteTrie(root->next[idx]);
                        delete root;
                        root = NULL;
                }
        }
}



原文地址:https://www.cnblogs.com/meihao1203/p/9508810.html