mtchavez/skiplist

View on GitHub
skiplist.go

Summary

Maintainability
A
3 hrs
Test Coverage
package skiplist

import (
    "math/rand"
    "sync"
)

const (
    // ListMaxLevel is the Skiplist can have
    ListMaxLevel = 32
    // ListP is the P value for the SkipList
    ListP = 0.5
)

// SkipList interface defining the methods
// needed for a skip list
type SkipList interface {
    Search(key int) *Node
    Delete(key int) bool
    Insert(key int, val interface{}) *Node
    Iterator() Iterator
}

// List is a basic skip list implementation
// with search, delete, and insert functionality
// and uses a mutex to allow for multi-threaded interaction
type List struct {
    sync.RWMutex
    MaxLevel int
    level    int
    length   int
    header   *Node
    footer   *Node
}

var _ SkipList = (*List)(nil)

// Returns a random level used during inserting nodes
func randomLevel(maxLevel int) int {
    newLevel := 1
    for rand.Float64() >= ListP && newLevel < maxLevel && newLevel < ListMaxLevel-1 {
        newLevel++
    }
    return newLevel
}

// NewList initializes a new skiplist with
// max level of 32 or 2^32 elements
func NewList() *List {
    return NewListWithLevel(ListMaxLevel)
}

// NewListWithLevel initializes a new skiplist with a custom
// max level. Level is defaulted to 32 to allow
// for 2^32 max elements
func NewListWithLevel(level int) *List {
    return &List{
        MaxLevel: level,
        header:   &Node{forward: make([]*Node, level)},
        level:    0,
    }
}

// Iterator returns an iterable from the current
// head of the skiplist.
func (l *List) Iterator() Iterator {
    return &iterable{curr: l.header}
}

// Size returns the length of the list
func (l *List) Size() int {
    return l.length
}

// Search for a node in the skip list by the key
// will return a Node if found or nil if not found
func (l *List) Search(key int) *Node {
    l.RLock()
    defer l.RUnlock()
    x := l.header
    for i := l.level; i >= 0; i-- {
        for x.forward[i] != nil && x.forward[i].key < key {
            x = x.forward[i]
        }
    }
    x = x.forward[0]
    if x != nil && x.key == key {
        return x
    }
    return nil
}

// Insert a new node into the skip list providing a
// integer key and a byte array value. Will return
// the inserted Node
func (l *List) Insert(key int, val interface{}) *Node {
    update := make([]*Node, l.MaxLevel)
    x := l.header
    var alreadyChecked *Node
    l.Lock()
    defer l.Unlock()

    for i := l.level; i >= 0; i-- {
        for x.forward[i] != nil &&
            alreadyChecked != x.forward[i] &&
            x.forward[i].key < key {
            x = x.forward[i]
        }
        alreadyChecked = x.forward[i]
        update[i] = x
    }
    x = x.forward[0]
    if x != nil && x.key == key {
        x.val = val
        return x
    }
    newLevel := randomLevel(l.MaxLevel)
    if newLevel > l.level {
        for i := l.level + 1; i < newLevel; i++ {
            update[i] = l.header
        }
        l.level = newLevel
    }
    x = NewNode(newLevel, key, val)
    for i := 0; i < newLevel; i++ {
        x.forward[i] = update[i].forward[i]
        update[i].forward[i] = x
    }
    x.backward = nil
    if update[0] != l.header {
        x.backward = update[0]
    }
    if x.forward[0] != nil {
        x.forward[0].backward = x
    }
    if l.footer == nil || l.footer.key < key {
        l.footer = x
    }
    l.length++
    return x
}

// Delete will delete a node for the provided key
// will return a true/false if Node was deleted or not
func (l *List) Delete(key int) bool {
    update := make([]*Node, l.MaxLevel)
    x := l.header
    var alreadyChecked *Node
    l.Lock()
    defer l.Unlock()

    for i := l.level; i >= 0; i-- {
        for x.forward[i] != nil &&
            alreadyChecked != x.forward[i] &&
            x.forward[i].key < key {
            x = x.forward[i]
        }
        alreadyChecked = x.forward[i]
        update[i] = x
    }
    x = x.forward[0]
    if x != nil && x.key == key {
        for i := 0; i < l.level; i++ {
            if update[i].forward[i] != x {
                break
            }
            update[i].forward[i] = x.forward[i]
        }
        for l.level > 1 && len(l.header.forward) > l.level && l.header.forward[l.level-1] == nil {
            l.level--
        }
        l.length--
        return true
    }
    return false
}