Skip to content

Commit

Permalink
抽取skip_list traverse方法, 修改randomLevel方法,增加测试
Browse files Browse the repository at this point in the history
  • Loading branch information
Oasis committed Oct 18, 2023
1 parent bf66de7 commit 2d441bc
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 22 deletions.
31 changes: 11 additions & 20 deletions internal/list/skip_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@ import (
"github.com/ecodeclub/ekit"
"github.com/ecodeclub/ekit/internal/errs"
"golang.org/x/exp/rand"
"time"
)

// 跳表 skip list

const (
FactorP = 0.25 // level i 上的结点 有FactorP的比例出现在level i + 1上
FactorP = float32(0.25) // level i 上的结点 有FactorP的比例出现在level i + 1上
MaxLevel = 32
)

Expand Down Expand Up @@ -78,8 +77,8 @@ func NewSkipList[T any](compare ekit.Comparator[T]) *SkipList[T] {
// levels的生成和跳表中元素个数无关
func (sl *SkipList[T]) randomLevel() int {
level := 1
rnd := rand.New(rand.NewSource(uint64(time.Now().UnixNano())))
for rnd.Float64() < FactorP {
p := FactorP
for (rand.Int31() & 0xFFFF) < int32(p*0xFFFF) {
level++
}
if level < MaxLevel {
Expand All @@ -90,26 +89,25 @@ func (sl *SkipList[T]) randomLevel() int {
}

func (sl *SkipList[T]) Search(target T) bool {
curr := sl.header
for i := sl.level - 1; i >= 0; i-- {
for curr.Forward[i] != nil && sl.compare(curr.Forward[i].Val, target) < 0 {
curr = curr.Forward[i]
}
}
curr, _ := sl.traverse(target, sl.level)
curr = curr.Forward[0] // 第1层 包含所有元素
return curr != nil && sl.compare(curr.Val, target) == 0
}

func (sl *SkipList[T]) Insert(Val T) {
func (sl *SkipList[T]) traverse(Val T, level int) (*skipListNode[T], []*skipListNode[T]) {
update := make([]*skipListNode[T], MaxLevel) // update[i] 包含位于level i 的插入/删除位置左侧的指针
curr := sl.header
for i := sl.level - 1; i >= 0; i-- {
for i := level - 1; i >= 0; i-- {
for curr.Forward[i] != nil && sl.compare(curr.Forward[i].Val, Val) < 0 {
curr = curr.Forward[i]
}
update[i] = curr
}
return curr, update
}

func (sl *SkipList[T]) Insert(Val T) {
_, update := sl.traverse(Val, sl.level)
level := sl.randomLevel()
if level > sl.level {
for i := sl.level; i < level; i++ {
Expand All @@ -134,14 +132,7 @@ func (sl *SkipList[T]) Len() int {
}

func (sl *SkipList[T]) DeleteElement(target T) bool {
update := make([]*skipListNode[T], MaxLevel)
curr := sl.header
for i := sl.level - 1; i >= 0; i-- {
for curr.Forward[i] != nil && sl.compare(curr.Forward[i].Val, target) < 0 {
curr = curr.Forward[i]
}
update[i] = curr
}
curr, update := sl.traverse(target, sl.level)
node := curr.Forward[0]
if node == nil || sl.compare(node.Val, target) != 0 {
return false
Expand Down
119 changes: 117 additions & 2 deletions internal/list/skip_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,51 @@ func TestSkipList_DeleteElement(t *testing.T) {
wantSize: 1,
wantRes: true,
},
{
name: "delete 1 from []",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{}, ekit.ComparatorRealNumber[int]),
value: 1,
wantSlice: []int{},
wantSize: 0,
wantRes: false,
},
{
name: "delete 1 from [1]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{1}, ekit.ComparatorRealNumber[int]),
value: 1,
wantSlice: []int{},
wantSize: 0,
wantRes: true,
},
{
name: "delete 1 from [2]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{2}, ekit.ComparatorRealNumber[int]),
value: 1,
wantSlice: []int{2},
wantSize: 1,
wantRes: false,
},
{
name: "delete 3 from [1,2,3,4,5,6,7]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{1, 2, 3, 4, 5, 6, 7}, ekit.ComparatorRealNumber[int]),
value: 3,
wantSlice: []int{1, 2, 4, 5, 6, 7},
wantSize: 6,
wantRes: true,
},
{
name: "delete 8 from [1,2,3,4,5,6,7]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{1, 2, 3, 4, 5, 6, 7}, ekit.ComparatorRealNumber[int]),
value: 8,
wantSlice: []int{1, 2, 3, 4, 5, 6, 7},
wantSize: 7,
wantRes: false,
},
}

for _, tc := range testCases {
Expand Down Expand Up @@ -150,6 +195,22 @@ func TestSkipList_Insert(t *testing.T) {
wantSlice: []int{1, 2, 3},
wantSize: 3,
},
{
name: "insert 1 into []",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{}, ekit.ComparatorRealNumber[int]),
value: 1,
wantSlice: []int{1},
wantSize: 1,
},
{
name: "insert 2 into [1,2,3]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{1, 2, 3}, ekit.ComparatorRealNumber[int]),
value: 2,
wantSlice: []int{1, 2, 2, 3},
wantSize: 4,
},
}

for _, tc := range testCases {
Expand All @@ -172,7 +233,7 @@ func TestSkipList_Search(t *testing.T) {
wantRes bool
}{
{
name: "search 2 into [1,3]",
name: "search 2 from [1,3]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{1, 3}, ekit.ComparatorRealNumber[int]),
value: 2,
Expand All @@ -181,14 +242,68 @@ func TestSkipList_Search(t *testing.T) {
wantRes: false,
},
{
name: "search 1 into [1,3]",
name: "search 1 from [1,3]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{1, 3}, ekit.ComparatorRealNumber[int]),
value: 1,
wantSlice: []int{1, 3},
wantSize: 2,
wantRes: true,
},
{
name: "search 1 from []",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{}, ekit.ComparatorRealNumber[int]),
value: 1,
wantSlice: []int{},
wantSize: 0,
wantRes: false,
},
{
name: "search 1 from [1]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{1}, ekit.ComparatorRealNumber[int]),
value: 1,
wantSlice: []int{1},
wantSize: 1,
wantRes: true,
},
{
name: "search 1 from [2]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{2}, ekit.ComparatorRealNumber[int]),
value: 1,
wantSlice: []int{2},
wantSize: 1,
wantRes: false,
},
{
name: "search 3 from [1,2,3,4,5,6]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{1, 2, 3, 4, 5, 6}, ekit.ComparatorRealNumber[int]),
value: 3,
wantSlice: []int{1, 2, 3, 4, 5, 6},
wantSize: 6,
wantRes: true,
},
{
name: "search 8 from [1,2,3,4,5,6]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{1, 2, 3, 4, 5, 6}, ekit.ComparatorRealNumber[int]),
value: 8,
wantSlice: []int{1, 2, 3, 4, 5, 6},
wantSize: 6,
wantRes: false,
},
{
name: "search 2 from [1,2,2,3,3,4,5,6]",
compare: ekit.ComparatorRealNumber[int],
skiplist: NewSkipListFromSlice[int]([]int{1, 2, 2, 3, 3, 4, 5, 6}, ekit.ComparatorRealNumber[int]),
value: 2,
wantSlice: []int{1, 2, 2, 3, 3, 4, 5, 6},
wantSize: 8,
wantRes: true,
},
}

for _, tc := range testCases {
Expand Down

0 comments on commit 2d441bc

Please sign in to comment.