Что такое идиоматические способ реализации красно-черного дерева в Go?

я новичок в Go и реализовал двоичное дерево поиска. Дерево может хранить любое значение (в частности, все, что реализует interface{}).

я хотел бы развить эту реализацию, чтобы создать самобалансирующееся красно-черное дерево. В объектно-ориентированном языке я бы определил подкласс BinarySearchTree добавляет color элемент данных, затем переопределите Insert метод для выполнения операции балансировки.

вопрос: Как я могу реализовать двоичный поиск дерево и красно-черное дерево в Go без дублирования кода?

Текущая Реализация Дерева Бинарного Поиска

вот моя реализация дерева бинарного поиска:

package trees

import (
    "github.com/modocache/cargo/comparators"
    "reflect"
)

type BinarySearchTree struct {
    Parent *BinarySearchTree
    Left   *BinarySearchTree
    Right  *BinarySearchTree
    Value  interface{}      // Can hold any value
    less   comparators.Less // A comparator function to determine whether
                            // an inserted value is placed left or right
}

func NewBinarySearchTree(value interface{}, less comparators.Less) *BinarySearchTree {
    return &BinarySearchTree{Value: value, less: less}
}

func (tree *BinarySearchTree) Insert(value interface{}) *BinarySearchTree {
    if tree.less(value, tree.Value) {
        return tree.insertLeft(value)
    } else {
        return tree.insertRight(value)
    }
}

func (tree *BinarySearchTree) insertLeft(value interface{}) *BinarySearchTree {
    if tree.Left == nil {
        tree.Left = &BinarySearchTree{Value: value, Parent: tree, less: tree.less}
        return tree.Left
    } else {
        return tree.Left.Insert(value)
    }
}

func (tree *BinarySearchTree) insertRight(value interface{}) *BinarySearchTree {
    if tree.Right == nil {
        tree.Right = &BinarySearchTree{Value: value, Parent: tree, less: tree.less}
        return tree.Right
    } else {
        return tree.Right.Insert(value)
    }
}

func (tree *BinarySearchTree) Find(value interface{}) *BinarySearchTree {
    if reflect.DeepEqual(value, tree.Value) {
        return tree
    } else if tree.less(value, tree.Value) {
        return tree.findLeft(value)
    } else {
        return tree.findRight(value)
    }
}

func (tree *BinarySearchTree) findLeft(value interface{}) *BinarySearchTree {
    if tree.Left == nil {
        return nil
    } else {
        return tree.Left.Find(value)
    }
}

func (tree *BinarySearchTree) findRight(value interface{}) *BinarySearchTree {
    if tree.Right == nil {
        return nil
    } else {
        return tree.Right.Find(value)
    }
}

вот пример того, как эта структура может быть использована:

tree := NewBinarySearchTree(100, func(value, treeValue interface{}) bool {
    return value.(int) < treeValue.(int)
})
tree.Insert(200)
tree.Insert(300)
tree.Insert(250)
tree.Insert(150)
tree.Insert(275)
tree.Find(250) // Returns tree.Right.Right.Left

Желаемая (Но Невозможная) Реализация Красно-Черного Дерева

я хотел бы "расширить"BinarySearchTree struct вот так:

type RedBlackTree struct {
    Parent *RedBlackTree     // These must be able to store
    Left   *RedBlackTree     // pointers to red-black trees
    Right  *RedBlackTree
    Value  interface{}
    less   comparators.Less
    color RedBlackTreeColor  // Each tree must maintain a color property
}

и затем "переопределить".Insert() способ вот так:

func (tree *RedBlackTree) Insert(value interface{}) *RedBlackTree {
    var inserted *RedBlackTree

    // Insertion logic is identical to BinarySearchTree
    if tree.less(value, tree.Value) {
        inserted = tree.insertLeft(value)
    } else {
        inserted tree.insertRight(value)
    }

    // .balance() is a private method on RedBlackTree that balances
    // the tree based on each node's color
    inserted.balance()

    // Returns a *RedBlackTree
    return inserted
}

я не думаю, что это идиоматический код Go, однако.

  • С BinarySearchTree определяется указателями на другие BinarySearchTree structs, a RedBlackTree что "расширяет" BinarySearchTree еще есть указатели на BinarySearchTree объекты.
  • нет никакого способа, чтобы "перекрыть" .Insert(). Мой единственный вариант-определить другой метод, например .BalancedInsert().

В Настоящее Время

одна идея, которую я сейчас пытаюсь определить интерфейс, такой как этот:

type BinarySearchable interface {
    Parent() *BinarySearchable
    SetParent(searchable *BinarySearchable)

    Left() *BinarySearchable
    SetLeft(searchable *BinarySearchable)

    Right() *BinarySearchable
    SetRight(searchable *BinarySearchable)

    Value() interface{}
    Less() comparators.Less
    Insert(searchable *BinarySearchable) *BinarySearchable
    Find(value interface{}) *BinarySearchable
}

на BinarySearchTree и RedBlackTree затем реализует эти интерфейсы. Одна из проблем заключается в том, как поделиться .Insert() логика, однако. Возможно, определите частную функцию, которую будет использовать каждая структура?

любые предложения приветствуются.

2 ответов


вот что я придумал. Я бы предпочел принять другой ответ, но пока это лучшее.

на BinarySearchable интерфейс

и BinarySearchTree и RedBlackTree соответствуют этому интерфейсу. Файл также определяет функции, общие для всех бинарных структур с возможностью поиска, включая insert(), .find(), leftRotate() и так далее.

для динамического создания объектов различных типов,


вы можете использовать встраивание для example :

type A struct{}

func (a *A) fn()  { fmt.Println("A.fn") }
func (a *A) fn1() { fmt.Println("A.fn1") }

type B struct{ *A }

func (a *B) fn() { fmt.Println("B.fn") }

func main() {
    b := &B{&A{}}
    b.fn()
    b.fn1()
}

это должно переопределить BST Insert но сохранить все другие функции:

type RedBlackTree struct {
    *BinarySearchTree
    color RedBlackTreeColor // This is the only new attribute
}

func (tree *RedBlackTree) Insert(value interface{}) *RedBlackTree {}

http://golang.org/doc/effective_go.html#embedding

/ / edit

перечитывая вопрос, вам придется немного изменить логику

type RedBlackTree struct {
    *BinarySearchTree
}
type rbtValue struct {
    value interface{}
    Color RedBlackTreeColor
}
func (tree *RedBlackTree) Insert(value interface{}) (inserted *RedBlackTree) {
    if tree.less(value, tree.Value) {
        inserted = tree.insertLeft(&rbt{value, Red})
    } else {
        inserted = tree.insertRight(&rbt{value, Black})
    }
    inserted.balance()
    return inserted
}

затем сделайте компаратор, который работает на tree.Value.(rbtValue).Value