当前位置: 首页>数据库>正文

redis zset 跳表 span redis跳表怎么实现

背景:

相信大家都知道排行榜,在很多场景里都需要用到排行榜功能,尤其是游戏中!之前在了解排行榜实现机制的时候,在网上看得最多的答复便是使用redis的有序集合实现。于是深入了解了一下redis中的有序集合。

redis中的有序结合(sorted set)是一种线性结构,底层是用有序链表实现的,但是对链表增加的“索引”,并且对索引进行了分层,跳表每层散落的节点数不同,查找过程中通过索引向下层跳转,最终落到最下层的数据链中,这样做的目的是通过空间换时间来获取更高的效率,故称之为跳跃表(跳表)。

1,跳表简介

跳表是由William Pugh发明的,这位确实是个大牛,搞出一些很不错的东西。简单说来跳表也是

链表的一种,只不过它在链表的基础上增加了跳跃功能,正是这个跳跃的功能,使得在查找元素时,跳表能够提供O(log n)的时间复杂

度。红黑树等这样的平衡数据结构查找的时间复杂度也是O(log n),并且相对于红黑树这样的平衡二叉树skiplist的优点是更好的支持并

发操作,但是要实现像红黑树这样的数据结构并非易事,但是只要你熟悉链表的基本操作,再加之对跳表原理的理解,实现一个跳表数据

结构就是一个很自然的事情了。

此外,跳表在当前热门的开源项目中也有很多应用,比如LevelDB的核心数据结构memtable是用跳表实现的,redis的sorted set数据

结构也是有跳表实现的。

2,skiplist主要思想

先从链表开始,如果是一个简单的链表(不一定有序),那么我们在链表中查找一个元素X的话,需要将遍历整个链表直到找到元素X为止。

有序数组查找问题我们可以使用二分查找算法,但对于有序链表却不能使用二分查找。这个时候我们在想下平衡树,比如BST,他们都是通过把一些

节点取出来作为其节点下某种意义的索引,比如父节点一般大于左子节点而小于右子节点。因此这个时候我们想到类似二叉搜索树的做法把一些

节点提取出来,作为索引。

当然我们还可以再从一级索引提取一些元素出来,作为二级索引,这样更能加快元素搜索。

这基本上就是跳表的核心思想,其实是一种通过“空间来换取时间”的一个算法,通过在每个节点中增加了向前的指针(即层),从而提升查找的效率。

跳跃列表是按层建造的。底层是一个普通的有序链表。每个更高层都充当下面列表的「快速跑道」,这里在层 i 中的元素按某个固定的概率 p (通常

为0.5或0.25)出现在层 i+1 中。平均起来,每个元素都在 1/(1-p) 个列表中出现, 而最高层的元素(通常是在跳跃列表前端的一个特殊的头元素)

在 O(log1/p n) 个列表中出现。

 

3,SkipList基本数据结构及其实现

一个跳表,应该具有以下特征:

 

1>,一个跳表应该有几个层(level)组成;

 

2>,跳表的第一层包含所有的元素;

 

3>,每一层都是一个有序的链表;

 

4>,如果元素x出现在第i层,则所有比i小的层都包含x;

 

5>,每个节点包含key及其对应的value和一个指向同一层链表的下个节点的指针数组

4,注意问题

1>,如果放任增长,高度失去控制会影响效果,所以一般会限制最高高度

2>,如果删除的值在索引中,注意要删除每一层

 

5.代码实现

https://github.com/pyihe/go-skipList

package main

import (
	"fmt"
	"math/rand"
	"time"
)

const MAX_LEVEL=10
type Skiplist struct {
	maxLevel int
	root []*Node
}
type Node struct{
	level int
	next []*Node
	prev []*Node
	value int
	count int
}

func NewNode(level,value int)*Node{
	return &Node{
		level:level,
		value:value,
		next:make([]*Node,level+1),
		prev:make([]*Node,level+1),
		count:1,
	}
}

func Constructor() Skiplist {
	return Skiplist{
		maxLevel:-1,
	}
}

func (this *Skiplist) SearchPos(target int)*Node{
	if this.maxLevel==-1{
		return nil
	}
	next:=this.root[this.maxLevel]
	for level:=next.level;level>=0;level--{
		if target==next.value{
			return next
		}else if target<next.value{
			for next.prev[level]!=nil && target<=next.prev[level].value{
				next=next.prev[level]
			}
		}else{
			for next.next[level]!=nil && target>=next.next[level].value{
				next=next.next[level]
			}
		}
		fmt.Println("search :",target," level",level)
	}
	return next
}

