字典树(Tire树)

Tire树(字典树)的基本操作 Tire树的基本原理:     Tire树是一种树形结构,因其是词典的一种存储方式,故又叫字典树。词典中的每一个单 词在tire树中表现为一条从根结点出发的路径,路径边上的点连起来就是一颗tire树,如右图: 其中含有ab,abc,bac,bbc,ca五个单词。     Tire树的基本性质可以归纳为: (1)根结点不包含字符,其他的每一个节点只包含一个字符; (2)从根结点到 阅读详情

引:假如有n(n很大)个字符串,有q个查询,每个查询表示在这n个串里面是否存在这个要查询的串。一种方法就是直接暴力查找,但是复杂度很高,稍微优化一点的方法是先把n个串排序,然后二分查找,但复杂度仍可以优化,hash或者字典树都可以,这里介绍字典树。

字典树是一颗树,每个节点都有多个子节点,子节点的数量取决于字符的范围,比如如果只有小写字母子节点就有26个就足够了,例如对于这六个字符串:ab, ada, bfg, ehn, eb, adp所构成的字典树如下:
这里写图片描述
注意红色部分是字典树的精华,对于ada和adp这两个字符串相同的前缀不会重复保存,即字典树不会重复保存没用的字符。
每个节点有些空节点就不画出来了,这里限制字符仅有小写字母,即每个节点有26个子节点,下标对应为0:a, 1:b, 2:c…………..

const int tp = 27;   ///字符范围
struct node {
    char val;     /// 当前节点的字符
    bool ifc;     ///  这个节点是否是字符串的结束位置
    struct node *next[tp];  ///子节点
} *root;  /// root是字典树的根节点

然后首先需要把n个字符串全部加入到字典树中才能够进行查询,插入操作很简单,只需要顺着树进行就可以了。

node* getNewNode() {   ///生成新节点
    node *p = new node;
    for (int i = 0; i < tp; ++i) p->next[i] = NULL;
    p->val = 0;
    p->ifc = false;
}

void Insert(char *str) {
    node *p = root;  ///注意不要直接操作根节点
    for (int i = 0; i < strlen(str); ++i) {
        int tmp = str[i] - 'a';   ///获取下标
        if (!p->next[tmp]) p->next[tmp] = getNewNode(); ///如果该节点为空则需要新建节点来延伸字典树
        p = p->next[tmp];   ///传递到下一节点
    }
    p->ifc = true;  ///注意在结束位置打上标记
}

然后剩下的查找标记只需要顺着根节点来一步一步往下走就可以了

bool Find(char *str) {
    node *rt = root;  ///注意不要直接操作根节点
    for (int i = 0; i < strlen(str); ++i) {
        int tmp = str[i] - 'a';
        if (rt->next[tmp]) rt = rt->next[tmp];
        else return false;
    }
    return rt->ifc;
}

附总代码:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1000 + 7;
const int INF = ~0U >> 1;
const int tp = 27;

typedef long long LL;

struct node {
    char val;
    bool ifc;
    struct node *next[tp];
} *root;

char s[maxn];
int n, q;

node* getNewNode() {
    node *p = new node;
    for (int i = 0; i < tp; ++i) p->next[i] = NULL;
    p->val = 0;
    p->ifc = false;
}

void Insert(char *str) {
    node *p = root;
    for (int i = 0; i < strlen(str); ++i) {
        int tmp = str[i] - 'a';
        if (!p->next[tmp]) p->next[tmp] = getNewNode();
        p = p->next[tmp];
    }
    p->ifc = true;
}

void Delete(node *rt) {
    for (int i = 0; i < tp; ++i)
        if (rt->next[i]) Delete(rt->next[i]);
    delete rt;
}

bool Find(char *str) {
    node *rt = root;
    for (int i = 0; i < strlen(str); ++i) {
        int tmp = str[i] - 'a';
        if (rt->next[tmp]) rt = rt->next[tmp];
        else return false;
    }
    return rt->ifc;
}

