Skip to content

Commit

Permalink
跳表 by golang
Browse files Browse the repository at this point in the history
  • Loading branch information
leotyliu(刘天一) committed Oct 29, 2018
1 parent 587f438 commit 5569046
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 0 deletions.
177 changes: 177 additions & 0 deletions go/17_skiplist/skiplist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package _7_skiplist

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

const (
//最高层数
MAX_LEVEL = 16
)

//跳表节点结构体
type skipListNode struct {
//跳表保存的值
v interface{}
//用于排序的分值
score int
//层高
level int
//每层前进指针
forwards []*skipListNode
}

//新建跳表节点
func newSkipListNode(v interface{}, score, level int) *skipListNode {
return &skipListNode{v: v, score: score, forwards: make([]*skipListNode, level, level), level: level}
}

//跳表结构体
type SkipList struct {
//跳表头结点
head *skipListNode
//跳表当前层数
level int
//跳表长度
length int
}

//实例化跳表对象
func NewSkipList() *SkipList {
//头结点,便于操作
head := newSkipListNode(0, math.MinInt32, MAX_LEVEL)
return &SkipList{head, 1, 0}
}

//获取跳表长度
func (sl *SkipList) Length() int {
return sl.length
}

//获取跳表层级
func (sl *SkipList) Level() int {
return sl.level
}

//插入节点到跳表中
func (sl *SkipList) Insert(v interface{}, score int) int {
if nil == v {
return 1
}

//查找插入位置
cur := sl.head
//记录每层的路径
update := [MAX_LEVEL]*skipListNode{}
i := MAX_LEVEL - 1
for ; i >= 0; i-- {
for nil != cur.forwards[i] {
if cur.forwards[i].v == v {
return 2
}
if cur.forwards[i].score > score {
update[i] = cur
break
}
cur = cur.forwards[i]
}
if nil == cur.forwards[i] {
update[i] = cur
}
}

//通过随机算法获取该节点层数
level := 1
for i := 1; i < MAX_LEVEL; i++ {
if rand.Int31()%7 == 1 {
level++
}
}

//创建一个新的跳表节点
newNode := newSkipListNode(v, score, level)

//原有节点连接
for i := 0; i <= level-1; i++ {
next := update[i].forwards[i]
update[i].forwards[i] = newNode
newNode.forwards[i] = next
}

//如果当前节点的层数大于之前跳表的层数
//更新当前跳表层数
if level > sl.level {
sl.level = level
}

//更新跳表长度
sl.length++

return 0
}

//查找
func (sl *SkipList) Find(v interface{}, score int) *skipListNode {
if nil == v || sl.length == 0 {
return nil
}

cur := sl.head
for i := sl.level - 1; i >= 0; i-- {
for nil != cur.forwards[i] {
if cur.forwards[i].score == score && cur.forwards[i].v == v {
return cur.forwards[i]
} else if cur.forwards[i].score > score {
break
}
cur = cur.forwards[i]
}
}

return nil
}

//删除节点
func (sl *SkipList) Delete(v interface{}, score int) int {
if nil == v {
return 1
}

//查找前驱节点
cur := sl.head
//记录前驱路径
update := [MAX_LEVEL]*skipListNode{}
for i := sl.level - 1; i >= 0; i-- {
update[i] = sl.head
for nil != cur.forwards[i] {
if cur.forwards[i].score == score && cur.forwards[i].v == v {
update[i] = cur
break
}
cur = cur.forwards[i]
}
}

cur = update[0].forwards[0]
for i := cur.level - 1; i >= 0; i-- {
if update[i] == sl.head && cur.forwards[i] == nil {
sl.level = i
}

if nil == update[i].forwards[i] {
update[i].forwards[i] = nil
} else {
update[i].forwards[i] = update[i].forwards[i].forwards[i]
}
}

sl.length--

return 0
}

func (sl *SkipList) String() string {
return fmt.Sprintf("level:%+v, length:%+v", sl.level, sl.length)
}
38 changes: 38 additions & 0 deletions go/17_skiplist/skiplist_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package _7_skiplist

import "testing"

func TestSkipList(t *testing.T) {
sl := NewSkipList()

sl.Insert("leo", 95)
t.Log(sl.head.forwards[0])
t.Log(sl.head.forwards[0].forwards[0])
t.Log(sl)
t.Log("-----------------------------")

sl.Insert("jack", 88)
t.Log(sl.head.forwards[0])
t.Log(sl.head.forwards[0].forwards[0])
t.Log(sl.head.forwards[0].forwards[0].forwards[0])
t.Log(sl)
t.Log("-----------------------------")

sl.Insert("lily", 100)
t.Log(sl.head.forwards[0])
t.Log(sl.head.forwards[0].forwards[0])
t.Log(sl.head.forwards[0].forwards[0].forwards[0])
t.Log(sl.head.forwards[0].forwards[0].forwards[0].forwards[0])
t.Log(sl)
t.Log("-----------------------------")

t.Log(sl.Find("jack", 88))
t.Log("-----------------------------")

sl.Delete("leo", 95)
t.Log(sl.head.forwards[0])
t.Log(sl.head.forwards[0].forwards[0])
t.Log(sl.head.forwards[0].forwards[0].forwards[0])
t.Log(sl)
t.Log("-----------------------------")
}

0 comments on commit 5569046

Please sign in to comment.