字典树
字典树,又称单词查找树,Trie树,是一种树形结构,典型应用是用于统计,排序和保存大量的字符串,所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度的减少无谓的字符串比较,查询效率比哈希表高。
它有三个基本性质,根节点不包含字符,除根节点外每一个节点都只包含一个字符,从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串,每个节点的所有子节点包含的字符都不相同。
字典树的插入,删除和查找都非常简单,用一个一重循环即可。
1. 从根节点开始一次搜索
2. 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索
3. 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索
4. 迭代过程...
5. 在某个节点处,关键词的所有字母已被取出,则读取附在该节点上的信息,即完成查找
字典树的应用
1.字典树在串的快速检索中的应用。
给出N个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。
在这道题中,我们可以用数组枚举,用哈希,用字典树,先把熟词建一棵树,然后读入文章进行比较,这种方法效率是比较高的。
2. 字典树在“串”排序方面的应用
给定N个互不相同的仅由一个单词构成的英文名,让你将他们按字典序从小到大输出
用字典树进行排序,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序。对这棵树进行先序遍历即可
3. 字典树在最长公共前缀问题的应用
对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,于是,问题就转化为最近公共祖先问题。
#ifndef __DICTTREE_H #define __DICTTREE_H #define NUM 26 typedef struct node_t { char c; int freq; node_t *children[NUM]; }node_t; node_t * create_node_t(); void free_node_t(node_t *p_node); typedef struct dicttree_t { node_t *root; }dicttree_t; dicttree_t *create_dicttree_t(); void free_dicttree_t(dicttree_t *p_tree); void insert_dicttree_t(dicttree_t *p_tree, char *str); int find_dicttree_t(dicttree_t *p_tree, char *str); #endif
#include <stdlib.h> #include <stdio.h> #include <string.h> #include "dicttree.h" node_t *create_node_t() { node_t *t = (node_t*)malloc(sizeof(node_t)); if (t == NULL) { printf("malloc error\n"); exit(-1); } t->c = 0; t->freq = 0; for (int i = 0; i < NUM; i++) { t->children[i] = NULL; } return t; } void free_node_t(node_t *p_node) { if (p_node == NULL) { return; } for (int i = 0; i < NUM; i++) { free_node_t(p_node->children[i]); } free(p_node); } dicttree_t *create_dicttree_t() { dicttree_t *p_tree = (dicttree_t *)malloc(sizeof(dicttree_t)); if (p_tree == NULL) { printf("malloc error\n"); exit(-1); } p_tree->root = create_node_t(); return p_tree; } void free_dicttree_t(dicttree_t *p_tree) { free(p_tree->root); free(p_tree); } void insert_dicttree_t(dicttree_t *p_tree, char *str) { if (str == NULL) { printf("string is NULL\n"); return; } node_t *p_node = p_tree->root; int char_index = 0; int len = strlen(str); for (int i = 0; i < len; i++) { char_index = str[i] - 'a'; if (p_node->children[char_index] == NULL) { p_node->children[char_index] = create_node_t(); } p_node->children[char_index]->c = str[i]; p_node = p_node->children[char_index]; } p_node->freq += 1; } int find_dicttree_t(dicttree_t *p_tree, char *str) { if (p_tree == NULL) { printf("dicttree is NULL"); return 0; } if (str == NULL) { return 0; } node_t *p_node = p_tree->root; int len = strlen(str); int char_index; for (int i = 0; i < len; i++) { char_index = str[i] - 'a'; if (p_node->children[char_index] == NULL) { return 0; } p_node = p_node->children[char_index]; } return p_node->freq; }
#include <stdio.h> #include <string.h> #include "dicttree.h" int main(int argc, char **argv) { char *strs[12] = {"a", "a", "a", "aa", "ab", "ac", "bb", "bb", "bc", "cc", "cc", "cc"}; dicttree_t *p_tree = create_dicttree_t(); for (int i = 0; i < 12; i++) { insert_dicttree_t(p_tree, strs[i]); } char *strs2[3] = {"a", "b", "cc"}; for (int i = 0; i < 3; i++) { int count = find_dicttree_t(p_tree, strs2[i]); printf("%s: %d\n", strs2[i], count); } free_dicttree_t(p_tree); getchar(); return 0; }
结果: