Trie树的分析与实现

字典树

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。(From baike)

它有三个基本性质:

(1)根节点不存储字符
(2)除根节点外每一个节点都只存储一个字符
(3)从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串,每个节点的所有子节点包含的字符都不相同。

Java实现代码(注释详细):

  1 package com.wxisme.trietree;
  2
  3 /**
  4  *Trie树的实现
  5  *@author wxisme
  6  *@time 2015-10-13 下午9:48:30
  7  */
  8 public class TrieTree {
  9
 10     private final int SIZE = 26;//字符出现的种类数,以所有的小写字母为例
 11
 12     private int nodeNumber;//子节点的个数
 13
 14     private int depth;//树的深度
 15
 16     private TrieNode root;//树根
 17
 18     public TrieTree() {
 19         this.nodeNumber = 0;
 20         this.depth = 0;
 21         this.root = new TrieNode();
 22     }
 23
 24     /**
 25      * 节点结构
 26      * @author wxisme
 27      *
 28      */
 29     private class TrieNode {
 30         private char val;//节点值
 31
 32         private TrieNode son[];//子节点数组
 33
 34         private boolean isEnd;//是否有以此节点为结束字符的单词
 35
 36         private int pearNumber;//节点出现的次数
 37
 38         public TrieNode() {
 39             this.isEnd = false;
 40             this.pearNumber = 0;
 41             this.son = new TrieNode[SIZE];
 42         }
 43     }
 44
 45     /**
 46      * 向Trie中插入一个word
 47      * @param word
 48      */
 49     public void insert(String word) {
 50         char[] wordChars = word.toCharArray();
 51
 52         TrieNode node = this.root;
 53
 54         for(char ch : wordChars) {
 55             int pos = ch - ‘a‘;
 56             //如果相应位置为空则创建
 57             if(node.son[pos] == null) {
 58                 node.son[pos] = new TrieNode();
 59                 node.son[pos].val = ch;
 60                 node.pearNumber = 1;//第一次出现
 61                 this.nodeNumber ++;
 62             }
 63             else {//已经有该字符
 64                 node.pearNumber ++;
 65             }
 66             node = node.son[pos];
 67         }
 68         node.isEnd = true;
 69         this.depth = Math.max(this.depth, word.length());
 70     }
 71
 72     /**
 73      * 查找是否存在单词word
 74      * @param word
 75      * @return 结果
 76      */
 77     public boolean search(String word) {
 78         char[] wordChars = word.toCharArray();
 79
 80         TrieNode node = this.root;
 81
 82         for(char ch : wordChars) {
 83             int pos = ch - ‘a‘;
 84             if(node.son[pos] != null) {
 85                 node = node.son[pos];//继续向下查找
 86             }
 87             else {
 88                 return false;
 89             }
 90         }
 91
 92         return node.isEnd;
 93     }
 94
 95     /**
 96      * 查找是否存在以word为前缀的单词,和search()类似,只是不用判断边界。
 97      * @param word
 98      * @return 结果
 99      */
100     public boolean searchPrefix(String word) {
101         char[] wordChars = word.toCharArray();
102
103         TrieNode node = this.root;
104
105         for(char ch : wordChars) {
106             int pos = ch - ‘a‘;
107             if(node.son[pos] != null) {
108                 node = node.son[pos];//继续向下查找
109             }
110             else {
111                 return false;
112             }
113         }
114
115         return true;
116     }
117
118     /**
119      * 统计单词出现的次数
120      * @param word
121      * @return 结果
122      */
123     public int wordCount(String word) {
124         char[] wordChars = word.toCharArray();
125
126         TrieNode node = this.root;
127
128         for(char ch : wordChars) {
129             int pos = ch - ‘a‘;
130             if(node.son[pos] == null) {
131                 return 0;
132             }
133             else {
134                 node = node.son[pos];
135             }
136         }
137
138         return node.isEnd?node.pearNumber:0;
139     }
140
141
142     /**
143      * 统计以word为前缀的单词个数
144      * @param word
145      * @return 结果
146      */
147     public int wordPrefixCount(String word) {
148         char[] wordChars = word.toCharArray();
149
150         TrieNode node = this.root;
151
152         for(char ch : wordChars) {
153             int pos = ch - ‘a‘;
154             if(node.son[pos] == null) {
155                 return 0;
156             }
157             else {
158                 node = node.son[pos];
159             }
160         }
161
162         return node.pearNumber;
163     }
164
165     /**
166      * 深度优先遍历Trie树
167      * @param root
168      */
169     public void traversal(TrieNode root) {
170         if(root == null) {
171             return;
172         }
173         for(TrieNode node : root.son) {
174             System.out.println(node.val);
175             traversal(node);
176         }
177     }
178
179     public int getNodeNumber() {
180         return nodeNumber;
181     }
182
183     public int getDepth() {
184         return depth;
185     }
186
187     public TrieNode getRoot() {
188         return root;
189     }
190
191 }

