Что такое идиоматические способ реализации красно-черного дерева в 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, aRedBlackTree
что "расширяет"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