高级数据结构与算法 | 三元搜索树(Ternary Search Tree)

news2024/11/24 7:09:01

文章目录

  • TernarySearchTree
    • 基本概念
      • 介绍
      • 原理
        • 插入
        • 查找
        • 删除
    • 代码实现

TernarySearchTree

基本概念

介绍

Ternary Search Tree(三元搜索树),它是由 Bentley 和 Sedgewick 在 1997 年提出的一种基于 Trie 的思想改良的一种数据结构,其目的在于优化 Trie 在大规模数据集下的时间、空间开销。

那么 TST 主要在哪几个方面优化呢?

  1. 子节点数:在 Trie 中,每一个节点都需要存储一个子节点指针数组,这个数组需要包含所有可能出现的字符,这就导致 Trie 的空间占用非常大,而在 TST 中,仅需要保留三个子节点指针。
  2. 字典序排列:在 Trie 中,查找时需要沿着树一直向下遍历,查询效率相对较低,而 TST 按照字典序对节点进行来排列,查找中可以依据该特点进行优化(例如使用二分查找)。

Trie 通常适用于少量字符串匹配、前缀匹配等场景,而 TST 主要应用于大量字符串查询的场景,例如搜索引擎、代码检查、自动补全。

原理

TST 的核心原理非常简单,与二叉树不同,TST 每个节点都存储着三个指向子节点的指针,这些子节点代表着查询字符串与该节点比较的结果,即:

  • 当前节点的字符小于等于查询字符串的对应字符,则搜索左子树。
  • 当前节点的字符大于等于查询字符串的对应字符,则搜索右子树。
  • 当前节点的字符等于等于查询字符串的对应字符,则搜索中子树。

插入

image-20230409021323568

首先,往一个空树中插入一个字符串 cute。

image-20230409021605221

接着,插入字符串 cup,此时对比字符 c、u 都相同,进入其中间节点,到了 t 时,由于 p 比 t 小,则将 p 插入到 t 的左子树。

image-20230409021834156

接着,插入一个字符串 he,由于 h 比 c 大,此时插入到 c 的右子树。

image-20230409022818599

接着,插入一个字符串 us,由于 u 比 c 大,进入其右子树。接着对比 h,仍然比它大,此时将 u 插入其右子树。

image-20230409023055625

插入一个 i,由于 i 比 c 大,进入其右子树。对比 h,仍然比它大,进入其左子树。对于 u,此时其比 u 小,插入左子树。

查找

接着来举几个查找的例子。image-20230409023415900

首先我们需要查找字符串 us 在不在树中,流程如下:

  1. u > c,进入其右子树。
  2. u > h,进入其右子树。
  3. u == u,进入其中子树。
  4. s == s,此时已到达叶子节点,且 us 刚好被标记为一个单词,查询成功。

删除

删除为插入的对称操作,只需要将最终找到的节点标记为 false 即可,如果是叶子节点则将其删除,这里就不过多赘述。

代码实现

TST 的原理上面已经讲过了,非常简单,这里就不过多介绍了,实现代码如下:

//
// Created by orekilee on 2023/4/8.
//

#ifndef TERNARY_SEARCH_TREE
#define TERNARY_SEARCH_TREE

#include <string>
#include <memory>

using namespace std;

class TernarySearchTreeNode {
public:
    explicit TernarySearchTreeNode(char ch) :data(ch), is_end(false), left(nullptr), right(nullptr), mid(nullptr) {}
    
    char data;
    bool is_end;
    shared_ptr<TernarySearchTreeNode> left;
    shared_ptr<TernarySearchTreeNode> right;
    shared_ptr<TernarySearchTreeNode> mid;
};

class TernarySearchTree {
public:
    TernarySearchTree() :root(make_shared<TernarySearchTreeNode>('\0')) {};

    virtual ~TernarySearchTree() = default;

    TernarySearchTree(const TernarySearchTree &) = delete;
    TernarySearchTree &operator=(const TernarySearchTree &) = delete;

    bool search(const string &str) {
        if (str.empty()) {
            return root->is_end;
        }
        return search_helper(root, str, 0);
    }

    void insert(const string &str) {
        if (str.empty()) {
            root->is_end = true;
        }
        insert_helper(root, str, 0);
    }

    void erase(const string &str) {
        if (str.empty()) {
            root->is_end = false;
        }
        erase_helper(root, str, 0);
    }

private:

    bool search_helper(shared_ptr<TernarySearchTreeNode> node, const string &str, int index) {
        if (node == nullptr) {
            return false;
        }
		
        //如果比当前字符小,则去左节点,如果大则去右节点,如果相同则去中间节点
        if (node->data > str[index]) {
            return search_helper(node->left, str, index);
        } else if (node->data < str[index]) {
            return search_helper(node->right, str, index);
        } else {
            //如果遍历完整个str,根据is_end判断是否成功查找
            if (str.size() - 1 > index) {
                return search_helper(node->mid, str, index + 1);
            } else {
                return node->is_end;
            }
        }
    }

