go语言简单实现 前缀树(Trie)与了解基数树(Radix-Tree)

一步一步分析Gin框架路由源码及radix tree基数树 Python微信订餐小程序课程视频 https://edu.youkuaiyun.com/course/detail/36074 Python实战量化交易理财系统 https://edu.youkuaiyun.com/course/detail/35475 Gin 简介 Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance – up to 40 times fa 阅读详情

前言

目录结构

Trie 
	Trie.go
main.go

Trie 的实现

  • 实现写法, 可以参照模仿 container/list 双向链表的写法实现
  • 下面代码中使用的是 slice 存储子节点, 线性查找遍历, 后面会进行 hash优化。
package Trie

// 字典树:
/*
	1. 单词结尾表示:需要使用一个 bool 类型,辨识当前节点是否是结尾字符
		叶子结点是 单词结尾
		非叶子节点 也可能是单词的结尾
	2. 实现功能
		增加单词
		搜索单词
*/


// 定义树的节点
type Node struct {
	// 1. 保存当前字符
	C byte
	// 2. 若干个子节点
	Children []*Node
	// 3. 标识节点是否是一个单词最后的一个字符
	isWord bool
}

// 给子节点 列表添加新的节点
func (n *Node) Add(c byte) {
	// 构造节点
	node := Node{
		C: c,
	}
	// 定义的 slice 类型的,不用初始化,也可以正常使用append方法
	n.Children = append(n.Children, &node)
}

// 返回子节点 列表 长度
func (n *Node) Len() int {
	return len(n.Children)
}

// 设置节点的 isword
func (n *Node) SetIsword(flag bool) {
	n.isWord = flag
}

// 整棵树的根节点
type Trie struct {
	// 字典树的根节点
	Root *Node
}


// 随便初始化根节点为 "/" 吧
func (t *Trie) Init() *Trie {
	t.Root = &Node{
		'/',
		make([]*Node, 0),
		false,
	}
	return t
}


// 外部调用初始化一个 字典树
func New() *Trie { return new(Trie).Init() }


// 添加单词
// 时间复杂度:
func (t *Trie) Add(word string) {
	// 转换为 字符
	w := []byte(word)
	// 找到每一个节点
	cur := t.Root
	// 遍历 word的每一个字符
	for _, c := range w {
		// 1. 查找子节点中是否包含当前字符
		index := t.containsChar(c, cur.Children)
		if index == -1 {
			// 添加新节点
			cur.Add(c)
			// 更新cur 指向它
			index = cur.Len() - 1
		}
		// cur 指向下一个子节点
		cur = cur.Children[index]
	}
	// 将最后一个节点字符的 尾设置为 true
	cur.SetIsword(true)
}


// 查找子节点中是否包含指定字符: 私有方法
func (t *Trie) containsChar(c byte, childrens []*Node) int {
	// 线性遍历查找
	for i, node := range childrens {
		// 查找到既返回索引
		if node.C ==  c {
			return i
		}
	}
	return -1
}


// 判断是否包含指定的单词
// 不仅能找到单词,并且单词的结尾必须是 isWord = true 才说明有这个单词
func (t *Trie) Contains(word string) bool {
	// 转换为 字符
	w := []byte(word)
	// 找到每一个节点
	cur := t.Root
	// 遍历 word的每一个字符
	for _, c := range w {
		// 1. 查找子节点中是否包含当前字符
		index := t.containsChar(c, cur.Children)
		if index == -1 {
			return false
		}
		// cur 指向下一个子节点
		cur = cur.Children[index]
	}
	// 判断最后一个单词是否是 单词末尾 cur.isWord == true,
	// 直接缩写为 cur.isWord
	return cur.isWord
}


使用hash优化效率,改造代码线性查找

package Trie

// 字典树:
/*
	1. 单词结尾表示:需要使用一个 bool 类型,辨识当前节点是否是结尾字符
		叶子结点是 单词结尾
		非叶子节点 也可能是单词的结尾
	2. 实现功能
		增加单词
		搜索单词
*/


