GeoHash之存储篇

前言:

在上一篇文章GeoHash——滴滴打车如何找出方圆一千米内的乘客主要介绍了GeoHash的应用是如何的,本篇文章我想要带大家探索一下使用什么样的数据结构去存储这些Base32编码的经纬度能够节省内存并且提高查询的效率。


前缀树、跳表介绍:

什么是前缀树:

针对于没有接触过前缀树或者不熟悉前缀树的同学,我先简单介绍一下其基本原理。

前缀树 其主要就是分为两个部分 前缀 + 树

树大家肯定不陌生,比如二叉搜索树这样的数据结构就可以将查询效率降低至O(logn),
而前缀树不同之处在于它的节点的核心数据结构是这样的:

`

type Trie struct {child [26]*TrieisEnd bool
}

首先 child [26]*Trie主要作用就是存放子节点的,而isEnd作用就是去判断当前节点是否存在有一个完整的元素的结尾。光说原理比较枯燥,举例图示说明:

不知道大家是否了解过web后端路由是有哪些存储方式的,在golang语言中gin框架就是基于前缀树去存储路由的,比如:

假设我们要使用前缀树去存储
/ /ag /c /e这四个路由

那么存储过程就是应该这样的

image.png

每一个节点是一个Trie数据结构的节点,每个数组节点对应的是需要存储数据的单个字符,这样做的好处就是当我们需要存放的数据如果有相同前缀那么就不需要重复存储,节省空间,例如app、approach。那么app就只需要存储一次即可。

为了更方便理解,这里放一下插入元素、搜寻元素是否存在的代码:

func (this *Trie) Insert(word string)  {cur:=thisfor i:=0;i<len(word);i++{idx:=word[i]-'a'if cur.child[idx]==nil{cur.child[idx]=&Trie{}}cur=cur.child[idx]}cur.isEnd=true
}func (this *Trie) Search(word string) bool {cur:=thisfor i:=0;i<len(word);i++{if cur.child[word[i]-'a']==nil{return false}cur=cur.child[word[i]-'a']}return cur.isEnd
}

而GeoHash得到的字符串其实正好满足大量相同前缀的特性,因此使用前缀树去存储GeoHash是相对比较合适的。


对于前缀树的补充

上述讲的其实是最基础版的前缀树,我们还可以对此进行一些魔改来优化存储与查询。

比如在Go/gin框架中的路由存储就是用的压缩前缀树

首先该树中当一个节点它仅有一个子节点时就会对树的结构进行一个压缩

image.png

/egg这个节点,e下子节点只有g,g下子节点就只有g,因此它们都会被合并到一起

其次句柄数量更多的 child node 摆放在 children 数组更靠前的位置.

如egg句柄数量更多,那么它就将会更靠前,以便于更早被遍历到


跳表原理简单介绍

其实用上述数据结构已经非常合适了,但是我为什么还要介绍一下SkipList这种数据结构呢,因为Redis中GEO 本身并没有设计新的底层数据结构,而是直接使用了 Sorted Set 集合类型。而Sorted Set底层其实就是跳表,那么就简单介绍一下。


链表在查找元素的时候,因为需要逐一查找,所以查询效率非常低,时间复杂度是O(N),于是就出现了跳表。跳表是在链表基础上改进过来的,实现了一种「多层」的有序链表,这样的好处是能快读定位数据。

如图所示

image.png

  • L0 层级共有 5 个节点,分别是节点1、2、3、4、5;
  • L1 层级共有 3 个节点,分别是节点 2、3、5;
  • L2 层级只有 1 个节点,也就是节点 3 。

如果我们要在链表中查找节点 4 这个元素,只能从头开始遍历链表,需要查找 4 次,而使用了跳表后,只需要查找 2 次就能定位到节点 4,因为可以在头节点直接从 L2 层级跳到节点 3,然后再往前遍历找到节点 4。

可以看到,这个查找过程就是在多个层级上跳来跳去,最后定位到元素。当数据量很大时,跳表的查找复杂度就是 O(logN)


想要自己简单动手去实现一下跳表可以刷一下对应的题(力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台)

这里贴一下自己写的跳表代码

type Node struct {Val  intNext *NodeDown *Node
}type Skiplist struct {head *Node
}func Constructor() Skiplist {return Skiplist{head:&Node{Val:-1,Next:nil,Down:nil} }
}func (this *Skiplist) Search(target int) bool {curr:=this.headfor curr!=nil{for curr.Next!=nil&&curr.Next.Val<target{curr=curr.Next}if curr.Next != nil&&curr.Next.Val==target{return true}curr=curr.Down}return false
}func (this *Skiplist) Add(num int) {curr:=this.headisInsert:=truedown:=&Node{Val:-1,Next:nil,Down:nil}deque:=[]*Node{}for curr!=nil{for curr.Next!=nil&&curr.Next.Val<num{curr=curr.Next}deque=append(deque,curr)curr=curr.Down}for len(deque)>0&&isInsert{curr=deque[len(deque)-1]deque=deque[:len(deque)-1]if down.Val==-1{curr.Next=&Node{Val:num,Next:curr.Next,Down:nil}}else{curr.Next=&Node{Val:num,Next:curr.Next,Down:down}}down=curr.NextisInsert=rand.Float64()>0.5}if isInsert{this.head=&Node{Val:-1,Next:nil,Down:this.head}}
}func (this *Skiplist) Erase(num int) bool {curr, isFound := this.head, falsefor curr != nil {for curr.Next != nil && curr.Next.Val < num {curr = curr.Next}if curr.Next != nil && curr.Next.Val == num {isFound = truecurr.Next = curr.Next.Next}curr = curr.Down}return isFound}

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

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

相关文章

数据结构队列的实现

本章介绍数据结构队列的内容&#xff0c;我们会从队列的定义以及使用和OJ题来了解队列&#xff0c;话不多说&#xff0c;我们来实现吧 队列 1。队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;…

centos7搭建apache作为文件站后,其他人无法访问解决办法

在公司内网的一个虚拟机上搭建了httpsd服务&#xff0c;准备作为内部小伙伴们的文件站&#xff0c;但是搭建好之后发现别的小伙伴是无法访问我机器的。 于是寻找一下原因&#xff0c;排查步骤如下&#xff1a; 1.netstat -lnp 和 ps aux 先看下端口和 服务情况 发现均正常 2.…

设计模式-工厂设计模式

核心思想 在简单工厂模式的基础上进一步的抽象化具备更多的可扩展和复用性&#xff0c;增强代码的可读性使添加产品不需要修改原来的代码&#xff0c;满足开闭原则 优缺点 优点 符合单一职责&#xff0c;每个工厂只负责生产对应的产品符合开闭原则&#xff0c;添加产品只需添…

探讨uniapp的路由与页面生命周期问题

1 首先我们引入页面路由 2 页面生命周期函数 onLoad() {console.log(页面加载)},onShow() {console.log(页面显示)},onReady(){console.log(页面初次显示)},onHide() {console.log(页面隐藏)},onUnload() {console.log(页面卸载)},onBackPress(){console.log(页面返回)}3 页面…

代码随想录算法训练营之JAVA|第三十九天|474. 一和零

今天是第39天刷leetcode&#xff0c;立个flag&#xff0c;打卡60天。 算法挑战链接 474. 一和零https://leetcode.cn/problems/ones-and-zeroes/ 第一想法 题目理解&#xff1a;找到符合条件的子集&#xff0c;这又是一个组合的问题。 看到这个题目的时候&#xff0c;我好像…

JAVA学习-愚见

JAVA学习-愚见 分享一下Java的学习路线&#xff0c;仅供参考【本人亲测&#xff0c;真实有效】 1、尽可能推荐较新的课程 2、大部分视频在B站上直接搜关键词就行【自学&#xff0c;B大的学生】 文章目录 JAVA学习-愚见前期准备Java基础课程练手项目 数据库JavaWeb前端基础 Vue…

学习设计模式之观察者模式,但是宝可梦

前言 作者在准备秋招中&#xff0c;学习设计模式&#xff0c;做点小笔记&#xff0c;用宝可梦为场景举例&#xff0c;有错误欢迎指出。 观察者模式 观察者模式定义了一种一对多的依赖关系&#xff0c;一个对象的状态改变&#xff0c;其他所有依赖者都会接收相应的通知。 所…

匈牙利算法 in 二分图匹配

https://www.luogu.com.cn/problem/P3386 重新看这个算法&#xff0c;才发现自己没有理解。 左边的点轮流匹配&#xff0c;看是否能匹配成功。对右边的点进行记录是否尝试过 然后有空就进&#xff0c;别人能退的就进 遍历左部点&#xff1a; 尝试匹配过程&#xff1a;

[C++] STL_vector 迭代器失效问题

文章目录 1、前言2、情况一&#xff1a;底层空间改变的操作3、情况二&#xff1a;指定位置元素的删除操作4、g编译器对迭代器失效检测4.1 扩容4.2 erase删除任意位置&#xff08;非尾删&#xff09;4.3 erase尾删 5、总结 1、前言 **迭代器的主要作用就是让算法能够不用关心底…

DataWhale 机器学习夏令营第三期——任务二:可视化分析

DataWhale 机器学习夏令营第三期 学习记录二 (2023.08.23)——可视化分析1.赛题理解2. 数据可视化分析2.1 用户维度特征分布分析2.2 时间特征分布分析 DataWhale 机器学习夏令营第三期 ——用户新增预测挑战赛 学习记录二 (2023.08.23)——可视化分析 2023.08.17 已跑通baseli…

Android沉浸式实现(记录)

沉浸式先看效果 直接上代码 Android manifest文件 android:theme"style/Theme.AppCompat.NoActionBar"布局文件 <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"ht…

mit s0681 lab2 Trace系统调用实现

实验一 实现一个用户级别的程序&#xff0c;功能为&#xff0c;指定系统调用后&#xff0c;跟踪程序的系统调用情况 分析实验 实验目标为实现一个程序去跟踪指定程序的系统调用。因此目标有两个 实现一个程序跟踪目标程序的系统调用 实现1&#xff0c;就需要在用户这边实…

4.18 TCP 和 UDP 可以使用同一个端口吗?

目录 TCP 和 UDP 可以同时绑定相同的端口吗&#xff1f; 多个 TCP 服务进程可以绑定同一个端口吗&#xff1f; 重启 TCP 服务进程时&#xff0c;为什么会有“Address in use”的报错信息&#xff1f; 重启 TCP 服务进程时&#xff0c;如何避免“Address in use”的报错信息…

HarmonyOS/OpenHarmony应用开发-ArkTS语言渲染控制LazyForEach数据懒加载

LazyForEach从提供的数据源中按需迭代数据&#xff0c;并在每次迭代过程中创建相应的组件。当LazyForEach在滚动容器中使用了&#xff0c;框架会根据滚动容器可视区域按需创建组件&#xff0c;当组件划出可视区域外时&#xff0c;框架会进行组件销毁回收以降低内存占用。一、接…

智驾算力芯片市场仍处于「波动」周期,Momenta曝光自研NPU

用「冷热不均」来形容当下的汽车芯片赛道&#xff0c;再合适不过了。 本周&#xff0c;英伟达公布的第二财季&#xff08;5-7月&#xff09;营收达到创纪录的135亿美元&#xff0c;大幅超出了此前市场普遍预期的略高于110亿美元&#xff0c;同比增速更是达到了101%。 其中&…

接口测试总结分享(http与rpc)

接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。 一、了解一下HTTP与RPC 1. HTTP&#xff08;H…

【python】输出高亮信息的内容

背景 日志是定位问题和数据分析的关键手段之一&#xff0c;尤其是在调试阶段&#xff0c;高效的、具有辨识度的日志可以非常快速准确的进行问题定位。shell中的echo命令自带文本格式化输出的功能&#xff0c;我们先来回顾下基本的语法&#xff0c;然后套用到python中即可。 s…

Docker安装及Docker构建简易版Hadoop生态

一、首先在VM创建一个新的虚拟机将Docker安装好 更新系统&#xff1a;首先打开终端&#xff0c;更新系统包列表。 sudo apt-get update sudo apt-get upgrade下图是更新系统包截图 安装Docker&#xff1a;使用以下命令在Linux上安装Docker。 sudo apt-get install -y docker.i…

pytestx容器化执行引擎

系统架构 前端、后端、pytest均以Docker容器运行服务&#xff0c;单独的容器化执行引擎&#xff0c;项目环境隔离&#xff0c;即用即取&#xff0c;用完即齐&#xff0c;简单&#xff0c;高效。 前端容器&#xff1a;页面交互&#xff0c;请求后端&#xff0c;展示HTML报告 后…

华为云渲染实践

// 编者按&#xff1a;云计算与网络基础设施发展为云端渲染提供了更好的发展机会&#xff0c;华为云随之长期在自研图形渲染引擎、工业领域渲染和AI加速渲染三大方向进行云渲染方面的探索与研究。本次LiveVideoStackCon 2023上海站邀请了来自华为云的陈普&#xff0c;为大家分…