Trie,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
性质:
根节点不包含字符,除根节点外每一个节点都只包含一个字符。
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
性质:
根节点不包含字符,除根节点外每一个节点都只包含一个字符。
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
每个节点的所有子节点包含的字符都不相同。
Trie树的基本实现
字母树的插入(Insert)、删除( Delete)和查找(Find)都非常简单,用一个一重循环即可,即第i 次循环找到前i 个字母所对应的子树,然后进行相应的操作。实现这棵字母树,我们用最常见的数组保存(静态开辟内存)即可,当然也可以开动态的指针类型(动态开辟内存)。至于结点对儿子的指向,一般有三种方法:
1、对每个结点开一个字母集大小的数组,对应的下标是儿子所表示的字母,内容则是这个儿子对应在大数组上的位置,即标号;
2、对每个结点挂一个链表,按一定顺序记录每个儿子是谁;
3、使用左儿子右兄弟表示法记录这棵树。
三种方法,各有特点。第一种易实现,但实际的空间要求较大;第二种,较易实现,空间要求相对较小,但比较费时;第三种,空间要求最小,但相对费时且不易写。
现就第一种给出实现代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mcheck.h>
#define TREE_WIDTH 256
#define WORDLENMAX 128
struct trie_node {
struct trie_node *next[TREE_WIDTH];
};
void insert(struct trie_node *tree, char *str)
{
int i = 0;
unsigned char c;
while((c = str[i]) != '\0') {
if(tree->next[c] == NULL) {
tree->next[c] = malloc(sizeof(struct trie_node));
memset(tree->next[c], 0, sizeof(struct trie_node));
}
tree = tree->next[c];
i++;
}
}
int isExist(struct trie_node *tree, char *str)
{
int i = 0;
unsigned char c;
if(!tree)
return 0;
while((c = str[i]) != '\0') {
if(tree->next[c] == NULL)
break;
tree = tree->next[c];
i++;
}
if(c != '\0')
return 0;
for(i = 0; i < TREE_WIDTH; i++) {
if(tree->next[i])
return 0;
}
return 1;
}
void delete(struct trie_node *tree, char *str)
{
int i = 0, j, child_num;
struct trie_node **path;
unsigned char c;
if(!tree)
return;
if(!isExist(tree, str))
return;
path = malloc(strlen(str) * sizeof(struct trie_node *));
while((c = str[i]) != '\0') {
path[i] = tree;
tree = tree->next[c];
i++;
}
free(tree);
for(i = strlen(str) - 1; i >= 0; i--) {
child_num = 0;
for(j = 0; j < TREE_WIDTH; j++) {
if(path[i]->next[j])
child_num++;
}
if(child_num == 1 && i != 0)
free(path[i]);
else {
path[i]->next[str[i]]= NULL;
break;
}
}
free(path);
}
void __print(struct trie_node *tree, unsigned char *str, int len)
{
int i, leaf_node = 1;
if(!tree)
return;
for(i = 0; i < TREE_WIDTH; i++) {
if(tree->next[i]) {
str[len++] = i;
__print(tree->next[i], str, len);
leaf_node = 0;
}
}
if(len > 0 && leaf_node == 1) {
str[len] = '\0';
printf("%s\n", str);
}
}
void print(struct trie_node *tree)
{
unsigned char str[WORDLENMAX];
int i = 0;
__print(tree, str, i);
}
void free_trie(struct trie_node *tree)
{
int i;
if(!tree)
return;
for(i = 0; i < TREE_WIDTH; i++) {
if(tree->next[i])
free_trie(tree->next[i]);
}
free(tree);
}
struct trie_node *create_trie()
{
struct trie_node *tree = malloc(sizeof(struct trie_node));
return tree;
}
int main()
{
struct trie_node *tree;
setenv("MALLOC_TRACE", "memory_report", 1);
mtrace();
tree = create_trie();
insert(tree, "trie_test");
insert(tree, "mytrie");
printf("%d\n", isExist(tree, "mytrie"));
delete(tree, "mytrie");
printf("%d\n", isExist(tree, "mytrie"));
print(tree);
free_trie(tree);
return 0;
}
测试结果为: