终于要开始更新我的ACM学习之路了,不过没想到却是因为一次Java大作业,有趣,%yuan老师。

字典树是一种很简单的树形结构,主要用来进行词频统计,在算法竞赛中有时也会碰到。

字典树的基本思路是,通过树这种数据结构,读入文本的时候同步建立树,每个节点通过一个指针数组保存了子树的指针,指针数组的下标存储了单词的信息,将每个单词的公共前缀都保存在同一条路径上,尽可能的节省了空间。同时因为一颗平衡二叉树的查找效率很高,因此字典树的查找效率很高,为O(logN)。

不过这种结构应该还可以用左孩子右兄弟表示法来进一步节省空间,只不过这样可能需要再多定义一个char来专门存储保存的字符。

好,既然大家都觉得这个思路那是相~~~~当的简单,那么让我们来动手实践一下吧~~

一下实现是基于java实现,因此没有释放内存的delete函数。

节点的数据结构定义如下:

class Node{
private int num;
private Node[] next;
private boolean leaf; public Node() {
this.num=0;
this.next=new Node[26];
this.leaf=true;
} public int getNum() {return num;} public void setNum(int num) {this.num = num;} public Node[] getNext() { return next;} public boolean isLeaf() {return leaf;} public void setLeaf(boolean leaf) {this.leaf = leaf;} }

说明一下,这里的Next数组就是我们的指针数组,这里它有两个作用,第一,记录子树的位置,第二,通过下标运算,可以得知存储的字母。这里一定要记住作用二呦,这样我们就不需要再定义一个专门的char来保存字母了。当然,我呢是个大懒蛋,所以为了能少写点代码,这里还定义一个boolean类型的leaf,这样我就不用每次通过判断节点的Next数组是不是全为null来判断是不是 leaf了,哈哈哈哈。

构建树并没有必要用递归,代码如下:

 public void creTree() throws IOException{
//initialize
this.head=createNode();
this.cnt=0;
//create tree
String s=this.read();
while(s.compareTo("\\$")!=0){
//处理每个单词
char []words=s.toLowerCase().toCharArray();
Node p=head;
for(int i=0;i<words.length;i++) {
if(p.getNext()[words[i]-'a']==null) {
p.getNext()[words[i]-'a'] =createNode();
p.setLeaf(false);
this.cnt++;
}
p = p.getNext()[words[i] - 'a'];
}
p.setNum(p.getNum()+1);
//读取下一个单词
s = this.read();
}
this.res = new String[cnt];
this.num = new int[cnt];
}

在通常字典树的应用范围中,常常是查找的应用,即只需要按照给定的字符串,判断是否有,或者有几个,因此也不需要使用递归,只需要将建树的部分12行以后的代码稍加修改,就可以了,因此就不赘述了,相信以各位的智商一定是毫无问题的。但是稍稍复杂一点的是,打印树中所有的单词,并输出出现的个数,这样就需要涉及到深度优先遍历(DFS),在处理需要输出的字符串上也稍复杂了一点,这里贴出我的解决方法,欢迎高端玩家批评指正呦~

首先在函数外定义一个StringBuffer,为什么要在函数外呢,因为遍历函数需要递归,当然不能在函数内啦,嘻嘻~~~

  private StringBuffer sbf = new StringBuffer();

然后就是DFS了

其中String[] res和 int[]num 分别存储字符串本身以及出现的次数

 public void findTree(Node h) {
if(h.isLeaf())return ;
Node p = h;
for(int i=0;i<p.getNext().length;i++) {
if(p.getNext()[i]==null)continue;
sbf.append((char) ((int) 'a' + i));
if(p.getNext()[i].getNum()>0) {
this.res[str]=sbf.toString();
this.num[str++]=p.getNext()[i].getNum();
}
this.findTree(p.getNext()[i]);
sbf.deleteCharAt(sbf.length() - 1);
}
}

这样,遍历就可以完成啦~~后面有时间我会继续更新一些ACM的字典树的题上来,就这样吧~

============================================我是渣渣专用的分割线==========================================

最近在百度的编程题目中遇到了需要用到字典树的题目,原题目大概是说,给你三个操作,insert,delete,search,每个操作后面都给你一个待操作的字符串,输出为:当遇到search时,进行查找,找到输出Yes,反之输出NO。

这个题很水对吧,我目前想到两种做法,一种是用C++的STL中的map直接对出现的次数做映射,这样代码简洁,并且插入和查找的效率都是O(1),

第二种就是字典树,这个方法当然代码量大一些,不过也能做,但是在字典树在删除的时候引起了我的思考:

  如果我将这个词所占用的内存直接释放,那么会出现这样的情况:比如app和apple两个词,如果我删除app的操作是释放内存,那么我就无法找到apple。

  因此,我只能在通过修改标记的方法进行删除,这样和map实现的删除原理上就一致了。

