forked from wangzheng0822/algo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
leotyliu(刘天一)
committed
Oct 29, 2018
1 parent
587f438
commit 5569046
Showing
2 changed files
with
215 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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("-----------------------------") | ||
} |