Skip to content

Commit

Permalink
Solve the "Test if a binary tree is balanced" problem
Browse files Browse the repository at this point in the history
commit 719971269104da2c8743540471c53821dc36e005
Author: Peter Mrekaj <mrekucci@gmail.com>
Date:   Tue Oct 20 21:49:12 2015 -0700

    Solve the "Test if a binary tree is balanced" problem

commit 3b950cb514552eddedf88402d48ce2e332adf788
Author: Peter Mrekaj <mrekucci@gmail.com>
Date:   Mon Oct 19 22:17:27 2015 -0700

    Simplify test for Walk method

commit 3aade4a7593a5cea042d7b549434c57335b1444f
Author: Peter Mrekaj <mrekucci@gmail.com>
Date:   Mon Oct 19 22:12:49 2015 -0700

    Implement BTree with walking support

commit 054653c91a31b659d6523c6725f89ab61b73079b
Author: Peter Mrekaj <mrekucci@gmail.com>
Date:   Sat Oct 17 18:15:12 2015 -0700

    Improve stack tests for more coverage and readability

commit 494a4d9186f34638504528373e899b307708ab7e
Author: Peter Mrekaj <mrekucci@gmail.com>
Date:   Sat Oct 17 17:10:42 2015 -0700

    Solve the "Implement a queue using stacks" problem
  • Loading branch information
mrekucci committed Oct 21, 2015
1 parent a8bfe9f commit 5c8a224
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 3 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Binary Trees

| Problem | Test | Implemented |
|--------------------------------------------------------------------------|:------------:|:-----------:|
| [Test if a binary tree is balanced][144] | [tests][145] | |
| [Test if a binary tree is balanced][144] | [tests][145] | |
| [Test if a binary tree is symmetric][146] | [tests][147] | |
| [Compute the lowest common ancestor in a binary tree][148] | [tests][149] | |
| [Compute the LCA when nodes have parent pointers][150] | [tests][151] | |
Expand Down Expand Up @@ -540,8 +540,8 @@ Honors Class
[141]: queues/stackqueue_test.go
[142]: in_progress.md
[143]: in_progress.md
[144]: in_progress.md
[145]: in_progress.md
[144]: btrees/balanced.go
[145]: btrees/balanced_test.go
[146]: in_progress.md
[147]: in_progress.md
[148]: in_progress.md
Expand Down
41 changes: 41 additions & 0 deletions btrees/balanced.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package btrees

// state represents the state of the binary tree.
type state struct {
isBalanced bool
height int
}

// checkState returns the status of the binary tree t.
func checkState(t *BTree) state {
if t == nil {
return state{true, -1} // Base case.
}

// Postorder walk.
lt := checkState(t.left)
if !lt.isBalanced {
return lt
}
rt := checkState(t.right)
if !rt.isBalanced {
return rt
}

d := lt.height - rt.height
max := lt.height
if lt.height < rt.height {
max = rt.height
}
return state{d <= 1 && d >= -1, max + 1}

}

// IsBalanced returns true if t is a balanced binary tree.
// The time complexity is O(n). The O(h) additional space
// is needed (where h is the height of the tree).
func IsBalanced(t *BTree) bool { return checkState(t).isBalanced }
84 changes: 84 additions & 0 deletions btrees/balanced_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package btrees

import "testing"

func TestIsBalance(t *testing.T) {
for _, test := range []struct {
tree *BTree
want bool
}{
// Balanced Binary Trees.
{&BTree{"TREE_0", nil, nil}, true},
{&BTree{"TREE_1", &BTree{"A", nil, nil}, nil}, true},
{&BTree{"TREE_2",
&BTree{"A",
&BTree{"B", nil, nil},
&BTree{"C", nil, nil}},
&BTree{"D", nil, nil}}, true},

// Not balanced Binary Trees.
{&BTree{"TREE_3", &BTree{"A", &BTree{"B", nil, nil}, nil}, nil}, false},
{&BTree{"TREE_4",
&BTree{"A",
&BTree{"B",
&BTree{"C", nil, nil},
&BTree{"D", nil, nil}},
&BTree{"E", nil, nil}},
&BTree{"F", nil, nil}}, false},
{&BTree{"TREE_5",
&BTree{"A",
&BTree{"B",
&BTree{"C",
&BTree{"D", nil, nil},
&BTree{"E", nil, nil}},
&BTree{"F", nil, nil}},
&BTree{"G", nil, nil}},
&BTree{"H", nil, nil}}, false},
{&BTree{"TREE_6",
&BTree{"A", nil, nil},
&BTree{"B",
&BTree{"C", nil, nil},
&BTree{"D",
&BTree{"E", nil, nil},
&BTree{"F", nil, nil}}}}, false},
{&BTree{"TREE_7",
&BTree{"A", nil, nil},
&BTree{"B",
&BTree{"C", nil, nil},
&BTree{"D",
&BTree{"E", nil, nil},
&BTree{"F",
&BTree{"G", nil, nil},
&BTree{"H", nil, nil}}}}}, false},
} {
if got := IsBalanced(test.tree); got != test.want {
t.Errorf("IsBalanced(%v) = %t; want %t", test.tree, got, test.want)
}
}
}

