javascript trie前缀树使用详解

这次给大家带来javascript trie前缀树使用详解,使用javascript trie前缀树的注意事项有哪些,下面就是实战案例,一起来看一下。

引子

Trie树(来自单词retrieval),又称前缀字,单词查找树,字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构。

它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。

Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。

Trie树也有它的缺点, 假定我们只对字母与数字进行处理,那么每个节点至少有52+10个子节点。为了节省内存,我们可以用链表或数组。在JS中我们直接用数组,因为JS的数组是动态的,自带优化。

javascript trie前缀树使用详解

基本性质

根节点不包含字符,除根节点外的每一个子节点都包含一个字符

从根节点到某一节点。路径上经过的字符连接起来,就是该节点对应的字符串

每个节点的所有子节点包含的字符都不相同

程序实现

// by 司徒正美class Trie { constructor() {  this.root = new TrieNode(); } isValid(str) {  return /^[a-z1-9]+$/i.test(str); } insert(word) {  // addWord  if (this.isValid(word)) {   var cur = this.root;   for (var i = 0; i < word.length; i++) {    var c = word.charCodeAt(i);    c -= 48; //减少”0“的charCode    var node = cur.son[c];    if (node == null) {     var node = (cur.son[c] = new TrieNode());     node.value = word.charAt(i);     node.numPass = 1; //有N个字符串经过它    } else {     node.numPass++;    }    cur = node;   }   cur.isEnd = true; //樯记有字符串到此节点已经结束   cur.numEnd++; //这个字符串重复次数   return true;  } else {   return false;  } } remove(word){   if (this.isValid(word)) {     var cur = this.root;     var array = [], n = word.length     for (var i = 0; i < n; i++) {       var c = word.charCodeAt(i);       c = this.getIndex(c)       var node = cur.son[c];       if(node){         array.push(node)         cur = node       }else{         return false       }      }     if(array.length === n){       array.forEach(function(){         el.numPass--       })       cur.numEnd --       if( cur.numEnd == 0){         cur.isEnd = false       }      }   }else{     return false   } } preTraversal(cb){//先序遍历    function preTraversalImpl(root, str, cb){       cb(root, str);      for(let i = 0,n = root.son.length; i < n; i ++){        let node = root.son[i];        if(node){          preTraversalImpl(node, str + node.value, cb);        }      }    }     preTraversalImpl(this.root, "", cb);  } // 在字典树中查找是否存在某字符串为前缀开头的字符串(包括前缀字符串本身) isContainPrefix(word) {  if (this.isValid(word)) {   var cur = this.root;   for (var i = 0; i < word.length; i++) {    var c = word.charCodeAt(i);    c -= 48; //减少”0“的charCode    if (cur.son[c]) {     cur = cur.son[c];    } else {     return false;    }   }   return true;  } else {   return false;  } } isContainWord(str) {  // 在字典树中查找是否存在某字符串(不为前缀)  if (this.isValid(word)) {   var cur = this.root;   for (var i = 0; i < word.length; i++) {    var c = word.charCodeAt(i);    c -= 48; //减少”0“的charCode    if (cur.son[c]) {     cur = cur.son[c];    } else {     return false;    }   }   return cur.isEnd;  } else {   return false;  } } countPrefix(word) {  // 统计以指定字符串为前缀的字符串数量  if (this.isValid(word)) {   var cur = this.root;   for (var i = 0; i < word.length; i++) {    var c = word.charCodeAt(i);    c -= 48; //减少”0“的charCode    if (cur.son[c]) {     cur = cur.son[c];    } else {     return 0;    }   }   return cur.numPass;  } else {   return 0;  } } countWord(word) {  // 统计某字符串出现的次数方法  if (this.isValid(word)) {   var cur = this.root;   for (var i = 0; i < word.length; i++) {    var c = word.charCodeAt(i);    c -= 48; //减少”0“的charCode    if (cur.son[c]) {     cur = cur.son[c];    } else {     return 0;    }   }   return cur.numEnd;  } else {   return 0;  } }}class TrieNode { constructor() {  this.numPass = 0;//有多少个单词经过这节点  this.numEnd = 0; //有多少个单词就此结束  this.son = [];  this.value = ""; //value为单个字符  this.isEnd = false; }}

