数据结构与算法专题——第十二题 Trie树

https://mp.weixin.qq.com/s/nndr2AcECuUatXrxd3MgCg

今天来聊一聊Trie树,Trie树的名字有很多,比如字典树,前缀树等等。

一:概念
下面有and,as,at,cn,com这几个关键词,构建成 trie 树如下。

从上面图中,应该可以或多或少的发现一些好玩的特性。

  • 根节点不包含字符,除根节点外的每一个子节点都包含一个字符。
  • 从根节点到某一节点,路径上经过的字符连接起来,就是该节点对应的字符串。
  • 每个单词的公共前缀作为一个字符节点保存。

二:使用范围

既然学Trie树,肯定要知道这玩意是用来干嘛的?

1. 词频统计。

可能有人要说了,词频统计简单啊,一个hash或者一个堆就可以打完收工,但问题来了,如果内存有限呢?还能这么玩吗?这种限制级条件下就可以用trie树来压缩下空间,因为公共前缀都是用一个节点保存的。

2. 前缀匹配

就拿上面的图来说吧,如果我想获取所有以 "a" 开头的字符串,从图中可以很明显的看到是:and,as,at,如果不用trie树,你该怎么做呢?很显然朴素的做法时间复杂度为O(N2) ,用Trie树就不一样了,它可以做到h,h为你检索单词的长度,可以说这是秒杀的效果。

举个例子:现有一个编号为1的字符串”and“,怎样插入到trie树中呢?采用动态规划的思想,将编号”1“计入到每个途径的节点中,那么以后我们要找”a“,”an“,”and"为前缀的字符串的编号将会轻而易举。

三:实际操作

到现在为止,我想大家已经对trie树有了大概的掌握,下面看看如何来实现。

1:定义trie树节点

为了方便,我也采用纯英文字母,大家都知道字母有26个,所以构建的trie树就是一个26叉树,每个节点包含26个子节点,实现代码如下:


/// <summary>
/// Trie树节点
/// </summary>
public class TrieNode
{
/// <summary>
/// 26个字符,也就是26叉树
/// </summary>
public TrieNode[] childNodes; /// <summary>
/// 词频统计
/// </summary>
public int freq; /// <summary>
/// 记录该节点的字符
/// </summary>
public char nodeChar; /// <summary>
/// 插入记录时的编码id
/// </summary>
public HashSet<int> hashSet = new HashSet<int>(); /// <summary>
/// 初始化
/// </summary>
public TrieNode()
{
childNodes = new TrieNode[26];
freq = 0;
}
}

2: 添加操作

从上面图中,应该可以或多或少的发现一些好玩的特性。

  • 根节点不包含字符,除根节点外的每一个子节点都包含一个字符。
  • 从根节点到某一节点,路径上经过的字符连接起来,就是该节点对应的字符串。
  • 每个单词的公共前缀作为一个字符节点保存。

二:使用范围

既然学Trie树,肯定要知道这玩意是用来干嘛的?

1. 词频统计。

可能有人要说了,词频统计简单啊,一个hash或者一个堆就可以打完收工,但问题来了,如果内存有限呢?还能这么玩吗?这种限制级条件下就可以用trie树来压缩下空间,因为公共前缀都是用一个节点保存的。

2. 前缀匹配

就拿上面的图来说吧,如果我想获取所有以 "a" 开头的字符串,从图中可以很明显的看到是:and,as,at,如果不用trie树,你该怎么做呢?很显然朴素的做法时间复杂度为O(N2) ,用Trie树就不一样了,它可以做到h,h为你检索单词的长度,可以说这是秒杀的效果。

举个例子:现有一个编号为1的字符串”and“,怎样插入到trie树中呢?采用动态规划的思想,将编号”1“计入到每个途径的节点中,那么以后我们要找”a“,”an“,”and"为前缀的字符串的编号将会轻而易举。