// 定义树的节点
type Node struct {
	// 1. 保存当前字符
	//C byte
	// 使用hash存储,就不需要当前的字符了,它已经在key中了
	// 2. 若干个子节点: 字符: 节点
	Children map[byte]*Node
	// 3. 标识节点是否是一个单词最后的一个字符
	isWord bool
}

// 给子节点 列表添加新的节点
func (n *Node) Add(c byte) {
	// 构造节点:  nil 类型 map 不可直接使用添加元素等
	node := Node{
		Children: make(map[byte]*Node, 0),
	}
	// 天啊及
	n.Children[c] = &node
}

// 返回子节点 列表 长度
//func (n *Node) Len() int {
//	return len(n.Children)
//}

// 设置节点的 isword
func (n *Node) SetIsword(flag bool) {
	n.isWord = flag
}

// 整棵树的根节点
type Trie struct {
	// 字典树的根节点
	Root *Node
}


// 随便初始化根节点为 "/" 吧
func (t *Trie) Init() *Trie {
	t.Root = &Node{
		make(map[byte]*Node, 0),
		false,
	}
	return t
}


// 外部调用初始化一个 字典树
func New() *Trie { return new(Trie).Init() }


// 添加单词
// 时间复杂度:
func (t *Trie) Add(word string) {
	// 转换为 字符
	w := []byte(word)
	// 找到每一个节点
	cur := t.Root
	// 遍历 word的每一个字符
	for _, c := range w {
		// 1. 查找子节点中是否包含当前字符
		// 如果不包含, 添加一下
		if _, ok := cur.Children[c]; !ok {
			// 添加新节点
			cur.Add(c)
		}
		// cur 指向下一个子节点
		cur = cur.Children[c]
	}
	// 将最后一个节点字符的 尾设置为 true
	cur.SetIsword(true)
}


//// 查找子节点中是否包含指定字符: 私有方法
//func (t *Trie) containsChar(c byte, childrens []*Node) int {
//	// 线性遍历查找
//	for i, node := range childrens {
//		// 查找到既返回索引
//		if node.C ==  c {
//			return i
//		}
//	}
//	return -1
//}


// 判断是否包含指定的单词
// 不仅能找到单词,并且单词的结尾必须是 isWord = true 才说明有这个单词
func (t *Trie) Contains(word string) bool {
	// 转换为 字符
	w := []byte(word)
	// 找到每一个节点
	cur := t.Root
	// 遍历 word的每一个字符
	for _, c := range w {
		// 1. 查找子节点中是否包含当前字符
		if _, ok :=  cur.Children[c]; !ok {
			return false
		}
		// cur 指向下一个子节点
		cur = cur.Children[c]
	}
	// 判断最后一个单词是否是 单词末尾 cur.isWord == true,
	// 直接缩写为 cur.isWord
	return cur.isWord
}


运行main方法,执行测试用例

package main

import (
	"01/Trie字典树/Trie"
	"fmt"
)

func main() {
	// 创建字典树
	t := Trie.New()
	// 编写测试
	t.Add("big")
	t.Add("pat")
	t.Add("bigger")
	t.Add("dog")
	t.Add("door")
	// 测试
	fmt.Println(t.Contains("big"))
	fmt.Println(t.Contains("bigg"))
	fmt.Println(t.Contains("bigger"))
	fmt.Println(t.Contains("biggerr"))
}

  • 选择不同的数据结构,实现不同的算法,对性能和空间的提升是有的,并且缩短了代码量。

基数树:

  • 前面的前缀树可以看出来, 查找速度是跟 树的深度有关的。 并且从在单一分支的情况,且对单一超长的 word或者是比较稀疏的单词的时候,存储很费力不讨好,会导致树总是只有单个分支,大大提高树的深度 和 存储空间。
  • 扩展到许多框架的路由匹配
  • 应对大量的路由匹配, radix 树可以提高你应对大量匹配的能力。
    在这里插入图片描述
    在这里插入图片描述
  • 这篇文章有个简单的介绍还可以, 可以看下,演进过程。
  • https://ethbook.abyteahead.com/ch4/radix.html