我们重点看一下TrieNode与Trie的insert方法。 由于字典树是主要用在词频统计,因此它的节点属性比较多, 包含了numPass, numEnd但非常重要的属性。

insert方法是用于插入重词,在开始之前,我们必须判定单词是否合法,不能出现 特殊字符与空白。在插入时是打散了一个个字符放入每个节点中。每经过一个节点都要修改numPass。

优化

现在我们每个方法中,都有一个c=-48的操作,其实数字与大写字母与小写字母间其实还有其他字符的,这样会造成无谓的空间的浪费

// by 司徒正美getIndex(c){   if(c < 58){//48-57     return c - 48   }else if(c  97      return c - 97 + 26+ 11   } }

然后相关方法将c-= 48改成c = this.getIndex(c)即可

测试

var trie = new Trie();   trie.insert("I");   trie.insert("Love");   trie.insert("China");   trie.insert("China");   trie.insert("China");   trie.insert("China");   trie.insert("China");   trie.insert("xiaoliang");   trie.insert("xiaoliang");   trie.insert("man");   trie.insert("handsome");   trie.insert("love");   trie.insert("Chinaha");   trie.insert("her");   trie.insert("know");   var map = {}  trie.preTraversal(function(node, str){    if(node.isEnd){     map[str] = node.numEnd    }  })  for(var i in map){    console.log(i+" 出现了"+ map[i]+" 次")  }  console.log("包含Chin(包括本身)前缀的单词及出现次数:");   //console.log("China")  var map = {}  trie.preTraversal(function(node, str){    if(str.indexOf("Chin") === 0 && node.isEnd){      map[str] = node.numEnd    }   })  for(var i in map){    console.log(i+" 出现了"+ map[i]+" 次")  }

javascript trie前缀树使用详解

Trie树和其它数据结构的比较

Trie树与二叉搜索树

二叉搜索树应该是我们最早接触的树结构了,我们知道,数据规模为n时,二叉搜索树插入、查找、删除操作的时间复杂度通常只有O(log n),最坏情况下整棵树所有的节点都只有一个子节点,退变成一个线性表,此时插入、查找、删除操作的时间复杂度是O(n)。

通常情况下,Trie树的高度n要远大于搜索字符串的长度m,故查找操作的时间复杂度通常为O(m),最坏情况下的时间复杂度才为O(n)。很容易看出,Trie树最坏情况下的查找也快过二叉搜索树。

文中Trie树都是拿字符串举例的,其实它本身对key的适宜性是有严格要求的,如果key是浮点数的话,就可能导致整个Trie树巨长无比,节点可读性也非常差,这种情况下是不适宜用Trie树来保存数据的;而二叉搜索树就不存在这个问题。

Trie树与Hash表

考虑一下Hash冲突的问题。Hash表通常我们说它的复杂度是O(1),其实严格说起来这是接近完美的Hash表的复杂度,另外还需要考虑到hash函数本身需要遍历搜索字符串,复杂度是O(m)。在不同键被映射到“同一个位置”(考虑closed hashing,这“同一个位置”可以由一个普通链表来取代)的时候,需要进行查找的复杂度取决于这“同一个位置”下节点的数目,因此,在最坏情况下,Hash表也是可以成为一张单向链表的。

Trie树可以比较方便地按照key的字母序来排序(整棵树先序遍历一次就好了),这跟绝大多数Hash表是不同的(Hash表一般对于不同的key来说是无序的)。

在较理想的情况下,Hash表可以以O(1)的速度迅速命中目标,如果这张表非常大,需要放到磁盘上的话,Hash表的查找访问在理想情况下只需要一次即可;但是Trie树访问磁盘的数目需要等于节点深度。

很多时候Trie树比Hash表需要更多的空间,我们考虑这种一个节点存放一个字符的情况的话,在保存一个字符串的时候,没有办法把它保存成一个单独的块。Trie树的节点压缩可以明显缓解这个问题,后面会讲到。

Trie树的改进

按位Trie树(Bitwise Trie)

原理上和普通Trie树差不多,只不过普通Trie树存储的最小单位是字符,但是Bitwise Trie存放的是位而已。位数据的存取由CPU指令一次直接实现,对于二进制数据,它理论上要比普通Trie树快。

节点压缩。

分支压缩:对于稳定的Trie树,基本上都是查找和读取操作,完全可以把一些分支进行压缩。例如,前图中最右侧分支的inn可以直接压缩成一个节点“inn”,而不需要作为一棵常规的子树存在。Radix树就是根据这个原理来解决Trie树过深问题的。

节点映射表:这种方式也是在Trie树的节点可能已经几乎完全确定的情况下采用的,针对Trie树中节点的每一个状态,如果状态总数重复很多的话,通过一个元素为数字的多维数组(比如Triple Array Trie)来表示,这样存储Trie树本身的空间开销会小一些,虽说引入了一张额外的映射表。

前缀树的应用

前缀树还是很好理解,它的应用也是非常广的。

(1)字符串的快速检索

字典树的查询时间复杂度是O(logL),L是字符串的长度。所以效率还是比较高的。字典树的效率比hash表高。

(2)字符串排序

从上图我们很容易看出单词是排序的,先遍历字母序在前面。减少了没必要的公共子串。

(3)最长公共前缀

inn和int的最长公共前缀是in,遍历字典树到字母n时,此时这些单词的公共前缀是in。

(4)自动匹配前缀显示后缀

我们使用辞典或者是搜索引擎的时候,输入appl,后面会自动显示一堆前缀是appl的东东吧。那么有可能是通过字典树实现的,前面也说了字典树可以找到公共前缀,我们只需要把剩余的后缀遍历显示出来即可。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相信看了本文案例你已经掌握了方法,更多精彩请关注创想鸟其它相关文章!

推荐阅读:

Angular2 父子组件通信方式

jQuery代码优化方式的总结

360浏览器兼容模式的页面显示不全怎么处理

立即学习“Java免费学习笔记(深入)”;

以上就是javascript trie前缀树使用详解的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1609796.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月24日 00:59:09
下一篇 2025年12月24日 00:59:30

