当前位置: 首页 > news >正文

东莞网站设计知名 乐云践新国际新闻头条最新消息

东莞网站设计知名 乐云践新,国际新闻头条最新消息,动漫网站建设目的,旅游网站的目的前言: 在上一篇文章GeoHash——滴滴打车如何找出方圆一千米内的乘客主要介绍了GeoHash的应用是如何的,本篇文章我想要带大家探索一下使用什么样的数据结构去存储这些Base32编码的经纬度能够节省内存并且提高查询的效率。 前缀树、跳表介绍: …

前言:

在上一篇文章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.zhongyajixie.com/news/11234.html

相关文章:

  • 郑州网站制作推广公司网站关键字排名优化
  • Java怎么做网站密码十大互联网广告公司
  • 做的最好的epub网站超云seo优化
  • 如何申请一个网站 做视频直播传媒公司
  • 专业做pc 手机网站小网站关键词搜什么
  • a站b站武汉seo技术
  • 天津h5模板建站百度商城官网
  • 南通网站制作哪个好seo零基础入门教程
  • 做导购网站 商品微信搜一搜seo优化
  • 做婚恋网站怎么样百度自助建站官网
  • 济南有做五合一网站公司百度最新秒收录方法2021
  • 佛山行业网站设计百度账户安全中心
  • 房山 网站建设合肥网站seo整站优化
  • 河南做网站公司报价百度官方优化指南
  • html网站列表怎么做南京百度seo代理
  • 网站建设要学哪些软件有哪些内容搜索引擎营销与seo优化
  • 网站建设 海口最火的推广软件
  • 网站备案主体撤销百度搜索排行seo
  • 特殊字体宁波seo在线优化哪家好
  • wordpress动漫网站模板舆情信息网
  • 网站开发论文题目审核表aso关键词排名优化是什么
  • 专做正品的护肤品网站如何网站seo
  • 哪些建材网站可以做宣传关键词优化seo公司
  • 郑州外贸建站企业培训课程有哪些内容
  • 网站备案主体信息变更化妆品营销推广方案
  • 网站的ftp别的公司会给么大连网站seo
  • 做笔记的网站阿里巴巴推广
  • 手机怎么网站模板网站管理
  • 360建筑网靠谱么上海关键词排名手机优化软件
  • 网站绩效营销北京seo公司工作