Go中实现的自适应基数树-Golang开发 Go中的自适应基数树实现该库提供了Adaptive Radix Tree(ART)的Go实现。 功能:查找性能超越高度优化的替代方案支持高效ins Go中的自适应基数树实现该库提供了自适应基数树(ART)的Go实现。 功能:查找性能优于高度优化的替代方案支持高效的插入和删除空间高效的性能可与哈希表相媲美保持数据的排序顺序,从而可以进行其他操作,例如范围扫描和前缀查找O(k)搜索/插入/删除操作,其中k是键的最小/最大值的长度 立即下载

相关推荐

Go-trie-单词查找树实现Go实现

trie - 单词查找树实现Go实现,极快的前缀/模糊字符串搜索的数据结构和相关算法

基数树(radix tree)与前缀树(Trie)

在读gin路由原理时了解到gin 路由应用数据结构基数树实现,有低内存、高效率的特点。 在此记录一下基数树的原理,同时也对比一下很相近的前缀树。 基数树: 前缀树: 引用 https://en.wikipedia.org/wiki/Radix_treehttps://en.wikipedia.org/wiki/Trie ...

shasha6的专栏 2193

go-radix, Radix树的Golang实现.zip

go-radix, Radix树的Golang实现 提供实现 radix的radix 包。 包只提供单个 Tree 实现,针对稀疏节点优化。作为一个基数树,它提供以下内容:O(k) 操作。在许多情况下,这可以能比散列表快,因为哈希函数是 O(k) 操作。最小/最大值查找有序

Go的数据结构与实现【Trie(前缀树)】

本文简要介绍了Trie(即前缀树)数据结构,其实现和复杂度分析。

ldxxxxll的博客 1127

从零开始开发AI Agent:基于大模型的智能体实战指南

### 摘要 本文介绍了AI Agent的开发全流程,从基础概念到实际部署,涵盖大模型集成、工具调用和记忆系统构建等核心技术。通过电商客服案例展示实战应用,并提供调试优化与部署方案,最后展望了AI Agent的未来发展方向,帮助开发者快速掌握智能体开发技能。

ghs_gss的博客 4860

告别时钟树平衡噩梦:在Innovus中巧妙设置stop/ignore pin来优化分段时钟网络

本文深入探讨了在Innovus工具中利用stop/ignore pin优化分段时钟树网络的高阶技巧。针对数字IC后端设计中的时钟树平衡难题,详细解析了特殊引脚属性的战略应用场景和配置方法,帮助工程师有效解决SoC设计中复杂的时钟结构问题,显著提升时序收敛效率。

weixin_30836759的博客 286

数据结构STL——golang实现前缀基数树radix

github仓库存储地址:https://github.com/hlccd/goSTL 概述 ​ 前缀基数树(Radix),又叫基数树,是前缀树的一种变种。 ​ 它和前缀树不同的地方在于,它前缀树是将一个string按char进行分段保存,而基数树是将多个char设为一层,然后将string进行分层保存,一般利用**‘/’**作为分层标识。 ​ 它可用于string的存储和索引,当加上模糊匹配时也可用于实现动态路由。 原理 ​ 本次实现的前缀基数树的每个结点分别存储一层的string,终结点存储整个

l2975的博客 1007

Jetson系列目标检测及推流

使用硬件编码,gstreamer推rtsp流至平台

xiao__run的博客 2710

Radix压缩字典树的原理以及Go语言实现代码

Radix树 Radix树,即基数树,也称压缩字典树,是一种提供key-value存储查找的数据结构。radix tree常用于快速查找的场景中,例如:redis中存储slot对应的key信息、内核中使用radix tree管理数据结构、大多数http的router通过radix管理路由。Radix树在Trie Tree(字典树)的原理上优化过来的。因此在介绍Radix树的特点之首先简单介绍一下Trie Tree。 Trie树 Trie Tree,即字典树。Trie Tree的原理是将每个key拆分成一个个