    shared_ptr<TernarySearchTreeNode> insert_helper(shared_ptr<TernarySearchTreeNode> node, const string &str, int index) {
        if (node == nullptr) {
            node = make_shared<TernarySearchTreeNode>(str[index]);
        }

        if (node->data > str[index]) {
            node->left = insert_helper(node->left, str, index);
        } else if (node->data < str[index]) {
            node->right = insert_helper(node->right, str, index);
        } else {
            if (str.size() - 1 > index) {
                node->mid = insert_helper(node->mid, str, index + 1);
            } else {
                node->is_end = true;
            }
        }

        return node;
    }

    shared_ptr<TernarySearchTreeNode> erase_helper(shared_ptr<TernarySearchTreeNode> node, const string &str, int index) {
        if (node == nullptr) {
            return nullptr;
        }

        if (node->data > str[index]) {
            return erase_helper(node->left, str, index);
        } else if (node->data < str[index]) {
            return erase_helper(node->right, str, index);
        } else {
            if (str.size() - 1 > index) {
                return erase_helper(node->mid, str, index + 1);
            } else {
                node->is_end = false;
            }
        }
        // 如果是叶子节点,则直接删除。这里资源用智能指针管理,直接标记为空即可
        if (!node->left && !node->right && !node->mid) {
            node = nullptr;
        }
        return node;
    }

    shared_ptr<TernarySearchTreeNode> root;
};

#endif // TERNARY_SEARCH_TREE

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/424719.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【GCU体验】基于PyTorch + GCU跑通ResNet50模型并测试GCU性能

一、环境 地址&#xff1a;启智社区:https://openi.pcl.ac.cn/ 二、计算卡介绍 云燧T20是基于邃思2.0芯片打造的面向数据中心的第二代人工智能训练加速卡&#xff0c;具有模型覆盖面广、性能强、软件生态开放等特点&#xff0c;可支持多种人工智能训练场景。同时具备灵活的可…

win10 64位 环境下安装CUDA 11.8和 cuDNN v8.6.0

win10 64位 环境下安装CUDA 11.8和 cuDNN v8.6.0 1 安装 NVIDIA 显卡驱动程序 下载地址&#xff1a;http://www.nvidia.cn/Download/index.aspx?langcn ​​​​​​ 下载文件&#xff1a;531.41-desktop-win10-win11-64bit-international-nsd-dch-whql 选择适合自己电脑的显…

DeepFM论文翻译

1.摘要 为了最大化推荐系统的CTR&#xff0c;学习用户行为的复杂交叉特征很关键。 尽管有很大进步&#xff0c;现有的方法无论对低阶还是高阶的交叉特征&#xff0c;似乎还是有很强的bias, 或者需要专门的特征工程。 本文&#xff0c;我们证明了得出一个能强化高阶和低阶交叉特…

前端实现自动化测试

什么是前端测试 我们经常说的单元测试其实只是前端测试的一种。前端测试分为单元测试&#xff0c;UI 测试&#xff0c;集成测试和端到端测试。 ● 单元测试&#xff1a;是指对软件中的最小可测试单元进行检查和验证&#xff0c;通常指的是独立测试单个函数。 ● UI 测试&#…

2023美赛Y题二手帆船价格--成品论文、思路、数据、代码

2023美赛Y题二手帆船价格 第一时间在CSDN分享 最新进度在文章最下方卡片&#xff0c;加入获取一手资源&#xff1a;2023美赛Y题二手帆船价格–成品论文、思路、数据、代码 可以提供关于帆船特性的信息: BoatTrader (https://www.boattrader.com/):一个网站&#xff0c;允许您根…

WindowsGUI自动化测试项目实战+辛酸过程+经验分享

WindowsGUI自动化测试项目实战辛酸过程经验分享一、前言⚜ 起因⚜ 项目要求⚜ 预研过程⚜⚜ 框架选型⚜⚜ 关于UIaotumation框架⚜ 预研成果二、项目介绍&#x1f493; 测试对象&#x1f493; 技术栈&#x1f493; 项目框架说明三、项目展示&#x1f923; 界面实现效果&#x1…

【深度学习】windows10环境配置详细教程

【深度学习】windows10环境配置详细教程 文章目录【深度学习】windows10环境配置详细教程Anaconda31.安装Anaconda32.卸载Anaconda33.修改Anaconda3安装虚拟环境的默认位置安装cuda/cudnn1.安装合适的CUDA2.安装对应的CUDNN3.卸载CUDA/CUDNNconda虚拟环境独立安装cuda/cudnn1.搭…

随想录Day55--动态规划: 392.判断子序列 , 115.不同的子序列

