字典树(Trie tree)

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;
}

测试结果为:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值