iskiplist

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 21, 2019 License: MIT Imports: 4 Imported by: 1

README

iskiplist

Indexable skip lists for Go.

Skip lists are typically used to implement associative arrays (analogous to Go maps). The ISkipList provided by this package is a sequence with O(log n) access, insertion and removal of elements at a given index (analogous to Go slices, but with different big O characteristics).

Each element of an ISkipList is an int. The idea is to use the int value as an index into a slice of the data structure of your choice. If this isn't feasible, you can modify ElemType in iskiplist.go and a handful of other definitions. See the comment below the definition of ElemType for details.

Each ISkipList maintains its own local PCG pseudorandom number generator state.

Documentation

https://godoc.org/github.com/addrummond/iskiplist

https://godoc.org/github.com/addrummond/iskiplist/buffered

Documentation

Overview

Package iskiplist provides a skip list based implementation of arrays with O(log n) indexing, insertion and removal. The array element type is 'int'. The idea is to use the int value as an index into a slice of the data structure of your choice. If this technique isn't applicable, it's easy to modify the code to use interface{} as the element type instead.

Each ISkipList maintains its own pseudorandom number generator state. The algorithm used is PCG32. By default, seed initialization piggybacks on address space randomization by using the address of an ISkipList to generate a seed. A seed can be supplied manually via Seed() if more entropy is required.

A cache is maintained of the index and set of nodes associated with the last element access. This increases the efficiency of common iteration patterns without introducing the complexities associated with explicit iterators. For example, if you iterate through every third element in an ISkipList by indexing using At(), then the search for each element at i+3 will begin at element i, not at the root of the skip list. The cache is automatically invalidated in the expected way by operations that mutate the ISkipList. For example, removing the element at i invalidates the cache for a preceding access of any element at index >= i.

The fastest way to iterate through the elements of an ISkipList in sequence is to use Iterate(), IterateI(), IterateRange(), IterateRangeI(), ForAll(), ForAllI(), ForAllRange(), and ForAllRangeI(). These functions do the minimum work possible and do not update the cache.

The behavior of the iteration methods mentioned in the preceding paragraph is unspecified if the ISkipList is mutated within the callback function. (Mutating the element itself is fine – you just can't insert or remove elements.) If you wish to mutate an ISkipList while iterating through it, you should iterate by index.

The most efficient way to build an ISkipList is to add elements sequentially using PushFront(). The next most efficient method is to add elements sequentially using PushBack(). Both run in constant time (the latter due to caching), but PushFront() has a lower constant overhead.

Slices can often be faster in practice than more sophisticated data structures. The following cautionary notes should be borne in mind:

1) Inserting or removing an element in the middle of a slice is extremely fast for slices of a thousand elements or fewer. You will not necessarily see any benefit from using an ISkipList unless you are dealing with sequences of more than 1000 elements. Once you get up to around 10,000 elements, insertions and removals targetting the middle of an ISkipList are much faster.

2) It takes much longer to create an ISkipList by sequentially appending elements than it does to do the same with a slice. Profiling suggests that most of the additional time is spent allocating the list nodes. Thus, if you are creating a list in sequence and then performing only a small number of insertion/removal operations on it, you might find that the total time is dominated by creation time.

These issues can sometimes be mitigated by using a BufferedISkipList instead of an ISkipList (see the bufferediskiplist package).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DebugPrintISkipList

func DebugPrintISkipList(l *ISkipList, pointerDigits int) string

DebugPrintISkipList returns a string representation of an ISkipList that is useful for debugging. There is no guarantee that this output will remain consistent between versions of this package.

Types

type ElemType

type ElemType = int

ElemType is the type of an element of an ISkipList.

type ISkipList

type ISkipList struct {
	// contains filtered or unexported fields
}

ISkipList is an indexable skip list. It behaves like an array or slice (elements sequenced and accessed by index) rather than a map (elements not sequenced and accessed by key).

func (*ISkipList) At

func (l *ISkipList) At(i int) ElemType

At retrieves the element at the specified index.