392.判断子序列 思路 &#xff08;这道题也可以用双指针的思路来实现&#xff0c;时间复杂度也是O(n)&#xff09; 动态规划五部曲分析如下&#xff1a; 1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和…

基线配置管理在网络中的重要性

在网络环境中&#xff0c;配置通常被认为具有不可估量的价值&#xff0c;因为设备配置的微小变化可以在几分钟内成就或破坏整个网络基础设施。 这些配置分为两部分&#xff1a;启动配置和运行配置。在网络设备中&#xff0c;默认情况下&#xff0c;第一个配置版本被视为运行和…

el-input-number的精度问题

前言 el-input-number 饿了么的数字输入框组件&#xff0c;在项目中听常用的。而这个组件比较常用的属性就是精度设置&#xff0c;给组件添加属性precision 。 其实吧&#xff0c;之前一直没怎么研究&#xff0c;保留几位小数就直接填几就好了&#xff0c;比如保留两位小数&am…

4.mysql内置函数

目录 日期函数 字符串函数 数学函数 其它函数 日期函数 获得当前年月日:

<点云>Bin-picking数据集

题目&#xff1a;工业料仓拣选的大规模6D物体姿态估计数据集 Abstract 介绍了一种新的公共数据集&#xff0c;用于6D对象姿态估计和用于工业bin-picking的实例分割。数据集包括合成场景和真实场景。对于这两者&#xff0c;提供了包括6D姿势 (位置和方向) 的点云、深度图像和注…

【华为机试真题详解JAVA实现】—从单向链表中删除指定值的节点

目录 一、题目描述 二、解题代码 一、题目描述 输入一个单向链表和一个节点的值,从单向链表中删除等于该值的节点,删除后如果链表中无节点则返回空指针。 链表的值不能重复。 构造过程,例如输入一行数据为: 6 2 1 2 3 2 5 1 4 5 7 2 2 则第一个参数6表示输入总共6个节点,…

C++基础语法(内存管理)

我们在学习C语言的时候&#xff0c;可以在栈区中使用内存空间&#xff0c;但栈区的空间毕竟很有限而且随着栈的销毁&#xff0c;该栈里的数据都会被销毁掉。因此我们学习了堆&#xff0c;堆的空间比栈要大很多很多&#xff0c;并且堆区空间的数据&#xff0c;只要我们不主动释放…

STM32 学习笔记_2 下载,GPIO 介绍

下载 Keil 编译例程 编译两个按钮&#xff0c;一个向下是部分编译&#xff0c;两个向下箭头是全部编译。对于未编译文件两个按钮等效。 点击编译后&#xff0c;linking 是链接&#xff0c;结果里面的几个数据的意义代表大小&#xff1a; 数据类型占用Flash or SRAM说明Code…

测试:腾讯云3年轻量2核4G5M服务器CPU内存带宽流量系统盘性能

2核4G云服务器可以选择腾讯云轻量应用服务器&#xff0c;自带5M公网带宽&#xff0c;5M带宽下载速度峰值可达640KB/秒&#xff0c;系统盘为60GB SSD盘&#xff0c;每月500GB流量包&#xff0c;折合每天16GB流量&#xff0c;2核4G5M轻量服务器一年168、198元15个月、三年628元&a…

从存算分离说起:金融行业数据库分布式改造之路

从上世纪90年代正式起步至今&#xff0c;中国数据库发展已走过近30年岁月。以2000年前后为拐点&#xff0c;以MySQL为首的开源数据库&#xff0c;在互联网厂商的推动下&#xff0c;逐步进入生产业务&#xff1b;而为了使单实例能力平庸的MySQL能够满足高性能要求&#xff0c;互…

Vulnhub:Digitalworld.local (JOY)靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.130 信息收集 端口扫描 nmap -A -v -sV -T5 -p- --scripthttp-enum 192.168.111.130 使用enum4linux枚举目标smb服务&#xff0c;发现两个系统用户 enum4linux -a 192.168.111.130 ftp可以匿名登陆&#xff…

基于CH32F203利用TIM1 同时输出4通道固定PWM占空比波形

基于CH32F203利用TIM1 同时输出4通道固定PWM占空比波形&#x1f4cc;相关篇《关于CH32F203程序下载方式说明》&#x1f4cd;有关CH32F203资料手册以及SDK资料&#xff1a;https://www.wch.cn/products/CH32F103.html&#x1f334;《树莓派RP2040 100M 24通道逻辑分析仪开源项目…

相关系数python实现

皮尔逊相关系数的python实现一、相关系数公式二、python实现法1&#xff1a;直接按公式算法2&#xff1a;调用numpy中的corrcoef方法法3&#xff1a;调用scipy.stats中的pearsonr方法法4&#xff1a;调用pandas.Dataframe中的corr方法一、相关系数公式 R的值在-1和1之间&#…