ianadiwibowo/central-park

View on GitHub
datastructures/binarytree/binarytree.go

Summary

Maintainability
A
0 mins
Test Coverage
package binarytree

import (
    "fmt"
    "strings"

    "github.com/ianadiwibowo/central-park/datastructures/queue"
)

type BinaryTree struct {
    Root *BinaryTreeNode
}

type BinaryTreeNode struct {
    Value int
    Left  *BinaryTreeNode
    Right *BinaryTreeNode
}

// NewBinaryTree creates a new empty binary tree
func NewBinaryTree() *BinaryTree {
    return &BinaryTree{}
}

// SetRoot assign a new value's node as the tree root
func (b *BinaryTree) SetRoot(value int) {
    b.Root = &BinaryTreeNode{
        Value: value,
    }
}

// InsertLeft create a new value's node and put it as left child of parent's node
func (b *BinaryTree) InsertLeft(value int, parent int) {
    parentNode := b.Find(parent)
    if parentNode != nil {
        parentNode.Left = &BinaryTreeNode{
            Value: value,
        }
    }
}

// InsertRight create a new value's node and put it as right child of parent's node
func (b *BinaryTree) InsertRight(value int, parent int) {
    parentNode := b.Find(parent)
    if parentNode != nil {
        parentNode.Right = &BinaryTreeNode{
            Value: value,
        }
    }
}

// Find returns value's node
func (b *BinaryTree) Find(value int) *BinaryTreeNode {
    return findInOrder(b.Root, value)
}

func findInOrder(currentNode *BinaryTreeNode, value int) *BinaryTreeNode {
    if currentNode != nil {
        leftNode := findInOrder(currentNode.Left, value)
        if leftNode != nil {
            return leftNode
        }

        if currentNode.Value == value {
            return currentNode
        }

        rightNode := findInOrder(currentNode.Right, value)
        if rightNode != nil {
            return rightNode
        }
    }

    return nil
}

// Height returns the tree height from the root
func (b *BinaryTree) Height() int {
    return maxHeightPreOrder(b.Root, 0)
}

func maxHeightPreOrder(currentNode *BinaryTreeNode, maxHeight int) int {
    if currentNode != nil {
        leftHeight := maxHeightPreOrder(currentNode.Left, maxHeight+1)
        rightHeight := maxHeightPreOrder(currentNode.Right, maxHeight+1)
        if leftHeight > maxHeight {
            maxHeight = leftHeight
        }
        if rightHeight > maxHeight {
            maxHeight = rightHeight
        }
        return maxHeight
    }

    return 0
}

// FindCompletePaths find all complete paths from root to all leaves
func (b *BinaryTree) FindCompletePaths() [][]int {
    return findCompletePaths(b.Root, []int{}, [][]int{})
}

func findCompletePaths(currentNode *BinaryTreeNode, path []int, prevResults [][]int) [][]int {
    if currentNode != nil {
        updatedPath := make([]int, len(path)+1)
        copy(updatedPath, append(path, currentNode.Value))

        if currentNode.IsLeaf() {
            updatedPrevResults := make([][]int, len(prevResults)+1)
            copy(updatedPrevResults, append(prevResults, updatedPath))

            return updatedPrevResults
        }
        prevResults = findCompletePaths(currentNode.Left, updatedPath, prevResults)
        prevResults = findCompletePaths(currentNode.Right, updatedPath, prevResults)
    }

    return prevResults
}

// TraversePreOrder returns the pre-ordered (depth-first) binary tree values
func (b *BinaryTree) TraversePreOrder() (result []int) {
    var traverse func(currentNode *BinaryTreeNode)
    traverse = func(currentNode *BinaryTreeNode) {
        if currentNode == nil {
            return
        }

        result = append(result, currentNode.Value)
        traverse(currentNode.Left)
        traverse(currentNode.Right)
    }

    traverse(b.Root)

    return result
}

// TraverseInOrder returns the in-ordered (depth-first) binary tree values
func (b *BinaryTree) TraverseInOrder() (result []int) {
    var traverse func(currentNode *BinaryTreeNode)
    traverse = func(currentNode *BinaryTreeNode) {
        if currentNode == nil {
            return
        }

        traverse(currentNode.Left)
        result = append(result, currentNode.Value)
        traverse(currentNode.Right)
    }

    traverse(b.Root)

    return result
}

// TraversePostOrder returns the post-ordered (depth-first) binary tree values
func (b *BinaryTree) TraversePostOrder() (result []int) {
    var traverse func(currentNode *BinaryTreeNode)
    traverse = func(currentNode *BinaryTreeNode) {
        if currentNode == nil {
            return
        }

        traverse(currentNode.Left)
        traverse(currentNode.Right)
        result = append(result, currentNode.Value)
    }

    traverse(b.Root)

    return result
}

// TraverseLevelOrder returns the breadth-first-ordered binary tree values
func (b *BinaryTree) TraverseLevelOrder() (result []int) {
    queue := queue.NewQueue()
    queue.Enqueue(b.Root)

    for !queue.IsEmpty() {
        currentNode := queue.Dequeue().(*BinaryTreeNode)
        result = append(result, currentNode.Value)

        if currentNode.Left != nil {
            queue.Enqueue(currentNode.Left)
        }

        if currentNode.Right != nil {
            queue.Enqueue(currentNode.Right)
        }
    }

    return result
}

// IsLeaf checks whether a binary tree node is leaf (true) or not (false)
func (btn *BinaryTreeNode) IsLeaf() bool {
    return btn.Left == nil && btn.Right == nil
}

// PrintInverseLevelOrder returns the level-ordered (breadth first) human-readable format of the binary tree, but inverted
func (b *BinaryTree) PrintInverseLevelOrder() (printout string) {
    queue := queue.NewQueue()
    queue.Enqueue(b.Root)

    for !queue.IsEmpty() {
        currentNode := queue.Dequeue().(*BinaryTreeNode)
        printout = fmt.Sprintf("%v %v", printout, currentNode.Value)

        if currentNode.Right != nil {
            queue.Enqueue(currentNode.Right)
        }

        if currentNode.Left != nil {
            queue.Enqueue(currentNode.Left)
        }
    }

    return fmt.Sprintf("[%v]", strings.TrimSpace(printout))
}

// FindParent searches for a node whose left or right child have a certain value
func (b *BinaryTree) FindParent(value int) *BinaryTreeNode {
    return b.findParent(b.Root, value)
}

func (b *BinaryTree) findParent(currentNode *BinaryTreeNode, value int) *BinaryTreeNode {
    queue := queue.NewQueue()
    queue.Enqueue(b.Root)

    for !queue.IsEmpty() {
        currentNode := queue.Dequeue().(*BinaryTreeNode)

        if currentNode.Left != nil {
            if currentNode.Left.Value == value {
                return currentNode
            }
            queue.Enqueue(currentNode.Left)
        }
        if currentNode.Right != nil {
            if currentNode.Right.Value == value {
                return currentNode
            }
            queue.Enqueue(currentNode.Right)
        }
    }

    return nil
}