树学习 ---------字典树(Trie Tree)

2015-01-27 06:07:31 · 作者: · 浏览: 6

字典树,又称为字母数,前缀树等等,不仅可以存储字符,还可以存储数字等,

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。


它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。 字典树与字典很相似,当你要查一个单词是不是在字典树中,首先看单词的第一个字母是不是在字典的第一层,如果不在,说明字典树里没有该单词,如果在就在该字母的孩子节点里找是不是有单词的第二个字母,没有说明没有该单词,有的话用同样的方法继续查找.字典树不仅可以用来储存字母,也可以储存数字等其它数据


节点结构:

每个节点对应一个最大可储存字符数组。假设字典只存26个小写英文字母,那么每个节点下应该有一个长度为26的数组。换言说,可存的元素类型越多,单个节点占用内存越大。如果用字典树储存汉字,那么每个节点必须为数千个常用汉字开辟一个数组作为储存空间,占用的内存实在不是一个数量级。不过Trie树就是一种用空间换时间的数据结构,鱼和熊掌往往不可兼得。

建树细节:

  • 取要插入字符串的首个字符,从根节点的孩子节点开始,匹配当前字符是否已有节点,有则把指针指向该节点。无则为该字符创建节点,并把指针指向该新建节点。
  • 迭代。
  • 遇到要插入字符串末尾结束符时停止迭代,并把最后一个非’\0’字符对应的节点设为末端节点。

    查找细节:
    循环取要插入字符串的首个字符,从根节点的孩子节点开始,匹配当前字符是否已有节点,有则继续循环,无则返回False. 直至匹配到最后一个字符则完成查找。

    树结构图:
    我们用apps, apply, apple, append, back, basic, backen几英文单词创建树形结构:
    trie

    上图很容易看出,有相同前缀的英文单词,会合并在同一个节点,Trie树顺着一个个节点进行检索,

    代码:

    #include
    #include
    #define MAXN 100000
    typedef struct TrieNode{
    int nCount;
    struct TrieNode *next[26];
    }TrieNode;
    TrieNode Memory[MAXN];
    int allocp = 0;
    void Init(TrieNode **pRoot)
    {
    *pRoot = NULL;
    }


    TrieNode *Build()
    {
    int i;
    TrieNode *p;
    p = &Memory[allocp++];
    p -> nCount = 1;
    for(int i = 0; i < 26; ++i)
    {
    p->next[i] = NULL;
    }
    return p;
    }


    void Insert(TrieNode **pRoot, char *s)
    {
    int i, k;
    TrieNode *p;
    if(!(p = *pRoot))
    {
    p = *pRoot = Build();
    }
    i = 0;
    while(s[i])
    {
    k = s[i++] - 'a';
    if(!p->next[k])
    {
    p->next[k] = Build();
    }
    else
    {
    p->next[k] -> nCount++;
    }
    p = p->next[k];
    }
    }


    int Search(TrieNode **pRoot, char *s)
    {
    int k;
    TrieNode *p;
    p = *pRoot;
    int i = 0;
    while(p && s[i])
    {
    k = s[i++] - 'a';
    p = p->next[k];
    }
    if(!p)
    return 0;
    else
    return p->nCount;
    }




    int main()
    {
    char s[11];
    TrieNode * Root = NULL;
    printf("请输入想存储的字符串:\n");
    while(gets(s) && s[0])
    {
    Insert(&Root, s);
    }
    printf("请输入查询的前缀:\n");
    while(gets(s))
    {
    printf("%d\n", Search(&Root, s));
    }
    return 0;
    }