vendor files

This commit is contained in:
Serguei Bezverkhi
2018-01-09 13:57:14 -05:00
parent 558bc6c02a
commit 7b24313bd6
16547 changed files with 4527373 additions and 0 deletions

23
vendor/github.com/petar/GoLLRB/.gitignore generated vendored Normal file
View File

@ -0,0 +1,23 @@
syntax:glob
*.[568ao]
*.ao
*.so
*.pyc
*.swp
*.swo
._*
.nfs.*
[568a].out
*~
*.orig
*.pb.go
core
_obj
_test
src/pkg/Make.deps
_testmain.go
syntax:regexp
^pkg/
^src/cmd/(.*)/6?\1$
^.*/core.[0-9]*$

4
vendor/github.com/petar/GoLLRB/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,4 @@
Petar Maymounkov <petar@5ttt.org>
Vadim Vygonets <vadik@vygo.net>
Ian Smith <iansmith@acm.org>
Martin Bruse

27
vendor/github.com/petar/GoLLRB/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2010, Petar Maymounkov
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
(*) Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
(*) Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
(*) Neither the name of Petar Maymounkov nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

66
vendor/github.com/petar/GoLLRB/README.md generated vendored Normal file
View File

@ -0,0 +1,66 @@
# GoLLRB
GoLLRB is a Left-Leaning Red-Black (LLRB) implementation of 2-3 balanced binary
search trees in Go Language.
## Overview
As of this writing and to the best of the author's knowledge,
Go still does not have a balanced binary search tree (BBST) data structure.
These data structures are quite useful in a variety of cases. A BBST maintains
elements in sorted order under dynamic updates (inserts and deletes) and can
support various order-specific queries. Furthermore, in practice one often
implements other common data structures like Priority Queues, using BBST's.
2-3 trees (a type of BBST's), as well as the runtime-similar 2-3-4 trees, are
the de facto standard BBST algoritms found in implementations of Python, Java,
and other libraries. The LLRB method of implementing 2-3 trees is a recent
improvement over the traditional implementation. The LLRB approach was
discovered relatively recently (in 2008) by Robert Sedgewick of Princeton
University.
GoLLRB is a Go implementation of LLRB 2-3 trees.
## Maturity
GoLLRB has been used in some pretty heavy-weight machine learning tasks over many gigabytes of data.
I consider it to be in stable, perhaps even production, shape. There are no known bugs.
## Installation
With a healthy Go Language installed, simply run `go get github.com/petar/GoLLRB/llrb`
## Example
package main
import (
"fmt"
"github.com/petar/GoLLRB/llrb"
)
func lessInt(a, b interface{}) bool { return a.(int) < b.(int) }
func main() {
tree := llrb.New(lessInt)
tree.ReplaceOrInsert(1)
tree.ReplaceOrInsert(2)
tree.ReplaceOrInsert(3)
tree.ReplaceOrInsert(4)
tree.DeleteMin()
tree.Delete(4)
c := tree.IterAscend()
for {
u := <-c
if u == nil {
break
}
fmt.Printf("%d\n", int(u.(int)))
}
}
## About
GoLLRB was written by [Petar Maymounkov](http://pdos.csail.mit.edu/~petar/).
Follow me on [Twitter @maymounkov](http://www.twitter.com/maymounkov)!

4401
vendor/github.com/petar/GoLLRB/doc/Sedgewick-LLRB.pdf generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,475 @@
public class RedBlackBST<Key extends Comparable<Key>, Value>
{
private static final int BST = 0;
private static final int TD234 = 1;
private static final int BU23 = 2;
private static final boolean RED = true;
private static final boolean BLACK = false;
private Node root; // root of the BST
private int k; // ordinal for drawing
private final int species; // species kind of tree for insert
private int heightBLACK; // black height of tree
RedBlackBST(int species)
{ this.species = species; }
private class Node
{
Key key; // key
Value value; // associated data
Node left, right; // left and right subtrees
boolean color; // color of parent link
private int N; // number of nodes in tree rooted here
private int height; // height of tree rooted here
private double xc, yc; // for drawing
Node(Key key, Value value)
{
this.key = key;
this.value = value;
this.color = RED;
this.N = 1;
this.height = 1;
}
}
public int size()
{ return size(root); }
private int size(Node x)
{
if (x == null) return 0;
else return x.N;
}
public int rootRank()
{
if (root == null) return 0;
else return size(root.left);
}
public int height()
{ return height(root); }
public int heightB()
{ return heightBLACK; }
private int height(Node x)
{
if (x == null) return 0;
else return x.height;
}
public boolean contains(Key key)
{ return (get(key) != null); }
public Value get(Key key)
{ return get(root, key); }
private Value get(Node x, Key key)
{
if (x == null) return null;
if (eq (key, x.key)) return x.value;
if (less(key, x.key)) return get(x.left, key);
else return get(x.right, key);
}
public Key min()
{
if (root == null) return null;
else return min(root);
}
private Key min(Node x)
{
if (x.left == null) return x.key;
else return min(x.left);
}
public Key max()
{
if (root == null) return null;
else return max(root);
}
private Key max(Node x)
{
if (x.right == null) return x.key;
else return max(x.right);
}
public void put(Key key, Value value)
{
root = insert(root, key, value);
if (isRed(root)) heightBLACK++;
root.color = BLACK;
}
private Node insert(Node h, Key key, Value value)
{
if (h == null)
return new Node(key, value);
if (species == TD234)
if (isRed(h.left) && isRed(h.right))
colorFlip(h);
if (eq(key, h.key))
h.value = value;
else if (less(key, h.key))
h.left = insert(h.left, key, value);
else
h.right = insert(h.right, key, value);
if (species == BST) return setN(h);
if (isRed(h.right))
h = rotateLeft(h);
if (isRed(h.left) && isRed(h.left.left))
h = rotateRight(h);
if (species == BU23)
if (isRed(h.left) && isRed(h.right))
colorFlip(h);
return setN(h);
}
public void deleteMin()
{
root = deleteMin(root);
root.color = BLACK;
}
private Node deleteMin(Node h)
{
if (h.left == null)
return null;
if (!isRed(h.left) && !isRed(h.left.left))
h = moveRedLeft(h);
h.left = deleteMin(h.left);
return fixUp(h);
}
public void deleteMax()
{
root = deleteMax(root);
root.color = BLACK;
}
private Node deleteMax(Node h)
{
// if (h.right == null)
// {
// if (h.left != null)
// h.left.color = BLACK;
// return h.left;
// }
if (isRed(h.left))
h = rotateRight(h);
if (h.right == null)
return null;
if (!isRed(h.right) && !isRed(h.right.left))
h = moveRedRight(h);
h.right = deleteMax(h.right);
return fixUp(h);
}
public void delete(Key key)
{
root = delete(root, key);
root.color = BLACK;
}
private Node delete(Node h, Key key)
{
if (less(key, h.key))
{
if (!isRed(h.left) && !isRed(h.left.left))
h = moveRedLeft(h);
h.left = delete(h.left, key);
}
else
{
if (isRed(h.left))
h = rotateRight(h);
if (eq(key, h.key) && (h.right == null))
return null;
if (!isRed(h.right) && !isRed(h.right.left))
h = moveRedRight(h);
if (eq(key, h.key))
{
h.value = get(h.right, min(h.right));
h.key = min(h.right);
h.right = deleteMin(h.right);
}
else h.right = delete(h.right, key);
}
return fixUp(h);
}
// Helper methods
private boolean less(Key a, Key b) { return a.compareTo(b) < 0; }
private boolean eq (Key a, Key b) { return a.compareTo(b) == 0; }
private boolean isRed(Node x)
{
if (x == null) return false;
return (x.color == RED);
}
private void colorFlip(Node h)
{
h.color = !h.color;
h.left.color = !h.left.color;
h.right.color = !h.right.color;
}
private Node rotateLeft(Node h)
{ // Make a right-leaning 3-node lean to the left.
Node x = h.right;
h.right = x.left;
x.left = setN(h);
x.color = x.left.color;
x.left.color = RED;
return setN(x);
}
private Node rotateRight(Node h)
{ // Make a left-leaning 3-node lean to the right.
Node x = h.left;
h.left = x.right;
x.right = setN(h);
x.color = x.right.color;
x.right.color = RED;
return setN(x);
}
private Node moveRedLeft(Node h)
{ // Assuming that h is red and both h.left and h.left.left
// are black, make h.left or one of its children red.
colorFlip(h);
if (isRed(h.right.left))
{
h.right = rotateRight(h.right);
h = rotateLeft(h);
colorFlip(h);
}
return h;
}
private Node moveRedRight(Node h)
{ // Assuming that h is red and both h.right and h.right.left
// are black, make h.right or one of its children red.
colorFlip(h);
if (isRed(h.left.left))
{
h = rotateRight(h);
colorFlip(h);
}
return h;
}
private Node fixUp(Node h)
{
if (isRed(h.right))
h = rotateLeft(h);
if (isRed(h.left) && isRed(h.left.left))
h = rotateRight(h);
if (isRed(h.left) && isRed(h.right))
colorFlip(h);
return setN(h);
}
private Node setN(Node h)
{
h.N = size(h.left) + size(h.right) + 1;
if (height(h.left) > height(h.right)) h.height = height(h.left) + 1;
else h.height = height(h.right) + 1;
return h;
}
public String toString()
{
if (root == null) return "";
else return heightB() + " " + toString(root);
}
public String toString(Node x)
{
String s = "(";
if (x.left == null) s += "("; else s += toString(x.left);
if (isRed(x)) s += "*";
if (x.right == null) s += ")"; else s += toString(x.right);
return s + ")";
}
// Methods for tree drawing
public void draw(double y, double lineWidth, double nodeSize)
{
k = 0;
setcoords(root, y);
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(lineWidth);
drawlines(root);
StdDraw.setPenColor(StdDraw.WHITE);
drawnodes(root, nodeSize);
}
public void setcoords(Node x, double d)
{
if (x == null) return;
setcoords(x.left, d-.04);
x.xc = (0.5 + k++)/size(); x.yc = d - .04;
setcoords(x.right, d-.04);
}
public void drawlines(Node x)
{
if (x == null) return;
drawlines(x.left);
if (x.left != null)
{
if (x.left.color == RED) StdDraw.setPenColor(StdDraw.RED);
else StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.line(x.xc, x.yc, x.left.xc, x.left.yc);
}
if (x.right != null)
{
if (x.right.color == RED) StdDraw.setPenColor(StdDraw.RED);
else StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.line(x.xc, x.yc, x.right.xc, x.right.yc);
}
drawlines(x.right);
}
public void drawnodes(Node x, double nodeSize)
{
if (x == null) return;
drawnodes(x.left, nodeSize);
StdDraw.filledCircle(x.xc, x.yc, nodeSize);
drawnodes(x.right, nodeSize);
}
public void mark(Key key)
{
StdDraw.setPenColor(StdDraw.BLACK);
marknodes(key, root);
}
public void marknodes(Key key, Node x)
{
if (x == null) return;
marknodes(key, x.left);
if (eq(key, x.key))
StdDraw.filledCircle(x.xc, x.yc, .004);
marknodes(key, x.right);
}
public int ipl()
{ return ipl(root); }
public int ipl(Node x)
{
if (x == null) return 0;
return size(x) - 1 + ipl(x.left) + ipl(x.right);
}
public int sizeRed()
{ return sizeRed(root); }
public int sizeRed(Node x)
{
if (x == null) return 0;
if (isRed(x)) return 1 + sizeRed(x.left) + sizeRed(x.right);
else return sizeRed(x.left) + sizeRed(x.right);
}
// Integrity checks
public boolean check()
{ // Is this tree a red-black tree?
return isBST() && is234() && isBalanced();
}
private boolean isBST()
{ // Is this tree a BST?
return isBST(root, min(), max());
}
private boolean isBST(Node x, Key min, Key max)
{ // Are all the values in the BST rooted at x between min and max,
// and does the same property hold for both subtrees?
if (x == null) return true;
if (less(x.key, min) || less(max, x.key)) return false;
return isBST(x.left, min, x.key) && isBST(x.right, x.key, max);
}
private boolean is234() { return is234(root); }
private boolean is234(Node x)
{ // Does the tree have no red right links, and at most two (left)
// red links in a row on any path?
if (x == null) return true;
if (isRed(x.right)) return false;
if (isRed(x))
if (isRed(x.left))
if (isRed(x.left.left)) return false;
return is234(x.left) && is234(x.right);
}
private boolean isBalanced()
{ // Do all paths from root to leaf have same number of black edges?
int black = 0; // number of black links on path from root to min
Node x = root;
while (x != null)
{
if (!isRed(x)) black++;
x = x.left;
}
return isBalanced(root, black);
}
private boolean isBalanced(Node x, int black)
{ // Does every path from the root to a leaf have the given number
// of black links?
if (x == null && black == 0) return true;
else if (x == null && black != 0) return false;
if (!isRed(x)) black--;
return isBalanced(x.left, black) && isBalanced(x.right, black);
}
public static void main(String[] args)
{
StdDraw.setPenRadius(.0025);
int species = Integer.parseInt(args[0]);
RedBlackBST<Integer, Integer> st;
st = new RedBlackBST<Integer, Integer>(species);
int[] a = { 3, 1, 4, 2, 5, 9, 6, 8, 7 };
for (int i = 0; i < a.length; i++)
st.put(a[i], i);
StdOut.println(st);
StdDraw.clear(StdDraw.LIGHT_GRAY);
st.draw(.95, .0025, .008);
StdOut.println(st.min() + " " + st.max() + " " + st.check());
StdOut.println(st.ipl());
StdOut.println(st.heightB());
}
}

Binary file not shown.

26
vendor/github.com/petar/GoLLRB/example/ex1.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
package main
import (
"fmt"
"github.com/petar/GoLLRB/llrb"
)
func lessInt(a, b interface{}) bool { return a.(int) < b.(int) }
func main() {
tree := llrb.New(lessInt)
tree.ReplaceOrInsert(1)
tree.ReplaceOrInsert(2)
tree.ReplaceOrInsert(3)
tree.ReplaceOrInsert(4)
tree.DeleteMin()
tree.Delete(4)
c := tree.IterAscend()
for {
u := <-c
if u == nil {
break
}
fmt.Printf("%d\n", int(u.(int)))
}
}

39
vendor/github.com/petar/GoLLRB/llrb/avgvar.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2010 Petar Maymounkov. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package llrb
import "math"
// avgVar maintains the average and variance of a stream of numbers
// in a space-efficient manner.
type avgVar struct {
count int64
sum, sumsq float64
}
func (av *avgVar) Init() {
av.count = 0
av.sum = 0.0
av.sumsq = 0.0
}
func (av *avgVar) Add(sample float64) {
av.count++
av.sum += sample
av.sumsq += sample * sample
}
func (av *avgVar) GetCount() int64 { return av.count }
func (av *avgVar) GetAvg() float64 { return av.sum / float64(av.count) }
func (av *avgVar) GetTotal() float64 { return av.sum }
func (av *avgVar) GetVar() float64 {
a := av.GetAvg()
return av.sumsq/float64(av.count) - a*a
}
func (av *avgVar) GetStdDev() float64 { return math.Sqrt(av.GetVar()) }

93
vendor/github.com/petar/GoLLRB/llrb/iterator.go generated vendored Normal file
View File

@ -0,0 +1,93 @@
package llrb
type ItemIterator func(i Item) bool
//func (t *Tree) Ascend(iterator ItemIterator) {
// t.AscendGreaterOrEqual(Inf(-1), iterator)
//}
func (t *LLRB) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) {
t.ascendRange(t.root, greaterOrEqual, lessThan, iterator)
}
func (t *LLRB) ascendRange(h *Node, inf, sup Item, iterator ItemIterator) bool {
if h == nil {
return true
}
if !less(h.Item, sup) {
return t.ascendRange(h.Left, inf, sup, iterator)
}
if less(h.Item, inf) {
return t.ascendRange(h.Right, inf, sup, iterator)
}
if !t.ascendRange(h.Left, inf, sup, iterator) {
return false
}
if !iterator(h.Item) {
return false
}
return t.ascendRange(h.Right, inf, sup, iterator)
}
// AscendGreaterOrEqual will call iterator once for each element greater or equal to
// pivot in ascending order. It will stop whenever the iterator returns false.
func (t *LLRB) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) {
t.ascendGreaterOrEqual(t.root, pivot, iterator)
}
func (t *LLRB) ascendGreaterOrEqual(h *Node, pivot Item, iterator ItemIterator) bool {
if h == nil {
return true
}
if !less(h.Item, pivot) {
if !t.ascendGreaterOrEqual(h.Left, pivot, iterator) {
return false
}
if !iterator(h.Item) {
return false
}
}
return t.ascendGreaterOrEqual(h.Right, pivot, iterator)
}
func (t *LLRB) AscendLessThan(pivot Item, iterator ItemIterator) {
t.ascendLessThan(t.root, pivot, iterator)
}
func (t *LLRB) ascendLessThan(h *Node, pivot Item, iterator ItemIterator) bool {
if h == nil {
return true
}
if !t.ascendLessThan(h.Left, pivot, iterator) {
return false
}
if !iterator(h.Item) {
return false
}
if less(h.Item, pivot) {
return t.ascendLessThan(h.Left, pivot, iterator)
}
return true
}
// DescendLessOrEqual will call iterator once for each element less than the
// pivot in descending order. It will stop whenever the iterator returns false.
func (t *LLRB) DescendLessOrEqual(pivot Item, iterator ItemIterator) {
t.descendLessOrEqual(t.root, pivot, iterator)
}
func (t *LLRB) descendLessOrEqual(h *Node, pivot Item, iterator ItemIterator) bool {
if h == nil {
return true
}
if less(h.Item, pivot) || !less(pivot, h.Item) {
if !t.descendLessOrEqual(h.Right, pivot, iterator) {
return false
}
if !iterator(h.Item) {
return false
}
}
return t.descendLessOrEqual(h.Left, pivot, iterator)
}

76
vendor/github.com/petar/GoLLRB/llrb/iterator_test.go generated vendored Normal file
View File

@ -0,0 +1,76 @@
package llrb
import (
"reflect"
"testing"
)
func TestAscendGreaterOrEqual(t *testing.T) {
tree := New()
tree.InsertNoReplace(Int(4))
tree.InsertNoReplace(Int(6))
tree.InsertNoReplace(Int(1))
tree.InsertNoReplace(Int(3))
var ary []Item
tree.AscendGreaterOrEqual(Int(-1), func(i Item) bool {
ary = append(ary, i)
return true
})
expected := []Item{Int(1), Int(3), Int(4), Int(6)}
if !reflect.DeepEqual(ary, expected) {
t.Errorf("expected %v but got %v", expected, ary)
}
ary = nil
tree.AscendGreaterOrEqual(Int(3), func(i Item) bool {
ary = append(ary, i)
return true
})
expected = []Item{Int(3), Int(4), Int(6)}
if !reflect.DeepEqual(ary, expected) {
t.Errorf("expected %v but got %v", expected, ary)
}
ary = nil
tree.AscendGreaterOrEqual(Int(2), func(i Item) bool {
ary = append(ary, i)
return true
})
expected = []Item{Int(3), Int(4), Int(6)}
if !reflect.DeepEqual(ary, expected) {
t.Errorf("expected %v but got %v", expected, ary)
}
}
func TestDescendLessOrEqual(t *testing.T) {
tree := New()
tree.InsertNoReplace(Int(4))
tree.InsertNoReplace(Int(6))
tree.InsertNoReplace(Int(1))
tree.InsertNoReplace(Int(3))
var ary []Item
tree.DescendLessOrEqual(Int(10), func(i Item) bool {
ary = append(ary, i)
return true
})
expected := []Item{Int(6), Int(4), Int(3), Int(1)}
if !reflect.DeepEqual(ary, expected) {
t.Errorf("expected %v but got %v", expected, ary)
}
ary = nil
tree.DescendLessOrEqual(Int(4), func(i Item) bool {
ary = append(ary, i)
return true
})
expected = []Item{Int(4), Int(3), Int(1)}
if !reflect.DeepEqual(ary, expected) {
t.Errorf("expected %v but got %v", expected, ary)
}
ary = nil
tree.DescendLessOrEqual(Int(5), func(i Item) bool {
ary = append(ary, i)
return true
})
expected = []Item{Int(4), Int(3), Int(1)}
if !reflect.DeepEqual(ary, expected) {
t.Errorf("expected %v but got %v", expected, ary)
}
}

46
vendor/github.com/petar/GoLLRB/llrb/llrb-stats.go generated vendored Normal file
View File

@ -0,0 +1,46 @@
// Copyright 2010 Petar Maymounkov. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package llrb
// GetHeight() returns an item in the tree with key @key, and it's height in the tree
func (t *LLRB) GetHeight(key Item) (result Item, depth int) {
return t.getHeight(t.root, key)
}
func (t *LLRB) getHeight(h *Node, item Item) (Item, int) {
if h == nil {
return nil, 0
}
if less(item, h.Item) {
result, depth := t.getHeight(h.Left, item)
return result, depth + 1
}
if less(h.Item, item) {
result, depth := t.getHeight(h.Right, item)
return result, depth + 1
}
return h.Item, 0
}
// HeightStats() returns the average and standard deviation of the height
// of elements in the tree
func (t *LLRB) HeightStats() (avg, stddev float64) {
av := &avgVar{}
heightStats(t.root, 0, av)
return av.GetAvg(), av.GetStdDev()
}
func heightStats(h *Node, d int, av *avgVar) {
if h == nil {
return
}
av.Add(float64(d))
if h.Left != nil {
heightStats(h.Left, d+1, av)
}
if h.Right != nil {
heightStats(h.Right, d+1, av)
}
}

456
vendor/github.com/petar/GoLLRB/llrb/llrb.go generated vendored Normal file
View File

@ -0,0 +1,456 @@
// Copyright 2010 Petar Maymounkov. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// A Left-Leaning Red-Black (LLRB) implementation of 2-3 balanced binary search trees,
// based on the following work:
//
// http://www.cs.princeton.edu/~rs/talks/LLRB/08Penn.pdf
// http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf
// http://www.cs.princeton.edu/~rs/talks/LLRB/Java/RedBlackBST.java
//
// 2-3 trees (and the run-time equivalent 2-3-4 trees) are the de facto standard BST
// algoritms found in implementations of Python, Java, and other libraries. The LLRB
// implementation of 2-3 trees is a recent improvement on the traditional implementation,
// observed and documented by Robert Sedgewick.
//
package llrb
// Tree is a Left-Leaning Red-Black (LLRB) implementation of 2-3 trees
type LLRB struct {
count int
root *Node
}
type Node struct {
Item
Left, Right *Node // Pointers to left and right child nodes
Black bool // If set, the color of the link (incoming from the parent) is black
// In the LLRB, new nodes are always red, hence the zero-value for node
}
type Item interface {
Less(than Item) bool
}
//
func less(x, y Item) bool {
if x == pinf {
return false
}
if x == ninf {
return true
}
return x.Less(y)
}
// Inf returns an Item that is "bigger than" any other item, if sign is positive.
// Otherwise it returns an Item that is "smaller than" any other item.
func Inf(sign int) Item {
if sign == 0 {
panic("sign")
}
if sign > 0 {
return pinf
}
return ninf
}
var (
ninf = nInf{}
pinf = pInf{}
)
type nInf struct{}
func (nInf) Less(Item) bool {
return true
}
type pInf struct{}
func (pInf) Less(Item) bool {
return false
}
// New() allocates a new tree
func New() *LLRB {
return &LLRB{}
}
// SetRoot sets the root node of the tree.
// It is intended to be used by functions that deserialize the tree.
func (t *LLRB) SetRoot(r *Node) {
t.root = r
}
// Root returns the root node of the tree.
// It is intended to be used by functions that serialize the tree.
func (t *LLRB) Root() *Node {
return t.root
}
// Len returns the number of nodes in the tree.
func (t *LLRB) Len() int { return t.count }
// Has returns true if the tree contains an element whose order is the same as that of key.
func (t *LLRB) Has(key Item) bool {
return t.Get(key) != nil
}
// Get retrieves an element from the tree whose order is the same as that of key.
func (t *LLRB) Get(key Item) Item {
h := t.root
for h != nil {
switch {
case less(key, h.Item):
h = h.Left
case less(h.Item, key):
h = h.Right
default:
return h.Item
}
}
return nil
}
// Min returns the minimum element in the tree.
func (t *LLRB) Min() Item {
h := t.root
if h == nil {
return nil
}
for h.Left != nil {
h = h.Left
}
return h.Item
}
// Max returns the maximum element in the tree.
func (t *LLRB) Max() Item {
h := t.root
if h == nil {
return nil
}
for h.Right != nil {
h = h.Right
}
return h.Item
}
func (t *LLRB) ReplaceOrInsertBulk(items ...Item) {
for _, i := range items {
t.ReplaceOrInsert(i)
}
}
func (t *LLRB) InsertNoReplaceBulk(items ...Item) {
for _, i := range items {
t.InsertNoReplace(i)
}
}
// ReplaceOrInsert inserts item into the tree. If an existing
// element has the same order, it is removed from the tree and returned.
func (t *LLRB) ReplaceOrInsert(item Item) Item {
if item == nil {
panic("inserting nil item")
}
var replaced Item
t.root, replaced = t.replaceOrInsert(t.root, item)
t.root.Black = true
if replaced == nil {
t.count++
}
return replaced
}
func (t *LLRB) replaceOrInsert(h *Node, item Item) (*Node, Item) {
if h == nil {
return newNode(item), nil
}
h = walkDownRot23(h)
var replaced Item
if less(item, h.Item) { // BUG
h.Left, replaced = t.replaceOrInsert(h.Left, item)
} else if less(h.Item, item) {
h.Right, replaced = t.replaceOrInsert(h.Right, item)
} else {
replaced, h.Item = h.Item, item
}
h = walkUpRot23(h)
return h, replaced
}
// InsertNoReplace inserts item into the tree. If an existing
// element has the same order, both elements remain in the tree.
func (t *LLRB) InsertNoReplace(item Item) {
if item == nil {
panic("inserting nil item")
}
t.root = t.insertNoReplace(t.root, item)
t.root.Black = true
t.count++
}
func (t *LLRB) insertNoReplace(h *Node, item Item) *Node {
if h == nil {
return newNode(item)
}
h = walkDownRot23(h)
if less(item, h.Item) {
h.Left = t.insertNoReplace(h.Left, item)
} else {
h.Right = t.insertNoReplace(h.Right, item)
}
return walkUpRot23(h)
}
// Rotation driver routines for 2-3 algorithm
func walkDownRot23(h *Node) *Node { return h }
func walkUpRot23(h *Node) *Node {
if isRed(h.Right) && !isRed(h.Left) {
h = rotateLeft(h)
}
if isRed(h.Left) && isRed(h.Left.Left) {
h = rotateRight(h)
}
if isRed(h.Left) && isRed(h.Right) {
flip(h)
}
return h
}
// Rotation driver routines for 2-3-4 algorithm
func walkDownRot234(h *Node) *Node {
if isRed(h.Left) && isRed(h.Right) {
flip(h)
}
return h
}
func walkUpRot234(h *Node) *Node {
if isRed(h.Right) && !isRed(h.Left) {
h = rotateLeft(h)
}
if isRed(h.Left) && isRed(h.Left.Left) {
h = rotateRight(h)
}
return h
}
// DeleteMin deletes the minimum element in the tree and returns the
// deleted item or nil otherwise.
func (t *LLRB) DeleteMin() Item {
var deleted Item
t.root, deleted = deleteMin(t.root)
if t.root != nil {
t.root.Black = true
}
if deleted != nil {
t.count--
}
return deleted
}
// deleteMin code for LLRB 2-3 trees
func deleteMin(h *Node) (*Node, Item) {
if h == nil {
return nil, nil
}
if h.Left == nil {
return nil, h.Item
}
if !isRed(h.Left) && !isRed(h.Left.Left) {
h = moveRedLeft(h)
}
var deleted Item
h.Left, deleted = deleteMin(h.Left)
return fixUp(h), deleted
}
// DeleteMax deletes the maximum element in the tree and returns
// the deleted item or nil otherwise
func (t *LLRB) DeleteMax() Item {
var deleted Item
t.root, deleted = deleteMax(t.root)
if t.root != nil {
t.root.Black = true
}
if deleted != nil {
t.count--
}
return deleted
}
func deleteMax(h *Node) (*Node, Item) {
if h == nil {
return nil, nil
}
if isRed(h.Left) {
h = rotateRight(h)
}
if h.Right == nil {
return nil, h.Item
}
if !isRed(h.Right) && !isRed(h.Right.Left) {
h = moveRedRight(h)
}
var deleted Item
h.Right, deleted = deleteMax(h.Right)
return fixUp(h), deleted
}
// Delete deletes an item from the tree whose key equals key.
// The deleted item is return, otherwise nil is returned.
func (t *LLRB) Delete(key Item) Item {
var deleted Item
t.root, deleted = t.delete(t.root, key)
if t.root != nil {
t.root.Black = true
}
if deleted != nil {
t.count--
}
return deleted
}
func (t *LLRB) delete(h *Node, item Item) (*Node, Item) {
var deleted Item
if h == nil {
return nil, nil
}
if less(item, h.Item) {
if h.Left == nil { // item not present. Nothing to delete
return h, nil
}
if !isRed(h.Left) && !isRed(h.Left.Left) {
h = moveRedLeft(h)
}
h.Left, deleted = t.delete(h.Left, item)
} else {
if isRed(h.Left) {
h = rotateRight(h)
}
// If @item equals @h.Item and no right children at @h
if !less(h.Item, item) && h.Right == nil {
return nil, h.Item
}
// PETAR: Added 'h.Right != nil' below
if h.Right != nil && !isRed(h.Right) && !isRed(h.Right.Left) {
h = moveRedRight(h)
}
// If @item equals @h.Item, and (from above) 'h.Right != nil'
if !less(h.Item, item) {
var subDeleted Item
h.Right, subDeleted = deleteMin(h.Right)
if subDeleted == nil {
panic("logic")
}
deleted, h.Item = h.Item, subDeleted
} else { // Else, @item is bigger than @h.Item
h.Right, deleted = t.delete(h.Right, item)
}
}
return fixUp(h), deleted
}
// Internal node manipulation routines
func newNode(item Item) *Node { return &Node{Item: item} }
func isRed(h *Node) bool {
if h == nil {
return false
}
return !h.Black
}
func rotateLeft(h *Node) *Node {
x := h.Right
if x.Black {
panic("rotating a black link")
}
h.Right = x.Left
x.Left = h
x.Black = h.Black
h.Black = false
return x
}
func rotateRight(h *Node) *Node {
x := h.Left
if x.Black {
panic("rotating a black link")
}
h.Left = x.Right
x.Right = h
x.Black = h.Black
h.Black = false
return x
}
// REQUIRE: Left and Right children must be present
func flip(h *Node) {
h.Black = !h.Black
h.Left.Black = !h.Left.Black
h.Right.Black = !h.Right.Black
}
// REQUIRE: Left and Right children must be present
func moveRedLeft(h *Node) *Node {
flip(h)
if isRed(h.Right.Left) {
h.Right = rotateRight(h.Right)
h = rotateLeft(h)
flip(h)
}
return h
}
// REQUIRE: Left and Right children must be present
func moveRedRight(h *Node) *Node {
flip(h)
if isRed(h.Left.Left) {
h = rotateRight(h)
flip(h)
}
return h
}
func fixUp(h *Node) *Node {
if isRed(h.Right) {
h = rotateLeft(h)
}
if isRed(h.Left) && isRed(h.Left.Left) {
h = rotateRight(h)
}
if isRed(h.Left) && isRed(h.Right) {
flip(h)
}
return h
}

239
vendor/github.com/petar/GoLLRB/llrb/llrb_test.go generated vendored Normal file
View File

@ -0,0 +1,239 @@
// Copyright 2010 Petar Maymounkov. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package llrb
import (
"math"
"math/rand"
"testing"
)
func TestCases(t *testing.T) {
tree := New()
tree.ReplaceOrInsert(Int(1))
tree.ReplaceOrInsert(Int(1))
if tree.Len() != 1 {
t.Errorf("expecting len 1")
}
if !tree.Has(Int(1)) {
t.Errorf("expecting to find key=1")
}
tree.Delete(Int(1))
if tree.Len() != 0 {
t.Errorf("expecting len 0")
}
if tree.Has(Int(1)) {
t.Errorf("not expecting to find key=1")
}
tree.Delete(Int(1))
if tree.Len() != 0 {
t.Errorf("expecting len 0")
}
if tree.Has(Int(1)) {
t.Errorf("not expecting to find key=1")
}
}
func TestReverseInsertOrder(t *testing.T) {
tree := New()
n := 100
for i := 0; i < n; i++ {
tree.ReplaceOrInsert(Int(n - i))
}
i := 0
tree.AscendGreaterOrEqual(Int(0), func(item Item) bool {
i++
if item.(Int) != Int(i) {
t.Errorf("bad order: got %d, expect %d", item.(Int), i)
}
return true
})
}
func TestRange(t *testing.T) {
tree := New()
order := []String{
"ab", "aba", "abc", "a", "aa", "aaa", "b", "a-", "a!",
}
for _, i := range order {
tree.ReplaceOrInsert(i)
}
k := 0
tree.AscendRange(String("ab"), String("ac"), func(item Item) bool {
if k > 3 {
t.Fatalf("returned more items than expected")
}
i1 := order[k]
i2 := item.(String)
if i1 != i2 {
t.Errorf("expecting %s, got %s", i1, i2)
}
k++
return true
})
}
func TestRandomInsertOrder(t *testing.T) {
tree := New()
n := 1000
perm := rand.Perm(n)
for i := 0; i < n; i++ {
tree.ReplaceOrInsert(Int(perm[i]))
}
j := 0
tree.AscendGreaterOrEqual(Int(0), func(item Item) bool {
if item.(Int) != Int(j) {
t.Fatalf("bad order")
}
j++
return true
})
}
func TestRandomReplace(t *testing.T) {
tree := New()
n := 100
perm := rand.Perm(n)
for i := 0; i < n; i++ {
tree.ReplaceOrInsert(Int(perm[i]))
}
perm = rand.Perm(n)
for i := 0; i < n; i++ {
if replaced := tree.ReplaceOrInsert(Int(perm[i])); replaced == nil || replaced.(Int) != Int(perm[i]) {
t.Errorf("error replacing")
}
}
}
func TestRandomInsertSequentialDelete(t *testing.T) {
tree := New()
n := 1000
perm := rand.Perm(n)
for i := 0; i < n; i++ {
tree.ReplaceOrInsert(Int(perm[i]))
}
for i := 0; i < n; i++ {
tree.Delete(Int(i))
}
}
func TestRandomInsertDeleteNonExistent(t *testing.T) {
tree := New()
n := 100
perm := rand.Perm(n)
for i := 0; i < n; i++ {
tree.ReplaceOrInsert(Int(perm[i]))
}
if tree.Delete(Int(200)) != nil {
t.Errorf("deleted non-existent item")
}
if tree.Delete(Int(-2)) != nil {
t.Errorf("deleted non-existent item")
}
for i := 0; i < n; i++ {
if u := tree.Delete(Int(i)); u == nil || u.(Int) != Int(i) {
t.Errorf("delete failed")
}
}
if tree.Delete(Int(200)) != nil {
t.Errorf("deleted non-existent item")
}
if tree.Delete(Int(-2)) != nil {
t.Errorf("deleted non-existent item")
}
}
func TestRandomInsertPartialDeleteOrder(t *testing.T) {
tree := New()
n := 100
perm := rand.Perm(n)
for i := 0; i < n; i++ {
tree.ReplaceOrInsert(Int(perm[i]))
}
for i := 1; i < n-1; i++ {
tree.Delete(Int(i))
}
j := 0
tree.AscendGreaterOrEqual(Int(0), func(item Item) bool {
switch j {
case 0:
if item.(Int) != Int(0) {
t.Errorf("expecting 0")
}
case 1:
if item.(Int) != Int(n-1) {
t.Errorf("expecting %d", n-1)
}
}
j++
return true
})
}
func TestRandomInsertStats(t *testing.T) {
tree := New()
n := 100000
perm := rand.Perm(n)
for i := 0; i < n; i++ {
tree.ReplaceOrInsert(Int(perm[i]))
}
avg, _ := tree.HeightStats()
expAvg := math.Log2(float64(n)) - 1.5
if math.Abs(avg-expAvg) >= 2.0 {
t.Errorf("too much deviation from expected average height")
}
}
func BenchmarkInsert(b *testing.B) {
tree := New()
for i := 0; i < b.N; i++ {
tree.ReplaceOrInsert(Int(b.N - i))
}
}
func BenchmarkDelete(b *testing.B) {
b.StopTimer()
tree := New()
for i := 0; i < b.N; i++ {
tree.ReplaceOrInsert(Int(b.N - i))
}
b.StartTimer()
for i := 0; i < b.N; i++ {
tree.Delete(Int(i))
}
}
func BenchmarkDeleteMin(b *testing.B) {
b.StopTimer()
tree := New()
for i := 0; i < b.N; i++ {
tree.ReplaceOrInsert(Int(b.N - i))
}
b.StartTimer()
for i := 0; i < b.N; i++ {
tree.DeleteMin()
}
}
func TestInsertNoReplace(t *testing.T) {
tree := New()
n := 1000
for q := 0; q < 2; q++ {
perm := rand.Perm(n)
for i := 0; i < n; i++ {
tree.InsertNoReplace(Int(perm[i]))
}
}
j := 0
tree.AscendGreaterOrEqual(Int(0), func(item Item) bool {
if item.(Int) != Int(j/2) {
t.Fatalf("bad order")
}
j++
return true
})
}

17
vendor/github.com/petar/GoLLRB/llrb/util.go generated vendored Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2010 Petar Maymounkov. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package llrb
type Int int
func (x Int) Less(than Item) bool {
return x < than.(Int)
}
type String string
func (x String) Less(than Item) bool {
return x < than.(String)
}