Tire-Tree(前缀树,字典树)

在计算机科学中,trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。
Trie这个术语来自于retrieval。根据词源学,trie的发明者Edward Fredkin把它读作/ˈtriː/ “tree”。[1][2]但是,其他作者把它读作/ˈtraɪ/ “try”。
如图可以查看trie树的基本结构:
这里写图片描述
接下来,我们直接看,实现方式,简单易懂:

#include <stdio.h>
#include <stdlib.h>
#define ALPHABET_SIZE 26

typedef struct trie_node {
    int count;
    struct trie_node *children[ALPHABET_SIZE];
} trie_node;



trie_node * create_node() {
    trie_node * n = (trie_node *) malloc(sizeof(trie_node));
    n->count = 0;
    int i;
    for (i = 0; i < ALPHABET_SIZE; ++i) {
        n->children[i] = NULL;
    }
}


void insert_word(trie_node *t, char *word) {
    trie_node * cur = t;
    char *w = word;
    int indis;
    while(*w) {
        indis = *w - 'a';
        if(cur->children[indis] == NULL) {
            cur->children[indis] = create_node();
        }
        cur = cur->children[indis];
        ++w;
    }
    cur->count= 1;
}

int search(trie_node *t, char *word) {
    trie_node * cur = t;
    char *p = word;

    while (*p && cur != NULL) {
        cur = cur->children[*p - 'a'];
        ++p;
    }
    if(cur == NULL) {
        return 0;
    }
    return cur->count;
}


int main() {
    // 关键字集合
    char keys[][8] = {"the", "a", "there", "answer", "any", "by", "bye", "their"};
    trie_node *root = create_node();
    int i;
    for (i = 0; i < 8; ++i){
        insert_word(root, keys[i]);
    }

    // 检索字符串
    char s[][32] = {"Present in trie", "Not present in trie"};
    printf("%s --- %s\n", "the", search(root, "the")>0?s[0]:s[1]);
    printf("%s --- %s\n", "these", search(root, "these")>0?s[0]:s[1]);
    printf("%s --- %s\n", "their", search(root, "their")>0?s[0]:s[1]);
    printf("%s --- %s\n", "thaw", search(root, "thaw")>0?s[0]:s[1]);
    printf("Hello, World!\n");
    return 0;
}

参考:
https://zh.wikipedia.org/wiki/Trie

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++的字典树Trie)模板: ```cpp #include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5, M = 26; int n, m; int son[N][M], idx; bool is_end[N]; char str[N]; void insert() { int p = 0; for (int i = 0; str[i]; i++) { int u = str[i] - 'a'; if (!son[p][u]) son[p][u] = ++idx; p = son[p][u]; } is_end[p] = true; } bool find() { int p = 0; for (int i = 0; str[i]; i++) { int u = str[i] - 'a'; if (!son[p][u]) return false; p = son[p][u]; } return is_end[p]; } int main() { cin >> n >> m; while (n--) { scanf("%s", str); insert(); } while (m--) { scanf("%s", str); if (find()) puts("Yes"); else puts("No"); } return 0; } ``` 在这个模板中,我们使用一个整数数组son来表示每个节点的子节点。我们还使用一个bool数组is_end来表示从根节点到当前节点的路径是否为一个单词。 在insert函数中,我们遍历输入的字符串,并检查该字符的子节点是否存在,如果不存在,我们就创建一个新的子节点。最后,我们将当前节点标记为一个单词的结尾。 在find函数中,我们遍历查询字符串,并检查是否存在该字符的子节点。如果当前字符的子节点不存在,则该字符串不在字典树中。最后,我们检查当前节点是否标记为一个单词的结尾。如果是,我们返回true,否则返回false。 这个模板的时间复杂度为O(nm),其中n是字典树中单词的数量,m是查询的数量。由于每个单词的长度为O(k),因此总运行时间为O(k(n+m)),其中k是单词的平均长度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值