tree

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 2, 2025 License: MIT Imports: 7 Imported by: 0

README

Tree

Provides a standardized way of working with binary search trees in Go, as well as several binary search tree implementations. Oriented towards competitive programming or the implementation of other data structures such as ordered sets and ordered multisets.

While this library includes common tree algorithms, they are offered as an extension. The core library exposes a minimal set of operations standardized across all common tree types, which can be used to implement tree algorithms.

The following interfaces abstracts Trees and Nodes, respectively:

type Tree[T cmp.Ordered] interface {
	Root() Node[T]
	Size() int
	Count(value T) int
	Insert(value T) error
	Delete(value T) error
}

type Node[T cmp.Ordered] interface {
	Value() T
	Count() int
	Parent() Node[T]
	Left() Node[T]
	Right() Node[T]
}

Available implementations

  • tree.BST (regular tree)

This implementation preserves the binary search tree properties upon addition and deletion, but doesn't do any kind of rebalancing. Operations should have O(lg n) complexity on avegrage, with worst case complexity going up to O(n) (e.g. if adding consecutive numbers to the tree).

  • tree.RBT (red black tree)

This implements a self-balancing binary search tree using a technique called "red-black tree". Because a tree of this kind has a height smaller or equal than 2lg(n+1) where n is the number of nodes, operations have O(lg n) both average and worst case complexity.

Installation

Install with

go get github.com/Ozoniuss/tree

Usage

The library is generic, allowing you to define trees on any value set that can be ordered.

func main() {
    // Instantiate a regular BST with int values.
    t1 := tree.NewBST[int]()

    // Insert values in the tree
    t1.Insert(4)
    t1.Insert(1)
    t1.Insert(8)
    t1.Insert(6)
    t1.Insert(9)
    t1.Insert(5)
    t1.Insert(11)
    t1.Insert(13)

    // Print the tree
    fmt.Println(t1)
}

Output:

  4         
 / \        
1   8       
   / \      
  6   9     
 /     \    
5       11  
         \  
          13
func main() {
    // Instantiate a regular BST with string values.
    t2 := tree.NewBST[string]()
    
    // Insert values in the tree
    t2.Insert("5sfhskfuceskjvsdnkvjkdsn")
    t2.Insert("1dbfalkfbdslkjfbadslkfbl")
    t2.Insert("3dbfalkfbdslkjfbadslkfbl")
    t2.Insert("8dsbflkjsdbfjzhklsdbfljkds")
    t2.Insert("7dsbflkjsdbfjzhklsdbfljkds")
    t2.Insert("9dsbflkjsdbfjzhklsdbfljkds")

    // Print the tree using a more compact formatting
    fmt.Println(tree.FormatTree(t2, tree.FormatHorizontalSquared))
}

Output:

                     5sfhskfuceskjvsdnkvjkdsn                                    
           ┌────────────────────┬────────────────────┐                           
1dbfalkfbdslkjfbadslkfbl                 8dsbflkjsdbfjzhklsdbfljkds              
           └┐                          ┌─────────────┬─────────────┐             
 3dbfalkfbdslkjfbadslkfbl  7dsbflkjsdbfjzhklsdbfljkds  9dsbflkjsdbfjzhklsdbfljkds

Printing

The code for printing the tree horizontally is ported from @billvanyo's tree_printer Java library, excluding the options to print multiple trees and allowing direction agnostic branches (that is, using a character like | to link the parent to the child). If you'd like to understand how it works, I did my best to document the printer source code.

For more examples on how the horizontal printer behaves, visit @billvanyo's github repository

There is also a vertical tree formatter inspired from the Linux tree utility that I implemented myself. See the FormatTree options for how to specify the formatter.

[!TIP] Red-black trees are printed with colored nodes.

Documentation

Index

Constants

View Source
const (
	/*
	   FormatLinuxTree formats the tree nicely as a string.

	   	    4
	   	   / \
	   	  2   12
	   	 /   / \
	   	1   8   13
	   	   / \
	   	  6   9
	   	 /     \
	   	5       11

	   would get converted to

	   	4
	   	├── 2
	   	│   ├── 1
	   	│   └── *
	   	└── 12
	   		├── 8
	   		│   ├── 6
	   		│   │   ├── 5
	   		│   │   └── *
	   		│   └── 9
	   		│       ├── *
	   		│       └── 11
	   		└── 13
	*/
	FormatLinuxTree = "FormatLinuxTree"
	/*
	   FormatHorizontal formats the tree horizontally. This is the most common
	   format used to represent trees in text files.

	      4
	     / \
	    1   8
	       / \
	      6   9
	     /     \
	    5       11
	             \
	              13
	*/
	FormatHorizontal = "FormatHorizontal"
	/*
	   FormatHorizontalSquared formats the tree horizontally but using squared
	   branches. This is useful if you want the output to be wider rather than
	   longer, for example if using nodes with long labels.

	                         5sfhskfuceskjvsdnkvjkdsn
	               ┌────────────────────┬────────────────────┐
	    1dbfalkfbdslkjfbadslkfbl                 8dsbflkjsdbfjzhklsdbfljkds
	               └┐                          ┌─────────────┬─────────────┐
	     3dbfalkfbdslkjfbadslkfbl  7dsbflkjsdbfjzhklsdbfljkds  9dsbflkjsdbfjzhklsdbfljkds
	*/
	FormatHorizontalSquared = "FormatHorizontalSquared"
)