int main() {
    root = getNewNode();
    scanf("%d%d", &n, &q);
    for (int i = 0; i < n; ++i) {
        scanf("%s", s);
        Insert(s);
    }
    for (int i = 0; i < q; ++i) {
        scanf("%s", s);
        if (Find(s)) printf("YES\n");
        else printf("NO\n");
    }
    Delete(root);
    return 0;
}

在字符集很大的情况下就不能用上述这种方式进行建树了,会爆内存。这里介绍一个字典树的另一种写法,写的比较挫,见谅。
左儿子右兄弟的写法,即lc指针指的是这个节点的儿子指针,rc指的是这个节点的兄弟节点。
如图:
这里写图片描述
图做的有点low。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>

using namespace std;

const int maxn = 100 + 7;

struct node {
    struct node *lc, *rc;
    bool ifc;
    char ch;
};

struct node *root;
int flag[maxn];

node *getNewNode() {
    struct node *q = new node;
    q->ifc = false;
    q->lc = q->rc = NULL;
    return q;
}

void Insert(char *s) {
    int len = strlen(s);
    struct node *p = root;
    for (int i = 0; i < len; ++i) {
        struct node *q, *tmp;
        bool ok = false;
        for (q = p->lc; q; q = q->rc) {
            if (q->rc == NULL) tmp = q;
            if (q->ch == s[i]) {
                ok = true;
                break;
            }
        }
        if (!ok) {
            if (q == p->lc) {
                q = getNewNode();
                q->ch = s[i];
                p->lc = q;
            } else {
                q = getNewNode();
                q->ch = s[i];
                tmp->rc = q;
            }
        }
        p = q;
    }
    p->ifc = true;
}

bool Find(char *s) {
    int len = strlen(s);
    struct node *p = root;
    for (int i = 0; i < len; ++i) {
        bool ok = false;
        node *q;
        for (q = p->lc; q; q = q->rc)
            if (q->ch == s[i]) {
                ok = true;
                break;
            }
        if (!ok) return false;
        p = q;
    }
    return p->ifc;
}

int n, m;
char str[maxn];

int main() {
    root = new node;
    root->ifc = false;
    root->lc = root->rc = NULL;
    root->ch = 0;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; ++i) {
        scanf("%s", str);
        Insert(str);
    }
    for (int i = 0; i < m; ++i) {
        scanf("%s", str);
        printf("%s\n", Find(str) ? "YES" : "NO");
    }
    return 0;
}
C++高级数据结构算法 | Tire树(字典树、前缀树) Trie树的基本概念与应用场景、 Trie树的结构定义、单词插入操作、单词查找操作、前缀查询、删除算法、销毁操作、 LeetCode 208 实现 Trie (前缀树) 题解 阅读详情

相关推荐

字典树算法 c语言实现

用C语言实现的字典树算法,用C语言实现的字典树算法。

Tire树(字典树)

1.1、什么是Trie树   Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。   Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。 它有3个基本性质: 根节点不包含字符,除根节点外每一个节点都只包含一个字符。 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应

qigaohua的博客 2317

FLoRA: 基于异构低秩适应的联邦微调大语言模型

大语言模型(LLMs)的快速发展推动了人工智能的进步,预训练的LLMs可以通过微调适应各种下游任务。联邦学习(FL)通过利用客户端的本地数据进行原位计算,进一步增强了隐私保护的微调,消除了数据移动的需求。然而,考虑到LLMs的巨大参数量,微调LLMs对于资源受限且异构的FL客户端来说是一个挑战。之前的方法采用了低秩适应(LoRA)进行高效的联邦微调,但在LoRA适配器上使用了传统的FL聚合策略。这些方法导致了数学上不准确的聚合噪声,降低了微调效果,并且未能解决异构LoRA的问题。

tiger00O的博客 2065

acwing.835.Trie字符串统计

Trie字符串统计 维护一个字符串集合,支持两种操作: I x 向集合中插入一个字符串 x; Q x 询问一个字符串在集合中出现了多少次。 共有 N 个操作,输入的字符串总长度不超过 105,字符串仅包含小写英文字母。 输入格式 第一行包含整数 N,表示操作数。 接下来 N 行,每行包含一个操作指令,指令为 I x 或 Q x 中的一种。 输出格式 对于每个询问指令 Q x,都要输出一个整数作为结果,表示 x 在集合中出现的次数。 每个结果占一行。 数据范围 1≤N≤2∗104 输入样例: 5 I abc

qq_47997583的博客 667

UE5 VlcMedia 插件编译与流媒体播放实战

本文详细介绍了在虚幻引擎5中编译并集成VlcMedia插件以解决流媒体播放难题的实战指南。针对UE5不再默认支持Win32 API导致的编译错误,文章提供了核心的构建配置文件修改步骤,并指导如何启用插件、创建VLC媒体播放器,最终成功播放如.m3u8等格式的网络直播流或点播视频。

weixin_29013129的博客 339

mipi协议中的calibration和scramble模式

在MIPI(Mobile Industry Processor Interface)协议中,calibration(校准)和scramble(加扰)模式是两个重要的特性,它们分别用于优化数据传输的准确性和减少信号干扰。

flomingo1的专栏 2401

字典树两种写法....

题目很简单 给定电话号码,然后看较短的号码是不是较长的号码的前缀,如果是的话就输出NO,否则就输出YES,当然相同也不可以存在,用普通写法一直超时。。。 每次用链表申请空间都很费时,以后最好用数组吧。。 代码如下 #include #include //时间复杂度与单词长度有关 //空间复杂度最坏为单词长度总和*10 //自动补全可以用字典树完成 struct no

有梦想的蜗牛 551

Google账号找回通用方法(尤其是知道账号密码仍无法登录和找回的)

Google账号找回通用方法【尤其是知道账号密码仍无法登录和找回的】普通找回注意:适用于常用谷歌账户的设备和网络情况下无法使用手机或辅助邮箱验证码进行密码找回特殊找回方法注意;适用于1.新的设备以及网络环境(包括由于非正常原因导致设备系统以及应用信息变更)2.没有开启辅助验证(手机/邮箱)3.知道账号密码但无法登录或找回。通过申诉进行找回 普通找回 注意:适用于 常用谷歌账户的设备和网络情况下 无法使用手机或辅助邮箱验证码进行密码找回 通过恢复页面进行恢复 https://accounts.google

极客代码-极致生活 23万+

Tire树(字典树-字符串快速查找)

Tire树又称字典树或前缀树,是一种能够快速查找一组字符串含有一个字符串的类似哈希表的树结构,是以空间换时间,利用字符串的前缀来降低查询时间。

qq_46056407的博客 3905

Android车载桌面开发实战:从CarLauncher源码解析到自定义Launcher开发(Android 11)

本文深入解析了Android 11中CarLauncher的源码架构与核心模块,并提供了从零开始定制开发车载Launcher的完整实战指南。内容涵盖车载桌面的独特定位、驾驶场景优化、多屏协同、动态内容嵌入等核心挑战,以及如何构建符合安全规范、体验流畅的自定义车载桌面应用,是车载应用开发者提升系统级定制能力的实用参考。

weixin_29266647的博客 516

惊爆揭秘!异步启动永磁同步电机,调速核心技术大起底

传统的同步启动方式需要额外的同步设备,成本高且维护复杂。异步启动PMSM则巧妙地利用了鼠笼感应电机的启动原理,无需额外同步设备即可实现安全可靠的启动。其核心思想是将定子电流分解为两个正交的分量:磁链分量(id)和转矩分量(iq),分别控制这两个分量,从而实现对电机转矩的精确控制。随着电机设计技术的不断进步和控制算法的不断优化,异步启动PMSM的性能将得到进一步提升,应用范围也将更加广泛。异步启动PMSM的调速技术是其核心技术之一,直接影响着电机的性能和应用范围。

wen8789的博客 983

Tire树(字典树)

from:https://www.cnblogs.com/justinh/p/7716421.html Trie,又经常叫前缀树,字典树等等。它有很多变种,如后缀树,Radix Tree/Trie,PATRICIA tree,以及bitwise版本的crit-bit tree。当然很多名字的意义其实有交叉。 定义 在计算机科学中,trie,又称前缀树或字典树,是一种有序树,用于保存关...

weixin_30251829的博客 761

五、MT8168 音频驱动之SPEAKER

本章主要讲解MT8168平台的内部SPEAKER驱动配置。分为HP接法和LINE OUT接法。2.1.3 audio_custom_exp.h设置。2.1.4 mixer_paths.xml设置。2.2.3 mixer_paths.xml设置。2.1.2 ProjectConfig 设置。2.2.2 ProjectConfig 设置。2.2.1 deconfig设置。2.1.1 DTS设置。......

Joon2020的博客 1664

海量数据处理之Tire树(字典树)

参考博文:http://blog.youkuaiyun.com/v_july_v/article/details/6897097 第一部分、Trie树 1.1、什么是Trie树     Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较

田原的学习笔记 3万+

量化交易零基础入门教程

特点 从零开始教编程。靠谱的量化交易学习资源稀少,且具有不讲编程、代码较难、过多等不适合新手等问题,本教程中则会从零开始教编程,解决量化入门过难过编程门槛这一问题。 量化与编程相结合。本教程不仅会教编程,而且会尽量结合量化情景,减少“我要做量化交易为什么要看这些用来培训程序员的东西”的愤懑。 简易精炼,快速入门。尽量只讲最核心最常用的知识,助你快速摆脱想学习量化却处处陌生不知所措的茫然的新手阶段。 读前说明 文后会有自测与自学,包括一些额外的延伸自学内容以及稍有难度的自测题目。 最最最基础的股票.

JanLEE 2886

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

字典树(tire树)

字典树功能: 1、维护字符串集合(即字典)。 2、向字符串集合中插入字符串(即建树)。 3、查询字符串集合中是否有某个字符串(即查询)。 4、统计字符串在集合中出现的个数(即统计)。 5、将字符串集合按字典序排序(即字典序排序)。 6、求集合内两个字符串的LCP(Longest Common Prefix,最长公共前缀)(即求最长公共前缀)。 模板: HDU1251 #include<iostream> #include &lt..

qq_55788328的博客 2323

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Tire 树(字典树/前缀树)

本文介绍了Trie树(字典树)的基本概念及其应用。Trie树是一种用于高效存储和查询字符串集合的数据结构,通过共享前缀来节省空间。文章提供了两个典型模板题:1)字符串统计(AcWing 835),实现插入和查询操作;2)最大异或对(AcWing 143),利用Trie树存储二进制数进行高效异或计算。两个示例均包含完整代码实现,展示了Trie树在处理字符串和二进制数据时的应用技巧。

2401_86095880的博客 422

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Tire 字典树、前缀树

字典树(又称单词查找树或Trie树)是一种树形结构,它是哈希树的变种,通常用于统计、排序和保存大量的字符串(但不仅限于字符串)。字典树在搜索引擎系统中常用于文本词频统计。它的主要优点在于能够利用字符串的公共前缀来减少查询时间,从而最大限度地减少无谓的字符串比较,因此查询效率通常比哈希树高。字典树的基本操作包括查找、插入和删除,但删除操作相对较少见。在查找操作中,通常从根节点开始,依次搜索关键词的每个字母,直到找到对应的节点或确定关键词不存在于树中。

Cobrander2_0的博客 533

poj 2001 Shortest Prefixes(Tire树/字典树)

poj 2001 Shortest Prefixes(Tire树/字典树)

PKU_ZZY的博客 770

TIRE 前缀树(字典树)

在计算机科学中,前缀树又称字典树(tire—源自于retrieval),是一种有序树。它用于保存关联数组,其中的键通常是字符串。

weixin_45115771的博客 668

java tire树_从leetcode386理解字典树Tire

LeetCode386 - LexicogarphicalNumbers​ 记录详细的思考过程,从此题加深对相关数据结构的理解,记录总结自己的思维误区。审题Given an integer n, return 1 - n in lexicographical order. For example, given 13, return: [1,10,11,12,13,2,3,4,5,6,7,8,9]....

weixin_32803963的博客 203
上一篇: HDU 5861 Road(线段树)
下一篇: 伸展树(splay树)
THE___BEST
博客等级 码龄12年 10粉丝 85原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值