内存空间有限情况下的词频统计 Trie树 前缀树的更多相关文章

  1. 软工之词频统计器及基于sketch在大数据下的词频统计设计

    目录 摘要 算法关键 红黑树 稳定排序 代码框架 .h文件: .cpp文件 频率统计器的实现 接口设计与实现 接口设计 核心功能词频统计器流程 效果 单元测试 性能分析 性能分析图 问题发现 解决方案 ...

  2. LeetCode 80,不使用外部空间的情况下对有序数组去重

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题的第49篇文章,我们一起来看LeetCode的第80题,有序数组去重II(Remove Duplicates fr ...

  3. Linux查看磁盘目录内存空间使用情况

    du 显示每个文件和目录的磁盘使用空间 命令参数 -c或--total  除了显示个别目录或文件的大小外,同时也显示所有目录或文件的总和. -s或--summarize  仅显示总计,只列出最后加总的 ...

  4. JS如何在不给新空间的情况下给数组去重?

    1.先排序,在让相邻元素对比去重 const nums = [3, 1, 1, 5, 2, 3, 4, 3, 5, 5, 6, 4, 6, 6, 6]; Array.prototype.arrayNo ...

  5. alloc_page分配内存空间--Linux内存管理(十七)

    1 前景回顾 在内核初始化完成之后, 内存管理的责任就由伙伴系统来承担. 伙伴系统基于一种相对简单然而令人吃惊的强大算法. Linux内核使用二进制伙伴算法来管理和分配物理内存页面, 该算法由Know ...

  6. STM32内存受限情况下摄像头驱动方式与图像裁剪的选择

    1.STM32图像接收接口 使用stm32芯片,128kB RAM,512kB Rom,资源有限,接摄像头采集图像,这种情况下,内存利用制约程序设计. STM32使用DCMI接口读取摄像头,协议如下. ...

  7. 萌新笔记——linux下查看内存的使用情况

    windows上有各种软件可以进行"一键加速"之类的操作,释放掉一些内存(虽然我暂时不知道是怎么办到的,有待后续学习).而任务管理器也可以很方便地查看各进程使用的内存情况,如下图: ...

  8. linux下查看内存的使用情况

    windows上有各种软件可以进行“一键加速”之类的操作,释放掉一些内存(虽然我暂时不知道是怎么办到的,有待后续学习).而任务管理器也可以很方便地查看各进程使用的内存情况,如下图: 同样地,linux ...

  9. 简单统计SQLSERVER用户数据表大小(包括记录总数和空间占用情况)

    在SQLSERVER,简单的组合sp_spaceused和sp_MSforeachtable这两个存储过程,可以方便的统计出用户数据表的大小,包括记录总数和空间占用情况,非常实用,在SqlServer ...

随机推荐

  1. .net MVC 微信公众号 获取 access_token

    官方文档说明:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_ ...

  2. 物联网、5G世界与大数据管理

    物联网带动中国产业转型.推动社会经济发展的时代已经到来.什么是物联网?物联网又给数据管理带来了哪些挑战?面对挑战,我们有怎样的解决方案?本文中我们将一一为您揭晓.     01 物联网时代的到来   ...

  3. hibernate连接数据库中文乱码

    4.做完这两步还是不行,需要修改hibernate的配置文件hibernate.cfg.xml,在配置文件配置hibernate.connection.url属性.示例: <property n ...

  4. 【老孟Flutter】Stateful 组件的生命周期​

    老孟导读:关于生命周期的文章共有2篇,第一篇是介绍 Flutter 中Stateful 组件的生命周期. 博客地址:http://laomengit.com/blog/20201227/Statefu ...

  5. 10分钟带你入门git到github

    git的产生背景 开局先来一个故事吧,故事看完如果不想看枯燥无味的指令,没关系我已经把这篇文章的内容录制成了一个视频,点击文末阅读原文就可以观看.或者说你已经熟练掌握git的使用了,可以直接跳到总结部 ...

  6. windows 10放大125%后字体模糊(已解决)、win10 文字放大之后变模糊 解决办法

    windows 10放大125%后字体模糊解决办法 百度搜索 "Windows10_DPI_FIX" 或者用这个地址下载下载地址   https://gallery.technet ...

  7. JAVA的一些笔记

    /*一般函数与构造函数的区别 构造函数:对象创建时,就会调用与之对应的构造函数,对对象进行初始化 一般函数:对象创建时,需要函数功能时才调用 构造函数:一个对象对象创建时,只调用一次 一般函数:对象创 ...

  8. C#设计模式——建造者模式(Builder Pattern)

    1.建造者模式简介 1.1>.定义 建造者模式(Builder)将复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. 1.2>.使用频率  中低 1.3>.原型模式应用 ...

  9. js--数组的every()和some()方法检测数组是否满足条件的使用介绍

    前言 阅读本文之前先来思考一个问题,如何如实现判断一个数组中是否存在满足条件的元素,如何去判断数组中是否全部元素都满足判断条件,这里可能能想到使用for循环遍历数组,if()判断每一项是否符合条件,同 ...

  10. VUE项目性能优化实践——通过懒加载提升页面响应速度

    本文由葡萄城技术团队原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 最近我司因业务需求,需要在一个内部数据分析平台集成在线Excel功能,既然我 ...