func (*ISkipList) Clear

func (l *ISkipList) Clear()

Clear empties an ISkipList. Following a call to Clear(), an ISkipList behaves the same as an ISkipList initialized with its default value.

func (*ISkipList) Copy

func (l *ISkipList) Copy() *ISkipList

Copy copies the ISkipList. It does not rerandomize. Seed() and SeedFrom() may be called on the result prior to any other operations. The cache of the ISkipList is not copied.

func (*ISkipList) CopyRange

func (l *ISkipList) CopyRange(from, to int) *ISkipList

CopyRange creates a new ISkipList whose contents are equal to a range of the original ISkipList. The 'from' argument must be >= 0 and < the length of the ISkipList. The 'to' argument must be >= 0 and <= the length of the ISkipList. If neither 'from' nor 'to' is out of bounds but to <= from, then this is a no-op.

func (*ISkipList) CopyRangeToSlice

func (l *ISkipList) CopyRangeToSlice(from, to int, slice []ElemType)

CopyRangeToSlice copies a range of the ISkipList to a slice. The 'from' argument must be >= 0 and < the length of the ISkipList. The 'to' argument must be >= 0 and <= the length of the ISkipList. If neither 'from' nor 'to' is out of bounds but to <= from, then this is a no-op.

func (*ISkipList) CopyToSlice

func (l *ISkipList) CopyToSlice(slice []ElemType)

CopyToSlice(slice) is a shorthand for l.CopyRangeToSlice(0, l.Length(), slice)

func (*ISkipList) ForAll

func (l *ISkipList) ForAll(f func(*ElemType))

ForAll(f) is a shorthand for l.ForAllRange(0, l.Length(), f)

func (*ISkipList) ForAllI

func (l *ISkipList) ForAllI(f func(int, *ElemType))

ForAllI(f) is a shorthand for l.ForAllI(0, l.Length(), f)

func (*ISkipList) ForAllRange

func (l *ISkipList) ForAllRange(from, to int, f func(*ElemType))

ForAllRange is like IterateRange except that the iteration always continues to the end of the specified range. This saves the bother of adding a boolean return value to the iteration function. Element pointers remain valid following any subsequent operations on the ISkipList. Keeping a pointer to a deleted element will prevent garbage collection of the associated skip list nodes.

func (*ISkipList) ForAllRangeI

func (l *ISkipList) ForAllRangeI(from, to int, f func(int, *ElemType))

ForAllRangeI is like IterateRangeI except that the iteration always continues to the end of the specified range. This saves the bother of adding a boolean return value to the iteration function. Element pointers remain valid following any subsequent operations on the ISkipList. Keeping a pointer to a deleted element will prevent garbage collection of the associated skip list nodes.

func (*ISkipList) Insert

func (l *ISkipList) Insert(index int, elem ElemType)

Insert inserts an element before the element at the specified index, or at the end of the list if the index is equal to the length of the ISkipList.

func (*ISkipList) Iterate

func (l *ISkipList) Iterate(f func(*ElemType) bool)

Iterate(f) is a shorthand for l.IterateRange(0, l.Length(), f)

func (*ISkipList) IterateI

func (l *ISkipList) IterateI(f func(int, *ElemType) bool)

IterateI(f) is a shorthand for l.IterateRangeI(0, l.Length(), f)

func (*ISkipList) IterateRange

func (l *ISkipList) IterateRange(from, to int, f func(*ElemType) bool)

IterateRange iterates over a range of the ISkipList and passes the supplied function a pointer to each element visited. The iteration is halted if the function returns false. The 'from' argument must be >= 0 and < the length of the ISkipList. The 'to' argument must be >= 0 and <= the length of the ISkipList. If neither 'from' nor 'to' is out of bounds but to <= from, then this is a no-op. Element pointers remain valid following any subsequent operations on the ISkipList. Keeping a pointer to a deleted element will prevent full garbage collection of the associated skip list nodes.

func (*ISkipList) IterateRangeI