func (this *Skiplist) Search(target int) bool {
	n:=this.SearchPos(target)
	this.Print()
	if n==nil{
		return false
	}
	return n.value==target
}
func(this *Skiplist)Print(){
	if this.root==nil{
		return
	}
	fmt.Println(*this)
	for i:=this.maxLevel;i>=0;i--{
		cur:=this.root[i]
		for cur!=nil && cur.next!=nil{
			fmt.Print("->[",cur.value,cur.count,"]")
			cur=cur.next[i]
		}
		fmt.Println(i)
	}
}

func(this*Skiplist)randomUpgrade()bool{
	rand.Seed(time.Now().UnixNano())
	r:=rand.Intn(7)%2
	if this.maxLevel>MAX_LEVEL{
		return false
	}
	fmt.Println("rand:---",r)
	return r==1
}

func(n*Node)InsertLevelNode(level int,nn *Node){
	if n==nil ||n.prev==nil || n.next==nil || nn==nil ||nn.prev==nil ||nn.next==nil{
		return
	}
	if n.value>nn.value {
		prev:=n.prev[level]

		n.prev[level]=nn
		nn.next[level]=n

		nn.prev[level]=prev

		if prev!=nil{
			prev.next[level]=nn
		}
	}else{
		next:=n.next[level]

		n.next[level]=nn
		nn.prev[level]=n

		nn.next[level]=next
		if next!=nil{
			next.prev[level]=nn
		}
	}
}

func (this *Skiplist) Add(num int)  {
	this.Print()
	n:=this.SearchPos(num)
	if n==nil{
		this.maxLevel=0
		n=NewNode(0,num)
		this.root=append(this.root,n)
		return
	}

	if n.value==num{
		n.count++
		return
	}


	if this.randomUpgrade(){
		this.maxLevel++
		nn:=NewNode(this.maxLevel,num)
		this.root=append(this.root,nn)

		for i:=1;i<=this.maxLevel-1;i++{
			in:=this.root[i]
			for in!=nil && in.value>num  && in.prev!=nil && in.prev[i]!=nil{
				in=in.prev[i]
			}
			for in!=nil && in.value<num && in.next!=nil && in.next[i]!=nil{
				in=in.next[i]
			}
			in.InsertLevelNode(i,nn)
		}

		n.InsertLevelNode(0,nn)
	}else{
		nn:=NewNode(0,num)
		n.InsertLevelNode(0,nn)
	}
}

func (this*Skiplist)DeleteNode(n*Node,level int){
	if n==nil{
		return
	}
	next:=n.next[level]
	prev:=n.prev[level]
	//fmt.Println("next",next,"prev",prev)
	if prev!=nil{
		prev.next[level]=next
	}else{
		this.root[level]=next
	}
	if next!=nil{
		next.prev[level]=prev
	}
}

func (this *Skiplist) Erase(num int) bool {
	//this.Print()
	n:=this.SearchPos(num)
	if n!=nil{
		//fmt.Println("erease ",*n)
	}
	if n==nil || n.value!=num{
		return false
	}

	if n.count>1{
		n.count--
		return true
	}

	for i:=0;i<=n.level;i++{
		//fmt.Println("-->",i)
		this.DeleteNode(n,i)
	}
	//fmt.Println("-->")
	//this.Print()
	//level i 删除了,i+1 肯定删除了,特殊情况,n层都是最高index,
	count:=0
	for level:=this.maxLevel;n.level==this.maxLevel && level>=0 && this.root!=nil && this.root[level]==nil ;level--{
		count++
	}
	this.root=this.root[:len(this.root)-count]
	this.maxLevel-=count

	n.count--
	n.level=-1
	n.next=nil
	n.prev=nil
	n=nil

	return true
}


/**
 * Your Skiplist object will be instantiated and called as such:
 * obj := Constructor();
 * param_1 := obj.Search(target);
 * obj.Add(num);
 * param_3 := obj.Erase(num);
 */

func main() {
	obj := Constructor();
	obj.Add(0);
	obj.Add(1);
	obj.Add(4);
	obj.Add(1);
	param_1 := obj.Search(1);
	fmt.Println(param_1)
	param_3 := obj.Erase(1);
	fmt.Println(param_3)
}

  

small_lei_it 技术无止境,追求更高。




https://www.xamrdz.com/database/63r1923180.html

相关文章: