package skip import ( "fmt" "math/rand" "time" ) type ( node struct { next []*node key interface{} value interface{} } SkipList struct { root *node size int less func(interface{},interface{})bool gen *rand.Rand probability float64 } ) // Create a new skip list func New(less func(interface{},interface{})bool) *SkipList { gen := rand.New(rand.NewSource(time.Now().UnixNano())) n := &node{make([]*node, 0),nil,nil} return &SkipList{n, 0, less, gen, 0.75} } func (this *SkipList) Do(f func(interface{}, interface{})bool) { if this.size == 0 { return } cur := this.root.next[0] for cur != nil { if !f(cur.key, cur.value) { break } cur = cur.next[0] } } // Get an item from the skip list func (this *SkipList) Get(key interface{}) interface{} { if this.size == 0 { return nil } cur := this.root // Start at the top for i := len(cur.next)-1; i >= 0; i-- { for this.less(cur.next[i].key, key) { cur = cur.next[i] } } cur = cur.next[0] if this.equals(cur.key, key) { return cur.value } return nil } // Insert a new item into the skip list func (this *SkipList) Insert(key interface{}, value interface{}) { prev := this.getPrevious(key) // Already in the list so just update the value if len(prev) > 0 && prev[0].next[0] != nil && this.equals(prev[0].next[0].key, key) { prev[0].next[0].value = value return } h := len(this.root.next) nh := this.pickHeight() n := &node{make([]*node, nh),key,value} // Higher than anything seen before, so tack it on top if nh > h { this.root.next = append(this.root.next, n) } // Update the previous nodes for i := 0; i < h && i < nh; i++ { n.next[i] = prev[i].next[i] prev[i].next[i] = n } this.size++ } // Get the length of the skip list func (this *SkipList) Len() int { return this.size } // Remove an item from the skip list func (this *SkipList) Remove(key interface{}) interface{} { prev := this.getPrevious(key) if len(prev) == 0 { return nil } cur := prev[0].next[0] // If we found it if cur != nil && this.equals(key, cur.key) { // Change all the linked lists for i := 0; i < len(prev); i++ { if prev[i] != nil && prev[i].next[i] != nil { prev[i].next[i] = cur.next[i] } } // Kill off the upper links if they're nil for i := len(this.root.next)-1; i>=0; i-- { if this.root.next[i] == nil { this.root.next = this.root.next[:i] } else { break } } this.size-- return cur.value } return nil } // String representation of the list func (this *SkipList) String() string { str := "{" if len(this.root.next) > 0 { cur := this.root.next[0] for cur != nil { str += fmt.Sprint(cur.key) str += ":" str += fmt.Sprint(cur.value) str += " " cur = cur.next[0] } } str += "}" return str } // Get a vertical list of nodes of all the things that occur // immediately before "key" func (this *SkipList) getPrevious(key interface{}) []*node { cur := this.root h := len(cur.next) nodes := make([]*node, h) for i := h-1; i >= 0; i-- { for cur.next[i] != nil && this.less(cur.next[i].key, key) { cur = cur.next[i] } nodes[i] = cur } return nodes } // Defines an equals method in terms of "less" func (this *SkipList) equals(a, b interface{}) bool { return !this.less(a,b) && !this.less(b,a) } // Pick a random height func (this *SkipList) pickHeight() int { h := 1 for this.gen.Float64() > this.probability { h++ } if h > len(this.root.next) { return h + 1 } return h }