func (l *ISkipList) IterateRangeI(from, to int, f func(int, *ElemType) bool)

IterateRangeI iterates over a range of the ISkipList and passes to the supplied function the index of each visited element and a pointer to it. The iteration is halted if the function returns false. The 'from' argument must be >= 0 and < the length of the ISkipList. The 'to' argument must be >= 0 and <= the length of the ISkipList. If neither 'from' nor 'to' is out of bounds but to <= from, then this is a no-op. Element pointers remain valid following any subsequent operations on the ISkipList. Keeping a pointer to a deleted element will prevent full garbage collection of the associated skip list nodes.

func (*ISkipList) Length

func (l *ISkipList) Length() int

Length returns the length of an ISkipList. It runs in constant time.

func (*ISkipList) PopBack

func (l *ISkipList) PopBack() (r ElemType, ok bool)

PopBack removes the last element of the list and returns it. The second return value is true iff the list was non-empty prior to the pop. PopFront should be preferred where applicable.

func (*ISkipList) PopFront

func (l *ISkipList) PopFront() (r ElemType, ok bool)

PopFront removes the first element of the list and returns it. The second return value is true iff the list was non-empty prior to the pop. PopFront runs in constant time.

func (*ISkipList) PtrAt

func (l *ISkipList) PtrAt(i int) *ElemType

PtrAt retrieves a pointer to the element at the specified index. This pointer remains valid following any subsequent operations on the ISkipList. Keeping a pointer to a deleted element will prevent full garbage collection of the associated skip list nodes.

func (*ISkipList) PushBack

func (l *ISkipList) PushBack(elem ElemType)

PushBack adds an element to the end of the ISkipList. PushFront should be preferred where applicable.

func (*ISkipList) PushFront

func (l *ISkipList) PushFront(elem ElemType)

PushFront adds an element to the beginning of the ISkipList. PushFront runs in constant time.

func (*ISkipList) Remove

func (l *ISkipList) Remove(index int) ElemType

Remove removes the element at the specified index. It returns the value of the removed element.

func (*ISkipList) Seed

func (l *ISkipList) Seed(seed1 uint64, seed2 uint64)

Seed seeds the random number generator used for the ISkipList. If Seed is called, it should be called immediately following creation of the ISkipList. If Seed is not called, the random number generator is automatically seeded using the address of the ISkipList. This works fine, but may not be sufficiently random if the ISkipList could be the target of adversarial usage.

func (*ISkipList) SeedFrom

func (l *ISkipList) SeedFrom(l2 *ISkipList)

SeedFrom sets the pseudorandom number generator state of an ISkipList by copying it from another ISkipList. If SeedFrom is called, it should be called immediately following creation of the ISkipList.

func (*ISkipList) Set

func (l *ISkipList) Set(i int, v ElemType)

Set updates the element at the specified index.

func (*ISkipList) Swap

func (l *ISkipList) Swap(index1, index2 int)

Swap swaps the values of the elements at the specified indices.

func (*ISkipList) Truncate

func (l *ISkipList) Truncate(n int)

Truncate reduces the length of the ISkipList to n, keeping the first n elements. If n is equal to the length of the ISkipList, this is a no-op. If n is zero, this is equivalent to Clear().

func (*ISkipList) Update

func (l *ISkipList) Update(i int, upd func(ElemType) ElemType)

Update applies an update function to the element at the specified index.

Directories

Path Synopsis
Package bufferediskiplist provides a version of ISkipList that (i) buffers insertions at the start and end of the sequence and (ii) does not construct a skip list structure until the sequence reaches a certain length.
Package bufferediskiplist provides a version of ISkipList that (i) buffers insertions at the start and end of the sequence and (ii) does not construct a skip list structure until the sequence reaches a certain length.
Package pcg is an internal package used by github.com/addrummond/iskiplist.
Package pcg is an internal package used by github.com/addrummond/iskiplist.
Package sliceutils is an internal package used by github.com/addrummond/iskiplist.
Package sliceutils is an internal package used by github.com/addrummond/iskiplist.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL