Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[奇怪但有用的数据结构]Trie前缀树

[奇怪但有用的数据结构]Trie前缀树

原创
作者头像
杜逸先
发布于 2018-06-08 06:52:07
发布于 2018-06-08 06:52:07
2K00
代码可运行
举报
运行总次数:0
代码可运行

想象一个这样的情景,有一个很大的字典包含了很多的单词,需要判断一个新单词是否在字典中,最直接也最快的办法就是使用哈希表了。现在添加一个条件,判断字典里是否存在单词以新单词为前缀,这时候哈希表就不合适了,因为存在单词在字典中但其前缀不在字典中的情况,例如[‘apple’, 'application','append']这个字典并不包含他们的公共前缀'app','ap'和‘a’。所以我们需要一种新的数据结构和算法来处理这类问题。

很显然如果我们知道哪些单词是以字母'a'开头的,就可以很方便的判断是否有单词是以'ap'为前缀的,从而不必理会以其他字母开头的单词。再进一步,我们可以从'ap'开头的单词中找是否有单词是以‘app’为前缀的,从'ab'开头的单词中找是否有单词一'aba'为前缀。于是这样的树形结构就构造出来了。

树形结构
树形结构

我们可以很容易地看出来这棵树中包含四个单词abc, apple, bad和bat。也可以轻松判断出存在单词以'app'为前缀,而没有'ad'开头的单词。

Trie前缀树

这样的树形结构就是前缀树(Trie),也叫单词查找树,典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。它的基本性质如下:

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

构造前缀树

首先我们要定义一下节点的数据结构。每一个节点可以跟着若干个子节点,因为都是字符,所以可以用哈希表来保存子节点。并且要有一个标记来表示这个字符是不是一个单词的最后一个字符,不然以上图为例,无法知晓单词'app'是否在这个字典中。这是我设计的Node类(__repr__方法用于清晰的展示节点的结构)。

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class Node:
    def __init__(self):
        self.is_last = False
        self.children = {}
    def __repr__(self):
        return 'Node({},[{}])'.format(self.is_last, 
            ','.join('{}:{}'.format(x, repr(self.children[x])) for x in self.children))

接下来就是构造前缀树了,很自然的会有一个Node类型的根节点root:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class Trie:
    def __init__(self):
        self.root = Node()

然后是在合适的位置插入新单词(去掉已有前缀的部分):

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class Trie:
    def __init__(self):
        self.root = Node()
        
    def generate_node(self, word:str) -> Node:
        node = Node()
        if len(word) > 0:
            node.children[word[0]] = self.generate_node(word[1:])
        else:
            node.is_last = True
        return node
    

对于后续的操作(insert, search, startsWith)来说,寻找前缀是第一步,我这里使用的是一个get_node_rest方法,获得一个单词在前缀树中最长前缀的尾节点和剩余的字符。

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class Trie:
    def __init__(self):
        self.root = Node()
        
    def generate_node(self, word:str) -> Node:
        #...
        
    
    def get_node_rest(self, root:Node, word:str)-> tuple:
        if not word:
            return root, ''
        elif word[0] in root.children:
            return self.get_node_rest(root.children[word[0]], word[1:])
        else:
            return root, word

获取了一个单词的node和rest,插入操作就是在node节点插入rest部分的字符,判断是否是前缀(startsWith)就是判断rest是否为空,如果node的is_last也同时为真的话就是存在这个单词了(search)。完整的代码如下:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
#前缀树
class Node:
    def __init__(self):
        self.is_last = False
        self.children = {}
    def __repr__(self):
        return 'Node({},[{}])'.format(self.is_last,
            ','.join('{}:{}'.format(x, repr(self.children[x])) for x in self.children))

        

class Trie:
    def __init__(self):
        self.root = Node()
        
    def generate_node(self, word:str) -> Node:
        node = Node()
        if len(word) > 0:
            node.children[word[0]] = self.generate_node(word[1:])
        else:
            node.is_last = True
        return node
        
    def get_node_rest(self, root:Node, word:str)-> tuple:
        if not word:
            return root, ''
        elif word[0] in root.children:
            return self.get_node_rest(root.children[word[0]], word[1:])
        else:
            return root, word
    
    def insert(self, word):
        node, rest = self.get_node_rest(self.root, word)
        if rest:
            node.children[rest[0]] = self.generate_node(rest[1:])
        else:
            node.is_last = True
    
    def search(self, word):
        node, rest = self.get_node_rest(self.root, word)
        return rest == '' and node.is_last
    
    def startsWith(self, word):
        _, rest = self.get_node_rest(self.root, word)
        return len(rest) == 0

我们可以看一下Trie类的使用。

Trie类的使用
Trie类的使用

结语

本文简单介绍了前缀树的定义和用途,并用Python实现了一个简单的Trie类,希望能够给予大家一些启发和帮助。

最后祝大家享受生活,享受代码。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Hexo + Github Pages博客搭建教程
一直以来自己都有书写文章的习惯,不管是收集资料还是表达自己的个人见解。最开始把资料都放在印象笔记里,但是印象笔记有个不好的点就是书写不方便,而且多设备登录不友好,需要升级账户。后来就搭建了一个WordPress站点,记录自己的点滴。慢慢的接触到了CSDN,也计划着在那里写博客。CSDN的编辑器有markdown版本,接触到了markdown就对其产生了好感。与此同时,我也将我的WordPress站点的编辑器换成了markdown编辑器,一处书写多处同步。 慢慢的,我感受到了WordPress站点的臃肿,由于我的站点原因,做的并不是单独的博客站点,所有的文章展示方面不友好。所以萌生了搭建一个单独的博客的想法。
慕白
2020/01/02
9490
Hexo + Github Pages博客搭建教程
hexo + GitHub
在最后找到Github pages(我的是默认开启的,如果你不是就点击Launch automatic page generator按钮,一直下一步就行了)
FinGet
2019/06/28
5890
hexo + GitHub
个人博客搭建
  前前后后大概花了一周多的时间,目前个人博客已经完善的差不多了,现在写个文章做个阶段总结,后续如果有更新的地方,会及时补充。本博客基于Hexo框架,采用hexo-theme-matery主题,在这里非常感谢作者洪卫的hexo-blog-fly博客开源,极大简化了构建博客的工作量和复杂度。在此开源博客的基础上做了改进,修复了一些bug,顺利搭建完成了我的个人博客。大家对此主题有兴趣的可以下载源代码,搭建属于自己的个性化博客。
LuckySec
2022/11/02
2.4K0
个人博客搭建
Markdown 拓展-Hexo 搭建博客(上)
一直想搭建个人网站, 当我了解到 hexo 是一款快速、简洁且高效的博客框架,我就迫不及待想尝试下。
acc8226
2022/05/17
2850
【Hexo基本使用】零基础,快速搭建属于自己的个人博客!
Hexo⭐零基础搭建Hexo个人博客!⭐本文主题以Butterfly为例!⭐Hexo官网:HexoHexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。安装安装Node.jsHexo基于Node.js运行npm安装Hexo全局安装 hexo-clinpm install -g hexo-cli使用快速使用# 进入项目目录cd <项目名># 安装项目依赖npm install --registry=https://re
LonelySnowman
2022/12/15
6230
使用 Github 和 Hexo 快速搭建个人博客
李科慧
2017/03/27
6.3K3
基于hexo的博客项目基本操作
​ 在指定博客项目中的themes文件夹中设定指定名称的文件夹(主题名称),随后在_config.yml文件中修改theme设定(默认是landscape)
hahah
2022/06/14
7030
使用hexo在GitHub上搭建个人博客
Hexo是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。
没有故事的陈师傅
2019/07/27
6620
如何在Ubuntu 14.04上使用Hexo创建博客
Hexo是一个基于Node.js的静态博客框架。使用Hexo,您可以以博客文章的形式发布Markdown文档。博客帖子和内容被处理并转换为HTML / CSS,它来自默认或自定义模板主题文件(很像其他静态博客生成器,如Jekyll和Ghost)。Hexo中的所有软件都是模块化的,因此您可以准确安装和设置所需的软件。
木纸鸢
2018/09/25
1.3K0
从零开始搭建一个炫酷免费的个人博客
前段时间摸索了一波如何搭建一个免费的个人网站,同时发在朋友圈献丑了一波,对于大佬们来说是雕虫小技,但是对于爱学习的小伙伴很好奇,到底是怎么搞的。因为很多人都搞过,而且网上资料非常多,这里就选择小吴同(大)学(佬)制作的一个非常用心和详细的教程来分享给大家。
AI算法与图像处理
2019/10/10
2.1K0
从零开始搭建一个炫酷免费的个人博客
低成本个人建站系列二 —— 使用 Hexo+GitHub 搭建个人免费博客
GitHub Pages 是由 GitHub 官方提供的一种免费的静态站点托管服务,让我们可以在 GitHub 仓库里托管和发布自己的静态网站页面。
浩Coding
2020/09/10
2.8K0
低成本个人建站系列二 —— 使用 Hexo+GitHub 搭建个人免费博客
建站神器:Hexo+Kaze+Gitee Pages 搭建静态博客网站
建网站本身是一个很大的工程,涉及前端页面的搭建,网站数据的存储,还要购置服务器资源,甚至是后期的维护,过程相当繁琐。
蜗牛互联网
2021/02/26
1.4K0
建站神器:Hexo+Kaze+Gitee Pages 搭建静态博客网站
使用 Hexo & GitPage 搭建博客
GitPage 是个什么东西?它和 GitHub 是什么关系?Hexo 又是什么?它和 GitPage 又是什么关系?为什么我要用 Hexo + GitPage 搭建博客?这些问题在我不了解 GitPage 之前都是一堆问号,想必大多数小白都和我一样很懵,现在网上关于搭建博客的教程一大堆,但是当初我在搭建的时候照着步骤一步一步搞感觉很不爽,直到最后博客搭完了才明白以上几个问题,所以这里我想先给大家回答一下上面几个问题,然后再逐步教大家使用 Hexo + GitPage 搭建属于你自己的博客。
SkyRiN
2018/11/20
7040
Hexo博客搭建
为什么网上这么多教程,我还要在这里写下一篇呢?主要是总结大家的经验和自己的操作过程,一来是方便自己看,二来是给大家提供一些参考。Google一下,你可以找到几乎所有你想看到的,但是能否为你带来实质性的解决方案,可能也是需要花时间的。而且,跟别人做一样的操作,可能就刚好是你出了问题。。。没错,说的就是我自己。写这篇文章,仅此以纪念从WordPress转到Hexo。
Bess Croft
2020/04/03
7470
使用Hexo在github上搭建个人博客
最近正好在学习前端开发,想着搭建一个属于自己的个人博客,把自己的技能树整理整理,温故而知新。
王大锤
2018/08/13
5710
使用Hexo在github上搭建个人博客
hexo——轻量、简易、高逼格的博客
写blog虽然经历了N多不同时代的产品,恒久不变的始终是自己无人问津的网站。虽然没几个人看,还是隔断时间就要折腾一下。从最开始的wordpress,到tale,到现在的hexo,网站变得越来越简单,越来越轻量级,这里主要说说hexo的使用。
itmifen
2018/10/08
1K0
hexo——轻量、简易、高逼格的博客
博客更新-迁移博客至Hexo的艰辛
Windows下访问GitDownload下载页面(已下载可跳过) 由于下载速度可能过慢,这里给网盘下载
筱锋xiao_lfeng
2022/03/16
4680
博客更新-迁移博客至Hexo的艰辛
Linux下搭建HEXO博客教程
参考 https://segmentfault.com/a/1190000002632530
Jean
2018/10/12
3K1
Linux下搭建HEXO博客教程
博客搭建之Hexo
快速建站工具(主要适用:博客、文档等静态站点),可以将Markdown编写的文章解析成html页面。生成的站点可以无需服务器一键部署到github、gitlab或者gitee上。
前端小书童
2022/01/04
4790
博客搭建之Hexo
Hexo使用文档
安装 Hexo 完成后,请执行下列命令,Hexo 将会在指定文件夹中新建所需要的文件。
机械视角
2019/10/23
6970
相关推荐
Hexo + Github Pages博客搭建教程
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验