Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

skiplist #8

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions collections/binaryheap/SkipList/SkipList.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package SkipList

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

type ConcurrentSkipList struct {
skipLists []*SKIPLIST
level int
}

// SKIPLIST skiplist
type SKIPLIST struct {
level int
length int32
head *Node
tail *Node
rand *rand.Rand
//vmutex sync.RWMutex
}

type Node struct {
index uint64
value int
nextNodes []*Node
}

func (s *SKIPLIST) createNode(index uint64, value, level int) *Node {

newNode := &Node{index, value, make([]*Node, s.randomLevel())}
return newNode
}

func (s *SKIPLIST) randomLevel() int {

level := 1
for ; level < s.level && s.rand.Uint32()&0x1 == 1; level++ {
}
return level

}

func (s *SKIPLIST) searchWithPreviousNodes(index uint64) ([]*Node, *Node) {
// Store all previous value whose index is less than index and whose next value's index is larger than index.
previousNodes := make([]*Node, s.level)

currentNode := s.head

// Iterate from top level to bottom level.
for l := s.level - 1; l >= 0; l-- {
// Iterate value util value's index is >= given index.
// The max iterate count is skip list's length. So the worst O(n) is N.
for currentNode.nextNodes[l] != s.tail && currentNode.nextNodes[l].index < index {
currentNode = currentNode.nextNodes[l]
}

// When next value's index is >= given index, add current value whose index < given index.
previousNodes[l] = currentNode
}

// Avoid point to tail which will occur panic in Insert and Delete function.
// When the next value is tail.
// The index is larger than the maximum index in the skip list or skip list's length is 0. Don't point to tail.
// When the next value isn't tail.
// Next value's index must >= given index. Point to it.
if currentNode.nextNodes[0] != s.tail {
currentNode = currentNode.nextNodes[0]
}

return previousNodes, currentNode
}

func (s *SKIPLIST) insert(index uint64, value int) bool {
// Write lock and unlock.

previousNodes, currentNode := s.searchWithPreviousNodes(index)

// 如果相应index的节点已存在,直接改值
if currentNode != s.head && currentNode.index == index {
currentNode.value = value
return true
}

// Make a new value.
newNode := s.createNode(index, value, s.randomLevel())

// Adjust pointer. Similar to update linked list.
for i := len(newNode.nextNodes) - 1; i >= 0; i-- {
// Firstly, new value point to next value.
newNode.nextNodes[i] = previousNodes[i].nextNodes[i]

// Secondly, previous nodes point to new value.
previousNodes[i].nextNodes[i] = newNode

// Finally, in order to release the slice, point to nil.
previousNodes[i] = nil
}

// atomic.AddInt32(&s.length, 1)

// 如果previousNode的长度大于newNode,经历上述清空后还有继续清空previousNode
for i := len(newNode.nextNodes); i < len(previousNodes); i++ {
previousNodes[i] = nil
}

return true
}

func (s *SKIPLIST) delete(index uint64) bool {

previousNodes, currentNode := s.searchWithPreviousNodes(index)

// If skip list length is 0 or could not find value with the given index.
if currentNode != s.head && currentNode.index == index {
// Adjust pointer. Similar to update linked list.
for i := 0; i < len(currentNode.nextNodes); i++ {
previousNodes[i].nextNodes[i] = currentNode.nextNodes[i]
currentNode.nextNodes[i] = nil
previousNodes[i] = nil
}
}

for i := len(currentNode.nextNodes); i < len(previousNodes); i++ {
previousNodes[i] = nil
}
return true
}
func (s *SKIPLIST) show() {
var currentNode *Node = s.head
for i := s.level - 1; i >= 0; i-- {
fmt.Print("level:", i+1, " ")
for {
if currentNode != nil {
fmt.Print(currentNode.value, " ")
if currentNode.nextNodes[i] != nil {
fmt.Print("-->")
}
currentNode = currentNode.nextNodes[i]
} else {
break
}

}
fmt.Printf("\n")
currentNode = s.head
}
}

//NEWSKIPLIST Create skiplist
func NEWSKIPLIST(level int) *SKIPLIST {

list := &SKIPLIST{}

if level <= 0 {

level = 32

}

list.level = level

list.head = &Node{nextNodes: make([]*Node, level, level)}

list.tail = nil

list.rand = rand.New(rand.NewSource(time.Now().UnixNano()))

for index := range list.head.nextNodes {

list.head.nextNodes[index] = list.tail

}

return list

}
43 changes: 43 additions & 0 deletions collections/binaryheap/SkipList/SkipList_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package SkipList

import (
"testing"
)

func TestInsertion(t *testing.T) {
var i uint64
var val int = 1
s := NEWSKIPLIST(6)
for i = 1; i < 10; i++ {
if !s.insert(i, val) {
t.Error("[-]Insertion failed")
}
val++
}
}

func TestSearch(t *testing.T) {
var i uint64
s := NEWSKIPLIST(6)
for i = 1; i < 10; i++ {
s.searchWithPreviousNodes(i)
}
}

func TestShow(t *testing.T) {
var i uint64
s := NEWSKIPLIST(6)
for i = 1; i < 10; i++ {
s.show()
}
}
func TestDelete(t *testing.T) {
var i uint64
s := NEWSKIPLIST(6)
for i = 1; i < 10; i++ {
if !s.delete(i) {
t.Error("[-]Deletion failed")
}

}
}
File renamed without changes.