综上:用map实现在时间效率上不输于Trie Tree,空间复杂度只要在比赛要求的范围内,就可以起到用很少的代码完成相同的问题的目标,性价比比较高

字典树(Trie Tree)的更多相关文章

  1. 字典树(Trie Tree)

    在图示中,键标注在节点中,值标注在节点之下.每一个完整的英文单词对应一个特定的整数.Trie 可以看作是一个确定有限状态自动机,尽管边上的符号一般是隐含在分支的顺序中的.键不需要被显式地保存在节点中. ...

  2. 字典树Trie Tree

    又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:利用字符串的公共前缀 ...

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

    一. 题目 487-3279 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 274040   Accepted: 48891 ...

  4. 字典树trie学习

    字典树trie的思想就是利用节点来记录单词,这样重复的单词可以很快速统计,单词也可以快速的索引.缺点是内存消耗大 http://blog.csdn.net/chenleixing/article/de ...

  5. 『字典树 trie』

    字典树 (trie) 字典树,又名\(trie\)树,是一种用于实现字符串快速检索的树形数据结构.核心思想为利用若干字符串的公共前缀来节约储存空间以及实现快速检索. \(trie\)树可以在\(O(( ...

  6. 字典树(Trie)详解

    详解字典树(Trie) 本篇随笔简单讲解一下信息学奥林匹克竞赛中的较为常用的数据结构--字典树.字典树也叫Trie树.前缀树.顾名思义,它是一种针对字符串进行维护的数据结构.并且,它的用途超级广泛.建 ...

  7. 字典树(Trie树)实现与应用

    一.概述 1.基本概念 字典树,又称为单词查找树,Tire数,是一种树形结构,它是一种哈希树的变种. 2.基本性质 根节点不包含字符,除根节点外的每一个子节点都包含一个字符 从根节点到某一节点.路径上 ...

  8. [转载]字典树(trie树)、后缀树

    (1)字典树(Trie树) Trie是个简单但实用的数据结构,通常用于实现字典查询.我们做即时响应用户输入的AJAX搜索框时,就是Trie开始.本质上,Trie是一颗存储多个字符串的树.相邻节点间的边 ...

  9. Codevs 4189 字典(字典树Trie)

    4189 字典 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 大师 Master 传送门 题目描述 Description 最经,skyzhong得到了一本好厉害的字典,这个字典里 ...

  10. 字典树trie

    字典树经常用于单词搜索,现在网络引擎中也应用了trie树: public class Trie{ private int SIZE = 26; private TrieNode root; Trie( ...

随机推荐

  1. [LG1886]滑动窗口 单调队列

    ---题面--- 题解: 观察数据范围,这应该是一个复杂度O(n)的题.以最大值为例,考虑单调队列,维护一个单调递减的队列.从前向后扫,每次答案取队首,如果后面进入的比前面大,那么就弹出前面的数,因为 ...

  2. 洛谷P1273 有线电视网 (树上分组背包)

    洛谷P1273 有线电视网 题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节 ...

  3. Codeforces Round #515 (Div. 3) E. Binary Numbers AND Sum

    E. Binary Numbers AND Sum 题目链接:https://codeforces.com/contest/1066/problem/E 题意: 给出两个用二进制表示的数,然后将第二个 ...

  4. istringstream()函数的用法

    istringstream()函数的用法 头文件:#include 功能:将一个含有多个空格的字符串分割开来 eg:

  5. maven项目在eclipse tomcat正常运行

    转摘自:http://binary.duapp.com/2013/10/1577.html 配置下部署路径即可.

  6. 取消eslint对指定代码进行代码检测

    eslint配置了不允许使用alert,但是有个需求需要用到. //eslint-disable-next-line alert('测试'); 如上,即可跳过当前行代码检查了

  7. java消息中间件入门

    消息中间件来解耦服务调用 比如1个登录系统,登录的话需要调用很多系统的其他服务,如果中间调用失败,可能会导致登录信息一致无法返回,同时也增加了系统的耦合度.而用消息中间件的话,则是不发送服务到其他系统 ...

  8. macos装多个python

    简介 Mac包管理工具brew: 安装方法:命令行输入 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Ho ...

  9. 【poj3420】递推式转矩阵乘法

    历史性的时刻!!! 推了一晚上!和hyc一起萌萌哒地推出来了!! 被摧残蹂躏的智商啊!!! 然而炒鸡高兴!! (请不要介意蒟蒻的内心独白..) 设a[i]为扫到第i行时的方案数. 易知,对于一行1*4 ...

  10. 【Foreign】阅读 [线段树][DP]

    阅读 Time Limit: 10 Sec  Memory Limit: 256 MB Description Input Output Sample Input 0 10 4 10 2 3 10 8 ...