Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
456 lines
8.9 KiB
456 lines
8.9 KiB
// 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 |
|
}
|
|
|