数据结构 练习21-trie的原理分析和应用
前言
今天具体分析一下trie树,包括:原理分析,应用场合,复杂度分析,与hash的比较,源码展现。大部分内容来自互联网,文中会注明出处。
原理分析
主要是hash树的变种,先看下图:
每一个点存储一个字符,所以trie(字典树)的key不是每个字符串,而是一条链。其原理就是充分利用了公共字符串,这样在查找时,就不需要做重复工作了。并且查找的复杂度可以维持在O(len),len为字符串的长度,原因很简单,我们只需沿着从根到节点的一条路径就可以了。插入也是类似的原理。
建立的过程:
每个节点包括三个信息:26个指针(假设查询26个英文小写字母),每个节点的后继节点可能出现26个字母当中的任何一个,故需26个指针,当然对于不存在的后继结点,设置为NULL;标志位,此标志位主要是为了识别是否为字符串为一个单词;第三个为附加信息,看具体应用场合,可以为字符出现的次数,也可以为前缀的个数,字符串的个数,总之灵活应用就是。
查询的过程:
与建立过程原理雷同,只是没有创建新节点的过程;
删除的过程:
很少见,如果非要删除,则采用递归从下往上挨个delete即可;
应用场合
我直接转载:http://www.cnblogs.com/aiyelinglong/archive/2012/04/09/2439777.html
trie树的应用:
1.有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
2.1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现?
3.一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。
4.寻找热门查询:搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复读比较高,虽然总数是1千万,但是如果去除重复和,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就越热门。请你统计最热门的10个查询串,要求使用的内存不能超过1G。
后缀树的应用:
1.查找字符串O是否在字符串S中。
方案:用S构造后缀树,按在trie中搜索字串的方法搜索O即可。
原理:若O在S中,则O必然是S的某个后缀的前缀。
例如:leconte,查找O:con是否在S中,则O(con)必然是S(leconte)的前缀。
2.指定字符串T在字符串S中的重复次数。
方案:用S+’$’构造后缀树,搜索T节点下的叶子节点数目即为重复次数
原理:如果T在S中重复了两次,则S应有两个后缀以T为前缀,重复次数自然统计出来了。
3.字符串S中的最长重复子串
方案:原理同2,具体做法是找到最深的非叶子节点。
这个深指从root所经历过的字符个数,最深非叶子节点所经历的字符串起来就是最长重复子串。为什么非要是叶子节点呢?因为既然是要重复的,当然叶子节点个数要>=2
4.两个字符串S1,S2的最长公共子串(而非以前所说的最长公共子序列,因为子序列是不连续的,而子串是连续的。)
方案:将S1#S2$作为字符串压入后缀树,找到最深的非叶子节点,且该节点的叶子节点既有#也有$.
5.最长回文子串
复杂度分析
前文已经提及,建立的时间复杂度为:O(n*len),查询,插入都为O(len)。空间复杂度就比较大了,这也是它的一个缺点,主要是指针得占用空间。
与hash的比较
首先比较创建的复杂度,创建的复杂度,hash为O(n*(len+3))(n指字符串的个数,len指字符串的长度),原理可见我的博文hash 一个海量数据的实现,里面有段代码:
int SDBMHash(char* str)
{
int hash = 0;
while(*str!='\0')
{
hash = *str++ + (hash <<6) + (hash <<16) - hash;
}
return (hash & 0x7FFFFFFF);
}
分析:3具体指int hash = 0; 和return (hash & 0x7FFFFFFF);有人会说,这也算,几乎没影响,但是大家想想,每个字符串多俩次操作,当字符串很大时,就不是俩次的问题了可能是10的几次方了,还有一次是hash表的操作。查询和插入同样的道理,每个字符串多两个操作。所以hash的时间复杂度不如trie的。这还是小case,在很多方面hash没法跟trie比的,比如查找前缀字符串,trie几乎用不到O(len),hash的操作就复杂多了,并且前缀字符串还要额外的hashmap。空间方面,可能hash 节省,但是恰恰就是因为trie牺牲了空间才换如此巨大的时间效果。
源码展现
我自己创建了一个txt文件,里面有很多单词,一行一个,利用trie统计某个单词出现的频数,可在我的资源文件里下到工程文件,里面有一个txt。可以在txt里复制同一个单词多次,然后查询,就可以看到它存在的次数了。
#include<iostream>
#include<cstring>
#include<fstream>
using namespace std; const int n=26;
typedef struct Trie_node
{
int count; // 统计单词前缀出现的次数
struct Trie_node* next[n]; // 指向各个子树的指针
bool exist; // 标记该结点处是否构成单词 }TrieNode , *Trie; TrieNode* createTrieNode()
{
TrieNode* node = (TrieNode *)malloc(sizeof(TrieNode));
node->count = 0;
node->exist = false;
memset(node->next , 0 , sizeof(node->next)); // 初始化为空指针
return node;
} void Trie_insert(Trie root, char* word)
{
Trie node = root;
char *p = word;
int id;
while( *p )
{
id = *p - 'a';
if(node->next[id] == NULL)
{
node->next[id] = createTrieNode();
}
node = node->next[id]; // 每插入一步,相当于有一个新串经过,指针向下移动
++p;
//node->count += 1; // 这行代码用于统计每个单词前缀出现的次数(也包括统计每个单词出现的次数)
}
node->exist = true;// 单词结束的地方标记此处可以构成一个单词
node->count++;
} int Trie_search(Trie root, char* word)
{
Trie node = root;
char *p = word;
int id;
while( *p )
{
id = *p - 'a';
node = node->next[id];
++p;
if(node == NULL)
{
cout<<endl<<word<<"在文件中不存在";
return 0;
}
}
if(node->exist==true)
cout<<endl<<word<<"出现了"<<node->count<<"次";
return node->count; } const int num=5000;
//产生一个txt文件,模拟字符串
void createStrTXT()
{
for(int i=0;i<num;++i)
{
char temp[12]={'\n','\r',rand()%26+97,rand()%26+97,rand()%26+97,rand()%26+97,rand()%26+97,rand()%26+97,rand()%26+97,rand()%26+97,rand()%26+97,'\0'}; char*str=temp;
ofstream ofs("str.txt",ios::app);
ofs<<str;
}
}
void establishTrieTree(Trie root)
{
ifstream ifs("str.txt");
char str[10];
int i=0; while(ifs>>str)
{
Trie_insert(root,str);
cout<<"插入单词:"<<str<<endl;
i++; }
cout<<"总共插入"<<i<<"个单词"; }
int main(void)
{
//初始化root
Trie root=createTrieNode(); //createStrTXT(); establishTrieTree( root); Trie_search(root,"zxuglsdsm"); return 0;
}
测试图:
数据结构 练习21-trie的原理分析和应用的更多相关文章
- 数据结构HashMap哈希表原理分析
先看看定义:“散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度. 哈希 ...
- JAVA常用数据结构及原理分析
JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balaba ...
- (6)Java数据结构-- 转:JAVA常用数据结构及原理分析
JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balab ...
- Junit 注解 类加载器 .动态代理 jdbc 连接池 DButils 事务 Arraylist Linklist hashset 异常 哈希表的数据结构,存储过程 Map Object String Stringbufere File类 文件过滤器_原理分析 flush方法和close方法 序列号冲突问题
Junit 注解 3).其它注意事项: 1).@Test运行的方法,不能有形参: 2).@Test运行的方法,不能有返回值: 3).@Test运行的方法,不能是静态方法: 4).在一个类中,可以同时定 ...
- JAVA经常使用数据结构及原理分析
前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源代码,balabala讲了一堆,如今总结一下. java.util包中三个重要的接口及特点:List(列表).Set(保证集合中元素 ...
- HashMap 与 ConcrrentHashMap 使用以及源码原理分析
前奏一:HashMap面试中常见问题汇总 HashMap的工作原理是近年来常见的Java面试题,几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和Has ...
- 基于Lucene查询原理分析Elasticsearch的性能
前言 Elasticsearch是一个很火的分布式搜索系统,提供了非常强大而且易用的查询和分析能力,包括全文索引.模糊查询.多条件组合查询.地理位置查询等等,而且具有一定的分析聚合能力.因为其查询场景 ...
- [转]Handler MessageQueue Looper消息循环原理分析
Handler MessageQueue Looper消息循环原理分析 Handler概述 Handler在Android开发中非常重要,最常见的使用场景就是在子线程需要更新UI,用Handler ...
- Android ListView实现不同item的方法和原理分析
ListView实现不同item的方法和原理分析 一问题抛出Listview是android里面的重要组件,用来显示一个竖向列表,这个没有什么问题:但是有个时候列表里面的item不是一样的,如下图,列 ...
随机推荐
- Java8:使用 Optional 处理 null
写过 Java 程序的同学,一般都遇到过 NullPointerException :) —— 为了不抛出这个异常,我们便会写如下的代码: User user = getUserById(id); i ...
- js 版本号
在web项目开发过程中,我们经常会引用css.js文件,更新文件后常出现缓存问题(明明更改了代码,在浏览器上访问的时候却没有发生变化),这种情况我们通常采用以下两种解决方案: 1.手动清除浏览器缓存 ...
- LodRunner实现大负载测试的四部曲(配置系统参数、配置LR、修改脚本、设置组策略)
见 http://www.51testing.com/?uid-97659-action-viewspace-itemid-210924 LoadRunner以下简称(LR)是目前业界最流行的压力测试 ...
- linux使用常见问题
出现RTNETLINK answers: File exists 同时出现connect:network is unreachable 和 Determining IP information for ...
- Unreal开发HTC Vive程序,开启VR编辑模式
新建项目模板有个VirtualReality 调试的时候,Play按钮下拉有个VR Preview 打开VR模式,在我现在用的4.15.0版本,VR编辑模式还是预览功能,可以在“编辑器偏好设置”-“试 ...
- C语言条件运算符
如果希望获得两个数中最大的一个,可以使用 if 语句,例如: if(a>b){ max = a; }else{ max = b; } 不过,C语言提供了一种更加简单的方法,叫做条件运算符,语法格 ...
- 四个dos命令检查你的电脑是否中木马
一些基本的命令往往可以在保护网络安全上起到很大的作用,下面几条命令的作用就非常突出. 命令是再CMD中输入,不是运行框中 一.检测网络连接 如果你怀疑自己的计算机上被别人安装了木马,或者是中了病毒,但 ...
- 第一次广搜!HDU1548--A Strange Lift
一上来看见题目就用了深搜(因为只会深搜)果断内存超限(据说时间也会超限)无奈只好开始用广搜 其实广搜的思路和深搜有很多类似的地方 不过实现的过程中用到了队列 因此有点难以理解(好吧我个人认为) 这题是 ...
- centos-iptables-scripts
author:headsen chen date:2018-06-04 11:20:38 notice:This article is created by headsen chen himsel ...
- Eclipse 安装更多版本SDK
暂时记下,实在没时间测试了... 安卓应用开发之查eclipse版本号和添加ADT.SDK https://jingyan.baidu.com/article/b0b63dbfc5f49b4a4830 ...