Variables

This section is empty.

Functions

func Equal

func Equal[T cmp.Ordered](t1, t2 Tree[T]) bool

Equal returns whether two trees have identical shape and store the same set of values.

func FormatTree

func FormatTree[T cmp.Ordered](t Tree[T], formatType string) string

FormatTree will return a string representation of the tree, based on the format options provided.

Types

type BST

type BST[T cmp.Ordered] struct {
	// contains filtered or unexported fields
}

func NewBST

func NewBST[T cmp.Ordered]() *BST[T]

NewBST returns an initialized binary search tree.

func (*BST[T]) Count

func (t *BST[T]) Count(value T) int

func (*BST[T]) Delete

func (t *BST[T]) Delete(value T) error

func (*BST[T]) Insert

func (t *BST[T]) Insert(value T) error

func (*BST[T]) Root

func (t *BST[T]) Root() Node[T]

func (*BST[T]) Size

func (t *BST[T]) Size() int

func (*BST[T]) String

func (t *BST[T]) String() string

type BSTNode

type BSTNode[T cmp.Ordered] struct {
	// contains filtered or unexported fields
}

func (*BSTNode[T]) Count

func (n *BSTNode[T]) Count() int

func (*BSTNode[T]) Left

func (n *BSTNode[T]) Left() Node[T]

func (*BSTNode[T]) Parent

func (n *BSTNode[T]) Parent() Node[T]

func (*BSTNode[T]) Right

func (n *BSTNode[T]) Right() Node[T]

func (*BSTNode[T]) Value

func (n *BSTNode[T]) Value() T

type Node

type Node[T cmp.Ordered] interface {
	// Value returns the value stored in the node.
	Value() T
	// Count returns the number of elements equal to the node's `value` are
	// present in the tree. Since the nodes are always bound to only one tree
	// (i.e. nodes are not created without a tree directly or transitively
	// pointing to them), implementations that require unique values will always
	// return 1.
	Count() int
	// Parent returns the parent node. This should return nil for the root node
	// and a non-nil value for all other nodes.
	//
	// This method should be used to check if an individual node is the root of
	// the tree.
	Parent() Node[T]
	// Left returns the left child of the node. This should return nil if there
	// is no left child.
	Left() Node[T]
	// Right returns the right child of the node. This should return nil if there
	// is no right child.
	Right() Node[T]
}

Node represents the possible operations on binary search tree nodes.

Nodes are not meant to be modified directly as all operations are expected to be performed using the Tree object. This is to prevent producing a tree that does not satisfy the binary search tree property. Functions from this interface only allow reading a node's state.

However, implementations may decide to allow mutating nodes. If you wish to modify the node's state directly, you should assert this interface into the node's concrete type.

Calling any method on a nil node should panic.

type RBT

type RBT[T cmp.Ordered] struct {
	// contains filtered or unexported fields
}

func NewRBT

func NewRBT[T cmp.Ordered]() *RBT[T]

NewRBT returns an initialized red black tree.

func (*RBT[T]) Count

func (t *RBT[T]) Count(value T) int

func (*RBT[T]) Delete

func (t *RBT[T]) Delete(value T) error

func (*RBT[T]) Insert

func (t *RBT[T]) Insert(value T) error

func (*RBT[T]) Root

func (t *RBT[T]) Root() Node[T]

func (*RBT[T]) Size

func (t *RBT[T]) Size() int

func (*RBT[T]) String

func (t *RBT[T]) String() string

type RBTNode

type RBTNode[T cmp.Ordered] struct {
	// contains filtered or unexported fields
}

func (*RBTNode[T]) Count

func (n *RBTNode[T]) Count() int

func (*RBTNode[T]) Left

func (n *RBTNode[T]) Left() Node[T]

func (*RBTNode[T]) Parent

func (n *RBTNode[T]) Parent() Node[T]

func (*RBTNode[T]) Right

func (n *RBTNode[T]) Right() Node[T]

func (*RBTNode[T]) Value

func (n *RBTNode[T]) Value() T

type Tree

type Tree[T cmp.Ordered] interface {
	// Retrieve the Root of this tree. Returns nil for a tree that had no nodes
	// inserted to it.
	Root() Node[T]
	// Return the number of nodes in the tree.
	Size() int
	// Count returns the number of elements with value `value` present in the
	// tree. Implementations that require unique values will either return 0
	// or 1.
	//
	// Use this method if you need to determine whether a value belongs to the
	// tree or not.
	Count(value T) int
	// Insert a value to the binary search tree. Implementations that require
	// storing unique values will return an error if that value already exists.
	// Callers may choose to ignore the error if they just want to ensure the
	// value is present in the tree.
	Insert(value T) error
	// Delete a value from the binary search tree. Implementations that allow
	// storing multiple values of the same type should only remove one occurence
	// of the value.
	// Callers may choose to ignore the error if they just want to ensure the
	// value is deleted from a tree supporting only unique values.
	Delete(value T) error
}

Tree represents the possible operations on binary search trees. Various tree types (e.g. regular BST, balanced BST, red black tree etc.) implement this interface.

Calling any method on a nil tree should panic.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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