Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

init

  • Loading branch information...
commit 7a299ec8a27bdd6981d6e6e7cf74c37a90c7cabe 1 parent 115752c
@huandu authored
View
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Huan Du
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
4 README.md
@@ -1,4 +0,0 @@
-skiplist.go
-===========
-
-A golang Skip List Implementation.
View
10 README.textile
@@ -0,0 +1,10 @@
+skiplist
+===========
+
+A golang Skip List Implementation.
+
+Use <code>go doc</code> to see more docs.
+
+<pre>
+go doc github.com/huandu/skiplist
+</pre>
View
27 element.go
@@ -0,0 +1,27 @@
+// A golang Skip List Implementation.
+// https://github.com/huandu/skiplist/
+//
+// Copyright 2011, Huan Du
+// Licensed under the MIT license
+// https://github.com/huandu/skiplist/blob/master/LICENSE
+
+package skiplist
+
+// Gets the ajancent next element.
+func (element *Element) Next() *Element {
+ return element.next[0]
+}
+
+// Gets next element at a specific level.
+func (element *Element) NextLevel(level int) *Element {
+ if level >= len(element.next) || level < 0 {
+ panic("invalid argument to NextLevel")
+ }
+
+ return element.next[level]
+}
+
+// Gets key.
+func (element *Element) Key() interface{} {
+ return element.key
+}
View
32 gen_compare_funcs.sh
@@ -0,0 +1,32 @@
+#! /bin/bash
+
+SIMPLE_TYPES='byte float32 float64 int int16 int32 int64 int8 rune string uint uint16 uint32 uint64 uint8 uintptr'
+
+function ucfirst() {
+ perl -ne 'print ucfirst()' <<<"$1"
+}
+
+# print simple types
+for i in $SIMPLE_TYPES; do
+ cat <<EOF
+ `ucfirst $i` GreaterThanFunc = func (lhs, rhs interface{}) bool {
+ return lhs.($i) > rhs.($i)
+ }
+ `ucfirst $i`Reversed GreaterThanFunc = func (lhs, rhs interface{}) bool {
+ return lhs.($i) < rhs.($i)
+ }
+
+EOF
+done
+
+# special case for bytes
+cat <<EOF
+ // the type []byte.
+ Bytes GreaterThanFunc = func (lhs, rhs interface{}) bool {
+ return bytes.Compare(lhs.([]byte), rhs.([]byte)) > 0
+ }
+ // the type []byte. reversed order.
+ BytesReversed GreaterThanFunc = func (lhs, rhs interface{}) bool {
+ return bytes.Compare(lhs.([]byte), rhs.([]byte)) < 0
+ }
+EOF
View
230 skiplist.go
@@ -0,0 +1,230 @@
+// A golang Skip List Implementation.
+// https://github.com/huandu/skiplist/
+//
+// Copyright 2011, Huan Du
+// Licensed under the MIT license
+// https://github.com/huandu/skiplist/blob/master/LICENSE
+
+// Package skiplist provides a go implementation for skip list.
+// About skip list: http://en.wikipedia.org/wiki/Skip_list
+//
+// Skip list is basically an ordered set.
+// Following code creates a skip list with int key and adds some values.
+// list := skiplist.New(skiplist.Int)
+//
+// // adds some elements
+// list.Set(20, "Hello")
+// list.Set(10, "World")
+// list.Set(40, true) // value can be any type
+// list.Set(40, 1000) // replace last element with new value
+//
+// // try to find one
+// e := list.Get(10) // value is the Element with key 10
+// _ = e.Value.(string) // it's the "World". remember to do type cast
+// v, ok := list.GetValue(20) // directly get value. ok is false if not exists
+// notFound := list.Get(15) // returns nil if key is not found
+//
+// // remove element
+// old := list.Remove(40) // remove found element and returns its pointer
+// // returns nil if key is not found
+//
+// // re-init list. it will make the list empty.
+// list.Init()
+//
+// Skip list elements have random number of next pointers. The max number (say
+// "max level") is configurable.
+//
+// The variable skiplist.DefaultMaxLevel is controlling global default.
+// Changing it will not affect created lists.
+// skiplist.DefaultMaxLevel = 24 // the global default is 24 at beginning
+// Max level of a created list can also be changed even if it's not empty.
+// list.SetMaxLevel(10)
+// Remember the side effect when changing this max level value.
+// See its wikipedia page for more details.
+//
+// Most comparable built-in types are pre-defined in skiplist, including
+// byte []byte float32 float64 int int16 int32 int64 int8
+// rune string uint uint16 uint32 uint64 uint8 uintptr
+// Pre-defined compare function name is similar to the type name, e.g.
+// skiplist.Float32 is for float32 key. A special case is skiplist.Bytes is for []byte.
+// These functions order key from small to big (say "ascending order").
+// There are also reserved order functions with name like skiplist.IntReversed.
+// For key types out of the pre-defined list, one can write a custom compare function.
+// type GreaterThanFunc func (lhs, rhs interface{}) bool
+// Such compare function returns true if lhs > rhs. Note that, if lhs == rhs, compare
+// function (let the name is "foo") must act as following.
+// // if lhs == rhs, following expression must be true
+// foo(lhs, rhs) == false && foo(rhs, lhs) == false
+package skiplist
+
+import (
+ "math/rand"
+)
+
+// Creates a new skiplist.
+// keyFunc is a func checking the "greater than" logic.
+// If k1 equals k2, keyFunc(k1, k2) and keyFunc(k2, k1) must both be false.
+// For built-in types, keyFunc can be found in skiplist package.
+// For instance, skiplist.Int is for the list with int keys.
+// By default, the list with built-in type key is in ascend order.
+// The keyFunc named as skiplist.IntReversed is for descend key order list.
+func New(keyFunc GreaterThanFunc) *SkipList {
+ if DefaultMaxLevel <= 0 {
+ panic("skiplist default level must not be zero or negative")
+ }
+
+ return &SkipList{
+ level: DefaultMaxLevel,
+ elementNode: elementNode{next: make([]*Element, DefaultMaxLevel)},
+ keyFunc: keyFunc,
+ }
+}
+
+func randLevel(level int) []*Element {
+ return make([]*Element, rand.Intn(level)+1)
+}
+
+// Resets a skiplist and discards all exists elements.
+func (list *SkipList) Init() *SkipList {
+ list.next = make([]*Element, list.level)
+ list.length = 0
+ return list
+}
+
+// Gets the first element.
+func (list *SkipList) Front() *Element {
+ return list.next[0]
+}
+
+// Gets list length.
+func (list *SkipList) Len() int {
+ return list.length
+}
+
+// Sets a value in the list with key.
+// If the key exists, change element value to the new one.
+// Returns new element pointer.
+func (list *SkipList) Set(key, value interface{}) *Element {
+ var element *Element
+
+ prevs := list.getPrevElementNodes(key)
+
+ // found an element with the same key, replace its value
+ if element = prevs[0].next[0]; element != nil && !list.keyFunc(element.key, key) {
+ element.Value = value
+ return element
+ }
+
+ element = &Element{
+ elementNode: elementNode{next: randLevel(list.level)},
+ key: key,
+ Value: value,
+ }
+
+ for i := range element.next {
+ element.next[i], prevs[i].next[i] = prevs[i].next[i], element
+ }
+
+ list.length++
+ return element
+}
+
+// Gets an element.
+// Returns element pointer if found, nil if not found.
+func (list *SkipList) Get(key interface{}) *Element {
+ var prev *elementNode = &list.elementNode
+ var next, last *Element
+
+ for i := list.level - 1; i >= 0; i-- {
+ next = prev.next[i]
+
+ for next != last && list.keyFunc(key, next.key) {
+ prev, next = &next.elementNode, next.next[i]
+ }
+
+ last = next
+ }
+
+ if last != nil && !list.keyFunc(last.key, key) {
+ return last
+ }
+
+ return nil
+}
+
+// Gets a value. It's a short hand for Get().Value.
+// Returns value and its existence status.
+func (list *SkipList) GetValue(key interface{}) (interface{}, bool) {
+ element := list.Get(key)
+
+ if element == nil {
+ return nil, false
+ }
+
+ return element.Value, true
+}
+
+// Removes an element.
+// Returns removed element pointer if found, nil if not found.
+func (list *SkipList) Remove(key interface{}) *Element {
+ prevs := list.getPrevElementNodes(key)
+
+ // found the element, remove it
+ if element := prevs[0].next[0]; element != nil && !list.keyFunc(element.key, key) {
+ for k, v := range element.next {
+ prevs[k].next[k] = v
+ }
+
+ list.length--
+ return element
+ }
+
+ return nil
+}
+
+func (list *SkipList) getPrevElementNodes(key interface{}) []*elementNode {
+ var prev *elementNode = &list.elementNode
+ var next, last *Element
+
+ prevs := make([]*elementNode, list.level)
+
+ for i := list.level - 1; i >= 0; i-- {
+ next = prev.next[i]
+
+ for next != last && list.keyFunc(key, next.key) {
+ prev, next = &next.elementNode, next.next[i]
+ }
+
+ prevs[i], last = prev, next
+ }
+
+ return prevs
+}
+
+// Gets current max level value.
+func (list *SkipList) MaxLevel() int {
+ return list.level
+}
+
+// Changes skip list max level.
+// If level is not greater than 0, just panic.
+func (list *SkipList) SetMaxLevel(level int) (old int) {
+ if level <= 0 {
+ panic("invalid argument to SetLevel")
+ }
+
+ old, list.level = list.level, level
+
+ if old == level {
+ return
+ }
+
+ if old > level {
+ list.next = list.next[:level]
+ return
+ }
+
+ nils := make([]*Element, level-old)
+ list.next = append(list.next, nils...)
+ return
+}
View
168 skiplist_test.go
@@ -0,0 +1,168 @@
+// A golang Skip List Implementation.
+// https://github.com/huandu/skiplist/
+//
+// Copyright 2011, Huan Du
+// Licensed under the MIT license
+// https://github.com/huandu/skiplist/blob/master/LICENSE
+
+package skiplist
+
+import (
+ "testing"
+ "math/rand"
+)
+
+func checkSanity(list *SkipList, t *testing.T) {
+ // each level must be correctly ordered
+ for k, v := range(list.next) {
+ if v == nil {
+ continue
+ }
+
+ if k > len(v.next) {
+ t.Fatal("first node's level must be no less than current level")
+ }
+
+ prev, next := v, v.next[k]
+
+ for next != nil {
+ if !list.keyFunc(next.key, prev.key) {
+ t.Fatal("next key value must be greater than prev key value")
+ }
+
+ if k > len(next.next) {
+ t.Fatal("node's level must be no less than current level")
+ }
+
+ prev, next = next, next.next[k]
+ }
+ }
+}
+
+func TestBasicCRUD(t *testing.T) {
+ list := New(String)
+ checkSanity(list, t)
+
+ list.Set("A", 1)
+ list.Set("golang", 2)
+ list.Set("Skip", 3)
+ list.Set("List", 4)
+ list.Set("Implementation", 5)
+ checkSanity(list, t)
+
+ list.Set("List", 9)
+ checkSanity(list, t)
+
+ list.Remove("a")
+ list.Remove("List")
+ checkSanity(list, t)
+
+ v1 := list.Get("A")
+ v2, ok2 := list.GetValue("golang")
+ v3, ok3 := list.GetValue("Skip")
+ v4, ok4 := list.GetValue("List")
+ v5, ok5 := list.GetValue("Implementation")
+ v6, ok6 := list.GetValue("not-exist")
+
+ if v1 == nil || v1.Value.(int) != 1 || v1.Key().(string) != "A" {
+ t.Fatal(`wrong "A" value`)
+ }
+
+ if v2.(int) != 2 || !ok2 {
+ t.Fatal(`wrong "golang" value`)
+ }
+
+ if v3.(int) != 3 || !ok3 {
+ t.Fatal(`wrong "Skip" value`)
+ }
+
+ if v4 != nil || ok4 {
+ t.Fatal(`wrong "List" value`)
+ }
+
+ if v5.(int) != 5 || !ok5 {
+ t.Fatal(`wrong "Implementation" value`)
+ }
+
+ if v6 != nil || ok6 {
+ t.Fatal(`wrong "not-exist" value`)
+ }
+}
+
+func TestChangeLevel(t *testing.T) {
+ DefaultMaxLevel = 10
+ list := New(IntReversed)
+
+ if list.MaxLevel() != 10 {
+ t.Fatal("max level must equal default max value")
+ }
+
+ for i := 0; i <= 200; i += 4 {
+ list.Set(i, i * 10)
+ }
+
+ checkSanity(list, t)
+
+ list.SetMaxLevel(20)
+ checkSanity(list, t)
+
+ for i := 1; i <= 201; i += 4 {
+ list.Set(i, i * 10)
+ }
+
+ list.SetMaxLevel(4)
+ checkSanity(list, t)
+
+ if list.Len() != 102 {
+ t.Fatal("wrong list element number", list.Len())
+ }
+
+ for c := list.Front(); c != nil; c = c.Next() {
+ if c.Key().(int) * 10 != c.Value.(int) {
+ t.Fatal("wrong list element value")
+ }
+ }
+}
+
+func BenchmarkWorstInserts(b *testing.B) {
+ b.StopTimer()
+ list := New(Int)
+ list.SetMaxLevel(96)
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ list.Set(i, i)
+ }
+}
+
+func BenchmarkBestInserts(b *testing.B) {
+ b.StopTimer()
+ list := New(IntReversed)
+ list.SetMaxLevel(96)
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ list.Set(i, i)
+ }
+}
+
+func BenchmarkRandomSelect(b *testing.B) {
+ b.StopTimer()
+ list := New(IntReversed)
+ list.SetMaxLevel(96)
+
+ for i := 0; i < b.N; i++ {
+ list.Set(i, i)
+ }
+
+ keys := make([]int, b.N)
+
+ for i := 0; i < b.N; i++ {
+ keys[i] = rand.Intn(b.N)
+ }
+
+ b.StartTimer()
+ for k := range(keys) {
+ list.Get(k)
+ }
+}
View
27 type.go
@@ -0,0 +1,27 @@
+// A golang Skip List Implementation.
+// https://github.com/huandu/skiplist/
+//
+// Copyright 2011, Huan Du
+// Licensed under the MIT license
+// https://github.com/huandu/skiplist/blob/master/LICENSE
+
+package skiplist
+
+// return true if lhs greater than rhs
+type GreaterThanFunc func(lhs, rhs interface{}) bool
+
+type elementNode struct {
+ next []*Element
+}
+
+type Element struct {
+ elementNode
+ key, Value interface{}
+}
+
+type SkipList struct {
+ elementNode
+ level int
+ length int
+ keyFunc GreaterThanFunc
+}
View
135 var.go
@@ -0,0 +1,135 @@
+// A golang Skip List Implementation.
+// https://github.com/huandu/skiplist/
+//
+// Copyright 2011, Huan Du
+// Licensed under the MIT license
+// https://github.com/huandu/skiplist/blob/master/LICENSE
+
+package skiplist
+
+import "bytes"
+
+var (
+ DefaultMaxLevel int = 24
+
+ Byte GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(byte) > rhs.(byte)
+ }
+ ByteReversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(byte) < rhs.(byte)
+ }
+
+ Float32 GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(float32) > rhs.(float32)
+ }
+ Float32Reversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(float32) < rhs.(float32)
+ }
+
+ Float64 GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(float64) > rhs.(float64)
+ }
+ Float64Reversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(float64) < rhs.(float64)
+ }
+
+ Int GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(int) > rhs.(int)
+ }
+ IntReversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(int) < rhs.(int)
+ }
+
+ Int16 GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(int16) > rhs.(int16)
+ }
+ Int16Reversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(int16) < rhs.(int16)
+ }
+
+ Int32 GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(int32) > rhs.(int32)
+ }
+ Int32Reversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(int32) < rhs.(int32)
+ }
+
+ Int64 GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(int64) > rhs.(int64)
+ }
+ Int64Reversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(int64) < rhs.(int64)
+ }
+
+ Int8 GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(int8) > rhs.(int8)
+ }
+ Int8Reversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(int8) < rhs.(int8)
+ }
+
+ Rune GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(rune) > rhs.(rune)
+ }
+ RuneReversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(rune) < rhs.(rune)
+ }
+
+ String GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(string) > rhs.(string)
+ }
+ StringReversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(string) < rhs.(string)
+ }
+
+ Uint GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uint) > rhs.(uint)
+ }
+ UintReversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uint) < rhs.(uint)
+ }
+
+ Uint16 GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uint16) > rhs.(uint16)
+ }
+ Uint16Reversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uint16) < rhs.(uint16)
+ }
+
+ Uint32 GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uint32) > rhs.(uint32)
+ }
+ Uint32Reversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uint32) < rhs.(uint32)
+ }
+
+ Uint64 GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uint64) > rhs.(uint64)
+ }
+ Uint64Reversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uint64) < rhs.(uint64)
+ }
+
+ Uint8 GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uint8) > rhs.(uint8)
+ }
+ Uint8Reversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uint8) < rhs.(uint8)
+ }
+
+ Uintptr GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uintptr) > rhs.(uintptr)
+ }
+ UintptrReversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return lhs.(uintptr) < rhs.(uintptr)
+ }
+
+ // the type []byte.
+ Bytes GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return bytes.Compare(lhs.([]byte), rhs.([]byte)) > 0
+ }
+ // the type []byte. reversed order.
+ BytesReversed GreaterThanFunc = func(lhs, rhs interface{}) bool {
+ return bytes.Compare(lhs.([]byte), rhs.([]byte)) < 0
+ }
+)
Please sign in to comment.
Something went wrong with that request. Please try again.