add skiplist

This commit is contained in:
xuzhiwei 2019-06-20 23:06:34 +09:00
parent 5d6dcd4b96
commit 2e893b6368

View File

@ -0,0 +1,171 @@
/**
* Redis使用的底层算法
* Olog n
* O1
*
*
* (https://juejin.im/post/57fa935b0e3dd90057c50fbc
*
* skiplist和各种平衡树AVLkey的查找
* skiplist操作要复杂
* skiplist上进行范围查找就非常简单1
* skiplist的插入和删除只需要修改相邻节点的指针
* skiplist比平衡树更灵活一些2skiplist每个节点包含的指针数目平均为1/(1-p)p的大小
* Redis里的实现一样p=1/41.33
* keyskiplist和平衡树的时间复杂度都为O(log n)O(1)使Map或dictionary结构
* skiplist比平衡树要简单
*/
export class SkipList<T> {
// head和tail始终指向最顶层的首位节点通过链表能访问任何位置
private head: SkipListNode<T>
private tail: SkipListNode<T>
// 索引的层数0表示最底层
private levelCount = 0
// 元素的个数
private size = 0
// private readonly MAX_LEVEL = 16
constructor() {
this.head = new SkipListNode<T>(SkipListNode.negInf, null)
this.tail = new SkipListNode<T>(SkipListNode.posInf, null)
}
public insert(key: number, value: T): void {
let p: SkipListNode<T>
let q: SkipListNode<T>
let i: number = 0
// 先查找位置
p = this.findNode(key)
// 如果跳跃表中的值已经存在了,直接赋值即可
if (p.key === key) {
p.value = value
return
}
// 没有该值,则进行插入操作,应该是插在p节点的右边. p -> q -> ?
q = new SkipListNode(key, value)
q.left = p
q.right = p.right
if (p.right) {
p.right.left = q
}
p.right = q
// 再使用随机数决定是否要向更高层攀升
while (Math.random() < 0.5) {
// 如果新元素的级别已经达到跳跃表的最大高度,则新建空白层
if (i >= this.levelCount) {
this.addEmptyLevel()
}
// 从p向左扫描含有高层节点的节点, 方便节点在每一层插入
while (!p.up) {
p = p.left!
}
p = p.up
// 新值对应的索引这里不需要存value了因为只需要最底层存value即可
const z = new SkipListNode<T>(key, null)
z.left = p
z.right = p.right
if (p.right) {
p.right.left = z
}
p.right = z
z.down = q
q.up = z
q = z
i = i + 1
}
this.size++
}
public get(key: number): T | null {
const p = this.findNode(key)
return p.key === key ? p.value : null
}
public remove(key: number) {
let p: SkipListNode<T> | undefined = this.findNode(key)
if (p.key !== key) return
while (p != null) {
p.left!.right = p.right
p.right!.left = p.left
p = p.up
}
}
private addEmptyLevel() {
const p1: SkipListNode<T> = new SkipListNode(SkipListNode.negInf, null)
const p2: SkipListNode<T> = new SkipListNode(SkipListNode.posInf, null)
p1.right = p2
p1.down = this.head
p2.left = p1
p2.down = this.tail
this.head.up = p1
this.tail.up = p2
this.head = p1
this.tail = p2
this.levelCount++
}
private findNode(key: number): SkipListNode<T> {
const { head } = this
let p = head
while (true) {
// 从左向右查找直到右节点的key值大于要查找的key值
while (p.right && p.right.key !== SkipListNode.posInf && p.right.key <= key) {
p = p.right
}
// 如果有更低层的节点,则向低层移动
if (p.down) {
p = p.down
} else {
break
}
}
// 这里返回的p的key值是小于等于要找的key值的
return p
}
}
export class SkipListNode<T> {
key: number
value: T | null
up?: SkipListNode<T>
down?: SkipListNode<T>
left?: SkipListNode<T>
right?: SkipListNode<T>
constructor(key: number, value: T | null) {
this.key = key
this.value = value
}
// 最小的数无限接近于0用于表示左标兵
static negInf: number = Number.MIN_VALUE
// 最大的数,用于表示右标兵
static posInf: number = Number.MAX_VALUE
}
const testSkipList = new SkipList()
testSkipList.insert(12, 'qwe')
testSkipList.insert(3, 'mmm')
console.log(testSkipList.get(3))