Trie树(字典树)

Trie树(字典树)

什么是Trie树

Trie树是一种多叉树结构,通常用来统计和排序大量的字符串。

上图所示就是一棵Trie树。该树包含的字符串集合为{“at”, “bee”, “ben”, “bt”, “q”}。
Trie树有如下特点:

  • 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
  • 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
  • 每个节点的所有子节点包含的字符都不相同。
    Trie树将字符串存储在一条路径上。
Trie树的优缺点

Trie树是以空间换时间。用字符串的公共前缀来降低查询时间开销以达到提高效率的目的。
优点:

  • 可以最大限度减少无畏的字符串比较,查询效率高。它插入和查询的时间复杂度都为O(k),其中k为key的长度。
  • Trie树中不同的关键字不会产生碰撞
  • Trie树可以对关键字按字典序排序

缺点:

  • 空间消耗大
  • 当hash函数很好时,效率不如哈希搜索
Trie树的应用
  1. 字符串检索:对于建立好的Trie树,查询是只需要从根节点开始一个个字符比较即可
  2. 词频统计:统计单词出现的次数。这时Trie树节点通常有一个count变量统计字符串出现的次数
  3. 字符串排序:可以先插入,然后先序遍历输出字符串
  4. 前缀匹配:找到以某个字符串开头的字符串
Trie树的数据结构

利用字符串创建一棵Trie树,这个Trie树保留了字符串的公共前缀。以小写英文单词创建字典树为例,每一个节点都有26个孩子(有26个字母)。

结构如下:

//Trie node
typedef struct TrieNode
{
    int count;//统计单词前缀出现的次数
    bool exist; //该节点是否存在
    struct TrieNode* next[26];//指向子树的指针

}TrieNode, *Trie;
简单实现
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <assert.h>

#pragma warning(disable:4996)//vs

//Trie node
typedef struct TrieNode
{
    int count;//统计单词前缀出现的次数
    struct TrieNode* next[26];//指向子树的指针
    bool exist; //该节点是否存在
}TrieNode, *Trie;

//创建一个节点
TrieNode* CreateTrieNode()
{
    TrieNode* node = (TrieNode*)malloc(sizeof(TrieNode));
    assert(node);
    //if (node == NULL)
    //{
    //    printf("Create Trie node error: Out of memoey!\n");
    //    return NULL;
    //}
    node->count = 0;
    node->exist = false;
    memset(node->next, 0, sizeof(node->next));

    return node;
}

//插入到Trie中
void TrieInsert(Trie root, char* word)
{
    TrieNode* node = root;
    char* p = word;
    int id = 0;
    //遍历每一个char
    while (*p)
    {
        id = *p - 'a'; // find the char position in the child
        if (node->next[id] == NULL) //不存在*p这条路径
        {
            node->next[id] = CreateTrieNode();
        }
        node = node->next[id];//指针向下移动.这里必须明白:每一个节点代表的是从根节点到此节点路径上所有字符组成的单词
        node->count++;//前缀加1
        ++p;
    }
    printf("insert %s ok!\n", word);
    node->exist = true;
}

//查找,和插入类似,返回以此字符为前缀的单词的个数
int TrieSearch(Trie root, char* word)
{
    TrieNode* node = root;
    char* p = word;
    int id;
    while (*p)
    {
        id = *p - 'a';
        node = node->next[id];
        if (node == NULL)
        {
            printf("not find the word:%s\n", word);
            return 0;           
        }
        ++p;
    }
    printf("find the word:%s\n", word);
    return node->count;
}

int main()
{
    freopen("read.txt", "r", stdin);
    Trie root = CreateTrieNode();//init
    char str[100][20];//100个单词,每个单词有20个字符
    int n = 0;
    while (~scanf("%s", str[n]))
    {
        TrieInsert(root, str[n++]);
    }

    for (int i = 0; i < 10; ++i)
    {
        TrieSearch(root, str[i]);
    }

    //无法检测的情况
    char str1[20] = "carbin";
    TrieSearch(root, str1);

    return 0;
}
/*

read.txt内容如下:
carbohydrate
cart
carburetor
caramel
caribou
carbonic
cartilage
carbon
carriage
carton
car
carbonate

output:
insert carbohydrate ok!
insert cart ok!
insert carburetor ok!
insert caramel ok!
insert caribou ok!
insert carbonic ok!
insert cartilage ok!
insert carbon ok!
insert carriage ok!
insert carton ok!
insert car ok!
insert carbonate ok!
find the word:carbohydrate
find the word:cart
find the word:carburetor
find the word:caramel
find the word:caribou
find the word:carbonic
find the word:cartilage
find the word:carbon
find the word:carriage
find the word:carton
not find the word:carbin
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值