看一个Leetcode应用:http://www.cnblogs.com/wxisme/p/4875309.html

时间: 2024-10-16 17:36:31

Trie树的分析与实现的相关文章

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类

剑指Offer——Trie树(字典树)

剑指Offer--Trie树(字典树) Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高. Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的. Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子右兄弟的方法建树的话,可能会好点.可见,优

poj_3630 trie树

题目大意 给定一系列电话号码,查看他们之间是否有i,j满足,号码i是号码j的前缀子串. 题目分析 典型的trie树结构.直接使用trie树即可.但是需要注意,若使用指针形式的trie树,则在大数据量下new/delete会很耗时,因此使用静态数组来存储trie树结构.使用静态数组代替指针在oj中常用于节省时间! 实现(c++) #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #define M

POJ 2503 Babelfish (Trie树 或 map)

Babelfish Time Limit: 3000MS        Memory Limit: 65536K Total Submissions: 34278        Accepted: 14706 Description You have just moved from Waterloo to a big city. The people here speak an incomprehensible dialect of a foreign language. Fortunately

HDU 1277 全文检索 (Trie树应用 好题)

全文检索 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1304    Accepted Submission(s): 416 Problem Description 我们大家经常用google检索信息,但是检索信息的程序是很困难编写的:现在请你编写一个简单的全文检索程序. 问题的描述是这样的:给定一个信息流文件,信息完全有数字组成,

利用Trie树求多个字符串编辑距离的进一步优化

1.引言 题目的意思应该是:在一个给定的字典中,求与给定的字符串的编辑距离不大于2的所有的单词.原先写过两片关于此问题的文章,那两片篇章文章给出两种解决思路:其一是暴力求解法,这种方法最容易想到.就是将词典中的词一一与给定的字符串计算编辑距离,不大于2的输出,大于2的舍弃,这种方法思路简单但是很费时间.其二根据词典中这些词之间的编辑距离建立一个以单词为节点的Trie树,遍历的时候,通过计算根节点与给定字符串的编辑距离就可以排除掉一部分分支了,然后继续计算该字符串与剩余的分支的根的编辑距离,继续排

B树、Trie树详解

查找(二) 散列表 散列表是普通数组概念的推广.由于对普通数组可以直接寻址,使得能在O(1)时间内访问数组中的任意位置.在散列表中,不是直接把关键字作为数组的下标,而是根据关键字计算出相应的下标. 使用散列的查找算法分为两步.第一步是用散列函数将被查找的键转化为数组的一个索引. 我们需要面对两个或多个键都会散列到相同的索引值的情况.因此,第二步就是一个处理碰撞冲突的过程,由两种经典解决碰撞的方法:拉链法和线性探测法. 散列表是算法在时间和空间上作出权衡的经典例子. 如果没有内存限制,我们可以直接

[POJ] #1003# 487-3279 : 桶排序/字典树(Trie树)/快速排序

一. 题目 487-3279 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 274040   Accepted: 48891 Description Businesses like to have memorable telephone numbers. One way to make a telephone number memorable is to have it spell a memorable word or

hdu1251(Trie树)

传送门:统计难题 分析:Trie树入门题,随便写写练下手感,统计每个节点被多少单词经过就可以了. #include <iostream> #include <cstdio> #include <cmath> #include <cstdlib> #include <algorithm> #include <cstring> #include <queue> #include <vector> #define L