trie树

描述摘自网络:

http://www.cnblogs.com/dolphin0520/archive/2011/10/11/2207886.html

 Trie树

       Trie树也称字典树,因为其效率很高,所以在在字符串查找、前缀匹配等中应用很广泛,其高效率是以空间为代价的。

一.Trie树的原理

    利用串构建一个字典树,这个字典树保存了串的公共前缀信息,因此可以降低查询操作的复杂度。

    下面以英文单词构建的字典树为例,这棵Trie树中每个结点包括26个孩子结点,因为总共有26个英文字母(假设单词都是小写字母组成)。

    则可声明包含Trie树的结点信息的结构体:

struct TrieNode
{
    bool isWord;
    TrieNode *next[MAX];
};

其中next是一个指针数组,存放着指向各个孩子结点的指针。

    如给出字符串"abc","ab","bd","dda",根据该字符串序列构建一棵Trie树。则构建的树如下:

    

Trie树的根结点不包含任何信息,第一个字符串为"abc",第一个字母为'a',因此根结点中数组next下标为'a'-97的值不为 NULL,其他同理,构建的Trie树如图所示,红色结点表示在该处可以构成一个单词。很显然,如果要查找单词"abc"是否存在,查找长度则为 O(len),len为要查找的字符串的长度。而若采用一般的逐个匹配查找,则查找长度为O(len*n),n为字符串的个数。显然基于Trie树的查找 效率要高很多。

但是却是以空间为代价的,比如图中每个结点所占的空间都为(26*4+1)Byte=105Byte,那么这棵Trie树所占的空间则为105*8Byte=840Byte,而普通的逐个查找所占空间只需(3+2+2+3)Byte=10Byte。

二.Trie树的操作

    在Trie树中主要有3个操作,插入、查找和删除。一般情况下Trie树中很少存在删除单独某个结点的情况,因此只考虑删除整棵树。

1.插入

  假设存在字符串str,Trie树的根结点为root。i=0,p=root。

  1)取str[i],判断p->next[str[i]-97]是否为空,若为空,则建立结点temp,并将p->next[str[i]-97]指向temp,然后p指向temp;

   若不为空,则p=p->next[str[i]-97];

  2)i++,继续取str[i],循环1)中的操作,直到遇到结束符'\0',此时将当前结点p中的isStr置为true。

2.查找

  假设要查找的字符串为str,Trie树的根结点为root,i=0,p=root

  1)取str[i],判断判断p->next[str[i]-97]是否为空,若为空,则返回false;若不为空,则p=p->next[str[i]-97],继续取字符。

  2)重复1)中的操作直到遇到结束符'\0',若当前结点p不为空并且isStr为true,则返回true,否则返回false。

3.删除

  删除可以以递归的形式进行删除。

代码自己实现:

#include <iostream>
#include <cassert>
using namespace std;

#define MAX 26

struct TrieNode
{
    bool isWord;
    TrieNode *next[MAX];
};

TrieNode* createNewNode()
{
    TrieNode* pNew = new TrieNode;
    pNew->isWord=false;
    for (int i=0; i<MAX; i++)
    {
        pNew->next[i] = NULL;
    }
    return pNew;
}

//向trie tree中添加单词
void insertWord(TrieNode* pRoot, const char* word)
{
    assert(pRoot!=NULL);
    assert(word!=NULL);
    TrieNode* p = pRoot;
    while (*word!='\0')
    {
        if (p->next[*word-'a']==NULL)
        {
            TrieNode* pNext = createNewNode();
            p->next[*word-'a'] = pNext;
        }
        p=p->next[*word-'a'];
        word++;
    }
    p->isWord=true;

}


// 查找某单词是否存在
bool searchWord(TrieNode* pRoot, const char *word)
{
    assert(pRoot!=NULL);
    assert(word!=NULL);
    TrieNode* p = pRoot;
    while(p!=NULL && *word!='\0')
    {
        p=p->next[*word-'a'];
        word++;
    }
    return (p!=NULL && p->isWord == true);
}

// 删除trie tree
void deleteTree(TrieNode *pRoot)
{
    if (pRoot==NULL)
    {
        return;
    }
    for (int i=0; i<MAX; i++)
    {
        deleteTree(pRoot->next[i]);
    }
    delete pRoot;

}


int main(int arrgc, char* argv[])  
{  
    // 建立根节点
    TrieNode* pRoot = createNewNode();
    
    insertWord(pRoot,"hello");
    insertWord(pRoot,"helloboy");
    insertWord(pRoot,"boy");
    insertWord(pRoot,"world");

    cout<<searchWord(pRoot,"boy");

    deleteTree(pRoot);
    return 0;
}  
原文地址:https://www.cnblogs.com/cyttina/p/2746094.html