haming123的专栏 1789

EtherCAT报文-BRD(广播读)抓包分析

EtherCAT报文之BRD(广播读)报文Wireshark抓包分析。

kevin1499的博客 1212

云计算 | 期末梳理(上)

2024云计算回忆版 && 复盘向梳理

知识库搭建ing 2229

GoLang IP Radix Tree:基于Go语言的IP地址前缀树实现

GoLang IP Radix Tree:基于Go语言的IP地址前缀树实现 GoLang IP Radix Tree 是一个基于 Go 语言的 IP 子网前缀树(Prefix Tree)的开源项目。该项目的目标是提供一个高效、易于使用的 IP 地址管理库。 1. 项目基础介绍和主要编程语言 GoLang IP Radix Tree 项目使用 Go 语言进行开发。Go 语言以其简洁、高效和并发性能著...

gitblog_00729的博客 478

面向非平行语料的语音转换技术综述

摘要语音转换是语音及人工智能领域的一项研究课题,其目标是在保持源语音内容不变的情况下改变语音的音色,使其听上去像是由另一个目标说话人说出的,同时还需保证语音的质量和自然度。面向非平行语料的语音转换技术是当下的热门研究内容,其使用非平行的多说话人语音数据集进行模型训练,能完成多对多以及任意对任意的语音转换。对近年来面向非平行语料的语音转换进行了全面的总结和分析。首先概述了早期面向平行语料的语音转换及其缺陷,然后对当下面向非平行语料的语音转换的各类实现方法进行介绍和对比分析,最后对语音转换技术进行了总结和展望。

qq_61890005的博客 829

golang的路由数据结构-基数树radix

Radix树 Radix树,即基数树,也称压缩前缀树,是一种提供key-value存储查找的数据结构。与Trie不同的是,它对Trie树进行了空间优化,只有一个子节点的中间节点将被压缩。同样的,Radix树的插入、查询、删除操作的时间复杂度都为O(k)。 Radix树特点 一般由根节点、中间节点和叶子节点组成。 每个节点可以包含一个或多个字符。 树的叶子结点数即是数据条目数。 从根节点到某一节点经过路径的字符连起来即为该节点对应的字符串。 每个节点的所有子节点字符串都不相同。 插入操作 对r

phpduang的博客 962

Transformer实战(30)——Transformer注意力机制可视化

在本节中,我们讨论了人工智能面临的最重要问题之一:可解释人工智能 (explainable artificial intelligence, XAI)。随着语言模型的不断发展,可解释性成为一个严峻的问题。本节中,我们从 Transformer 的角度出发,研究了 Transformer 架构中的自注意力机制,尝试通过各种可视化工具理解这些机制的内部过程。

盼小辉丶的博客 2613

第12步 支持向量机(SVM)

搭建SVM

Jet4505的博客 1049

路由查找之Radix Tree

copy fromhttps://michaelyou.github.io/2018/02/10/%E8%B7%AF%E7%94%B1%E6%9F%A5%E6%89%BE%E4%B9%8BRadix-Tree/ 什么是Radix Tree 在计算机科学中,基数树,或称Patricia trie/tree,或crit bit tree,压缩前缀树,是一种更节省空间的Trie(前缀树)。对于基...

wunity的博客 1694

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

linux tree 数据结构,基数树