func BenchmarkIsBalanced(b *testing.B) {
tree := &BTree{"A",
&BTree{"B",
&BTree{"C",
&BTree{"D",
&BTree{"E", nil, nil},
&BTree{"F", nil, nil}},
&BTree{"G", nil, nil}},
&BTree{"H",
&BTree{"I", nil, nil},
&BTree{"J", nil, nil}}},
&BTree{"K",
&BTree{"L",
&BTree{"M", nil, nil},
&BTree{"N", nil, nil}},
&BTree{"O", nil, nil}}}
b.ResetTimer()
for i := 0; i < b.N; i++ {
IsBalanced(tree)
}
}
70 changes: 70 additions & 0 deletions btrees/btree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package btrees

// BTree represents a binary tree.
type BTree struct {
Data interface{}
left *BTree
right *BTree
}

// Height returns the height of the binary tree t.
// The time complexity is O(n). The O(h) additional
// space is needed (where h is the height of the tree).
func Height(t *BTree) int {
hl, hr := -1, -1
if t != nil {
hl = 1 + Height(t.right)
hr = 1 + Height(t.left)
}
if hl > hr {
return hl
}
return hr
}

// Walk returns elements of the binary tree t in given traversal order.
func Walk(t *BTree, order func(t *BTree, w *[]interface{})) []interface{} {
var w []interface{}
order(t, &w)
return w
}

// Preorder visit the root, traverse the left
// subtree, then traverse the right subtree.
// The time complexity is O(n). The O(h) additional
// space is needed (where h is the height of the tree).
func Preorder(t *BTree, w *[]interface{}) {
if t != nil {
*w = append(*w, t.Data)
Preorder(t.left, w)
Preorder(t.right, w)
}
}

// Inorder traverse the left subtree, visit the
// root, then traverse the right subtree.
// The time complexity is O(n). The O(h) additional
// space is needed (where h is the height of the tree).
func Inorder(t *BTree, w *[]interface{}) {
if t != nil {
Inorder(t.left, w)
*w = append(*w, t.Data)
Inorder(t.right, w)
}
}

// Postorder traverse the left subtree, traverse the
// right subtree, and then visit the root.
// The time complexity is O(n). The O(h) additional
// space is needed (where h is the height of the tree).
func Postorder(t *BTree, w *[]interface{}) {
if t != nil {
Postorder(t.left, w)
Postorder(t.right, w)
*w = append(*w, t.Data)
}
}
66 changes: 66 additions & 0 deletions btrees/btree_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package btrees

import (
"reflect"
"testing"
)

func TestHeight(t *testing.T) {
for _, test := range []struct {
tree *BTree
want int
}{
{&BTree{"TREE_0", nil, nil}, 0},
{&BTree{"TREE_1", &BTree{"A", nil, nil}, nil}, 1},
{&BTree{"TREE_2", nil, &BTree{"A", nil, nil}}, 1},
{&BTree{"TREE_3", &BTree{"A", nil, nil}, &BTree{"B", nil, nil}}, 1},
{&BTree{"TREE_4", &BTree{"A", &BTree{"B", nil, nil}, nil}, nil}, 2},
} {
if got := Height(test.tree); got != test.want {
t.Errorf("Height(%v) = %d; want %d", test.tree, got, test.want)
}
}
}

func TestWalk(t *testing.T) {
// A Binary Tree of height 5.
tree := &BTree{"A",
&BTree{"B",
&BTree{"C",
&BTree{"D", nil, nil},
&BTree{"E", nil, nil}},
&BTree{"F",
nil,
&BTree{"G",
&BTree{"H", nil, nil},
nil}}},
&BTree{"I",
&BTree{"J",
nil,
&BTree{"K",
&BTree{"L",
nil,
&BTree{"M", nil, nil}},
&BTree{"N", nil, nil}}},
&BTree{"O",
nil,
&BTree{"P", nil, nil}}}}

for _, test := range []struct {
fnName string
fn func(t *BTree, w *[]interface{})
want []interface{}
}{
{"Preorder", Preorder, []interface{}{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"}},
{"Inorder", Inorder, []interface{}{"D", "C", "E", "B", "F", "H", "G", "A", "J", "L", "M", "K", "N", "I", "O", "P"}},
{"Postorder", Postorder, []interface{}{"D", "E", "C", "H", "G", "F", "B", "M", "L", "N", "K", "J", "P", "O", "I", "A"}},
} {
if got := Walk(tree, test.fn); !reflect.DeepEqual(got, test.want) {
t.Errorf("tree.Walk %q got %v; want %v", test.fnName, got, test.want)
}
}
}

0 comments on commit 5c8a224

Please sign in to comment.