相关推荐

  • 深入理解CSS框架与JS之间的关系

    深入理解CSS框架与JS之间的关系 在现代web开发中,CSS框架和JavaScript (JS) 是两个常用的工具。CSS框架通过提供一系列样式和布局选项,可以帮助我们快速构建美观的网页。而JS则提供了一套功能强大的脚本语言,可以为网页添加交互和动态效果。本文将深入探讨CSS框架和JS之间的关系,…

    2025年12月24日
    000
  • 项目实践:如何结合CSS和JavaScript打造优秀网页的经验总结

    项目实践:如何结合CSS和JavaScript打造优秀网页的经验总结 随着互联网的快速发展,网页设计已经成为了各行各业都离不开的一项技能。优秀的网页设计可以给用户留下深刻的印象,提升用户体验,增加用户的黏性和转化率。而要做出优秀的网页设计,除了对美学的理解和创意的运用外,还需要掌握一些基本的技能,如…

    2025年12月24日
    200
  • 学完HTML和CSS之后我应该做什么?

    网页开发是一段漫长的旅程,但是掌握了HTML和CSS技能意味着你已经赢得了一半的战斗。这两种语言对于学习网页开发技能来说非常重要和基础。现在不可或缺的是下一个问题,学完HTML和CSS之后我该做什么呢? 对这些问题的答案可以分为2-3个部分,你可以继续练习你的HTML和CSS编码,然后了解在学习完H…

    2025年12月24日
    000
  • 聊聊怎么利用CSS实现波浪进度条效果

    本篇文章给大家分享css 高阶技巧,介绍一下如何使用css实现波浪进度条效果,希望对大家有所帮助! 本文是 CSS Houdini 之 CSS Painting API 系列第三篇。 现代 CSS 之高阶图片渐隐消失术现代 CSS 高阶技巧,像 Canvas 一样自由绘图构建样式! 在上两篇中,我们…

    2025年12月24日 好文分享
    200
  • 巧用距离、角度及光影制作炫酷的 3D 文字特效

    如何利用 css 实现3d立体的数字?下面本篇文章就带大家巧用视觉障眼法,构建不一样的 3d 文字特效,希望对大家有所帮助! 最近群里有这样一个有意思的问题,大家在讨论,使用 CSS 3D 能否实现如下所示的效果: 这里的核心难点在于,如何利用 CSS 实现一个立体的数字?CSS 能做到吗? 不是特…

    2025年12月24日 好文分享
    000
  • CSS高阶技巧:实现图片渐隐消的多种方法

    将专注于实现复杂布局,兼容设备差异,制作酷炫动画,制作复杂交互,提升可访问性及构建奇思妙想效果等方面的内容。 在兼顾基础概述的同时,注重对技巧的挖掘,结合实际进行运用,欢迎大家关注。 正文从这里开始。 在过往,我们想要实现一个图片的渐隐消失。最常见的莫过于整体透明度的变化,像是这样: 立即学习“前端…

    2025年12月24日 好文分享
    000
  • css实现登录按钮炫酷效果(附代码实例)

    今天在网上看到一个炫酷的登录按钮效果;初看时感觉好牛掰;但是一点一点的抛开以后发现,并没有那么难;我会将全部代码贴出来;如果有不对的地方,大家指点一哈。 分析 我们抛开before不谈的话;其实原理和就是通过背景大小以及配合位置达到颜色渐变的效果。 text-transform: uppercase…

    2025年12月24日
    000
  • CSS flex布局属性:align-items和align-content的区别

    在用flex布局时,发现有两个属性功能好像有点类似:align-items和align-content,乍看之下,它们都是用于定义flex容器中元素在交叉轴(主轴为flex-deriction定义的方向,默认为row,那么交叉轴跟主轴垂直即为column,反之它们互调,flex基本的概念如下图所示)…

    2025年12月24日 好文分享
    000
  • 手把手教你用 transition 实现短视频 APP的点赞动画

    怎么使用纯 css 实现有趣的点赞动画?下面本篇文章就带大家了解一下巧妙借助 transition实现点赞动画的方法,希望对大家有所帮助! 在各种短视频界面上,我们经常会看到类似这样的点赞动画: 非常的有意思,有意思的交互会让用户更愿意进行互动。 那么,这么有趣的点赞动画,有没有可能使用纯 CSS …

    2025年12月24日 好文分享
    000
  • 巧用CSS实现各种奇形怪状按钮(附代码)

    本篇文章带大家看看怎么使用 CSS 轻松实现高频出现的各类奇形怪状按钮,希望对大家有所帮助! 怎么样使用 CSS 实现一个内切角按钮呢、怎么样实现一个带箭头的按钮呢? 本文基于一些高频出现在设计稿中的,使用 css 实现稍微有点难度和技巧性的按钮,讲解使用 css 如何尽可能的实现它们。【推荐学习:…

    2025年12月24日 好文分享
    000
  • 原来利用纯CSS也能实现文字轮播与图片轮播!

    怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯css也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助! 今天,分享一个实际业务中能够用得上的动画技巧。【推荐学习:css视频教程】 巧用逐帧动画,配合补间动画实现一个无限循环的轮播效果,像是这样: 立即学习“前端…

    2025年12月24日 好文分享
    000
  • HTML+CSS+JS实现雪花飘扬(代码分享)

    使用html+css+js如何实现下雪特效?下面本篇文章给大家分享一个html+css+js实现雪花飘扬的示例,希望对大家有所帮助。 很多南方的小伙伴可能没怎么见过或者从来没见过下雪,今天我给大家带来一个小Demo,模拟了下雪场景,首先让我们看一下运行效果 可以点击看看在线运行:http://hai…

    2025年12月24日 好文分享
    500
  • 总结整理:需要避坑的五大常见css错误(收藏)

    本篇文章给大家总结5个最常见的css错误,并介绍一下避坑方法,希望对大家有所帮助! 正如我们今天所知,CSS语言是web的一个重要组成部分。它使我们有能力绘制元素在屏幕、网页或其他媒体中的展示方式。 它简单、强大,而且是声明式的。我们可以很容易地实现复杂的事情,如暗黑/光明模式。然而,对它有很多误解…

    2025年12月24日
    000
  • CSS+JS实现爱心点赞按钮(代码示例)

    本篇文章给大家介绍一下css+js实现一个“爱之满满”点赞按钮的方法,希望对大家有所帮助! 前段时间在看一档说唱节目,被里面的一个说唱歌手JBcob的爱之满满这句词给洗脑了。 于是这次给大家带来一个爱之满满的点赞按钮,让大家在点赞的同时还能感受到被爱包裹的感觉。 立即学习“前端免费学习笔记(深入)”…

    2025年12月24日 好文分享
    000
  • 让人眼前一亮的五个前端小技巧

    为了让大家编程更轻松一些,本挑选一些有用的但相对比较少见有用的技巧。废话不多说,开车了。 1.快速隐藏 要隐藏一个DOM元素,不需要JavaScript。一个原生的HTML属性就足以隐藏。其效果类似于添加一个style display: none;。 该段落在页面上是不可见的,它对HTML是隐藏的。…

    2025年12月24日
    000
  • 10款好看且实用的文字动画特效,让你的页面更吸引人!

    图片和文字是网页不可缺少的组成部分,图片运用得当可以让网页变得生动,但普通的文字不行。那么就可以给文字添加一些样式,实现一下好看的文字效果,让页面变得更交互,更吸引人。下面创想鸟就来给大家分享10款文字动画特效,好看且实用,快来收藏吧! 1、网页玻璃文字动画特效 模板简介:使用css3制作网页渐变底…

    2025年12月24日 好文分享
    000
  • 如何实现炫酷的数字大屏

    依托强大无远开发平台,可以快速实现带各种酷炫联动效果的数字化大屏。一起来看一下吧 DEMO 地址:https://previewer.wuyuan.io/p… 配置地址:https://workbench.wuyuan.io/p… 效果图 1 效果图 2 实现步骤 1. 完成…

    2025年12月24日 好文分享
    000
  • 使用JS或CSS如何实现瀑布流布局,几种方案介绍

    本篇文章带大家了解一下瀑布流布局,介绍一下三种靠谱js方案,以及n种不靠谱css方案。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 本着实用精神,我们今天来分享一下瀑布流布局(昨天有个小兄弟问我怎么做,我找了半天没找到,啊原来写在内网了)。 演示地址: http://www.li…

    2025年12月24日 好文分享
    000
  • tp5如何引入css文件

    tp5引入css文件的方法:1、将css文件放在public目录下的static文件里即可;2、在页面引入中写上“”语句即可。 本教程操作环境:windows7系统、CSS3&&HTML5版、Dell G3电脑。 其实很简单,只需要将css,js,image文件放在这个目录下即可 页…

    2025年12月24日
    000
  • 聊聊CSS 与 JS 是如何阻塞 DOM 解析和渲染的

    本篇文章给大家介绍一下css和js阻塞 dom 解析和渲染的原理。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 hello~各位亲爱的看官老爷们大家好。估计大家都听过,尽量将CSS放头部,JS放底部,这样可以提高页面的性能。然而,为什么呢?大家有考虑过么?很长一段时间,我都是知其…

    2025年12月24日
    200

发表回复

登录后才能评论
关注微信