Linux内核中的数据结构基数树正如你所知道的 Linux 内核通过许多不同库以及函数提供各种数据结构以及算法实现。 这个部分我们将介绍其中一个数据结构 Radix tree。Linux 内核中有两个文件与 radix tree 的实现和API相关:首先说明一下什么是 radix tree 。Radix tree 是一种 压缩 trie,其中 trie 是一种通过保存关联数组(associativ...

weixin_30600605的博客 284

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

linux内核的数据结构,Linux 内核数据结构:Radix树

原标题:Linux 内核数据结构:Radix树本文转载自Linux爱好者原文出处:0xAX译文出处:伯乐在线译文链接:http://blog.jobbole.com/87675/正如你所知道的, Linux 内核通过许多不同库以及函数提供各种数据结构以及算法。这个部分我们将介绍其中一个数据结构 Radix tree。Linux 内核中有两个文件与 radix tree 的实现和 API 相关:in...

weixin_33436232的博客 587

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

探索高效数据结构的魅力: go-immutable-radix树的深度揭秘与应用

在软件开发的浩瀚世界中,数据结构的选择往往决定了程序的效率与性能。今天,我们将深入探讨一个由Hashicorp带来的开源神器——**go-immutable-radix**,这是一份为追求高性能和代码安全而生的技术礼物。 ## 项目介绍 go-immutable-radix是一个专为Go语言设计的库,它提供了一个不可变的[基数树](http://en.wikipedia.org/wiki/Ra...

gitblog_00058的博客 908

探索高效路径匹配:Radix Tree在Crystal语言的优雅实践

探索高效路径匹配:Radix Tree在Crystal语言的优雅实践 随着微服务和高性能Web应用的兴起,高效的路径解析和路由成为了开发者关注的核心之一。今天,我们要推荐的是一个专为Crystal语言打造的利器——Radix Tree,它以一种新颖且高效的方式管理你的应用程序路由。 项目介绍 Radix Tree是一个针对Crystal语言实现的高效前缀树(又称作字典树)。通过提供简洁的API设计...

gitblog_00283的博客 450

路由树实现(tree.go)

Gin框架中的tree.go文件实现了压缩前缀树(radixtree)路由匹配,是Gin高效性能的核心。该数据结构通过路径压缩减少内存占用,支持:id和*filepath等参数路由。核心结构node包含路径片段、子节点索引和处理链等字段,通过优先级排序优化查询性能。路由注册时进行节点分裂和通配符校验,匹配时采用静态优先+参数兜底的策略,并利用预分配实现零内存分配。相比哈希表和字典树,radixtree在功能与性能间取得平衡,是Gin路由高效匹配的关键。

不愿言弃-念何的博客 614

libart源代码分析:一步步带你看懂自适应基数树的实现原理

自适应基数树(Adaptive Radix Tree,简称ART)是一种高效的索引数据结构,能够在内存数据库、缓存系统等场景中提供出色的查找性能。本文将通过分析libart项目的源代码,带你深入理解ART的核心实现原理,掌握这种数据结构的设计精髓。 ## 自适应基数树的核心优势 自适应基数树结合了基数树(Radix Tree)和前缀树(Trie)的优点,通过动态调整节点大小来平衡内存占用和访问

gitblog_00045的博客 529

Guard核心功能解析:一文读懂熔断保护、负载均衡与Radix树路由

Guard(GitHub 加速计划)是一款用 Go 语言编写的高性能熔断与代理服务器,它通过熔断保护、智能负载均衡和高效的 Radix 树路由三大核心功能,为服务提供稳定可靠的流量管理解决方案。无论是微服务架构还是分布式系统,Guard 都能帮助开发者轻松应对高并发场景下的服务稳定性挑战。 ## 核心功能一:智能熔断保护 🛡️ 熔断保护是 Guard 的核心特性之一,它能在服务出现异常时快速

gitblog_00406的博客 357

Radix Tree学习记录

假设当前已插入10001111 val为10, 10000000 01110100 val为11,会产生分裂,父节点只保留公共前缀,同时父节点的val也可能会发生变动。假设当前已插入10001111 val为10, 10000000 01110100 val为11,已知是图2情况。根据父子节点直接的bitLen,清除无效比特位后,合并成完整字节,删除子节点。设置左右子树的依据是,分裂的初始位bit为1则为右边子树,0则为左子树。执行过程中,不断更新子节点为当前节点,直到存在插入条件。则使用递归进行解决。

weixin_63023132的博客 490
上一篇: 《redis实战》一书笔记, 事务及分布式锁场景分析设计, 包括降低内存占用,短结构与分片
下一篇: 详细讲解go web框架之gin框架源码解析记录及思路流程和理解
我是py呀
博客等级 码龄8年 205粉丝 130原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值