Binary Trees

advertisement
Binary Trees
CS1316: Representing
Structure and Behavior
Story


Binary Trees
Structuring Binary Trees to make them fast for
searching
•
•


Binary search trees
How we insert() in order, how we traverse in order,
how we search in order
More than one way to traverse: Pre-order
Treating a tree like a list
Here’s the question


Searching a list and an array is O(n)
We can arrange an array so that
searching it is O(log n)
• Binary search of an ordered array.


Lists are harder to arrange to create a
faster search.
How about trees?
A Binary Tree

A binary tree
consists of nodes
each of which can
have at most two
children
• A left
• A right
Parent Child
Left Child
Right Child
Every node in a
binary tree is
another tree
Parent Child
Left Child
Right Child
Parent
Child
Parent
Child
Left Child
Left Child
Right Child
Right Child
Computer scientists know a lot
about binary trees

For example, how many levels will you
have for n nodes in a binary tree?
• Maximum: n
• Minimum: 1+ log n
Defining a binary tree
public class TreeNode {
private String data;
private TreeNode left;
private TreeNode right;
public TreeNode(String something){
data = something;
left = null;
right = null;
}
Our nodes will
contain Strings as
their data. Could
be anything.
Accessors
// Accessors
public String getData() {return data;}
public void setData(String something){data = something;}
public TreeNode getLeft() {return left;}
public TreeNode getRight() {return right;}
public void setLeft(TreeNode newleft){left = newleft;}
public void setRight(TreeNode newright){right = newright;}
Defining printing on a node
(for a tree, recursively)
public String toString()
{return
"This:"+this.getData()+
" Left: "+this.getLeft() +
" Right: "+this.getRight();}
Testing the printing
> TreeNode node1 = new TreeNode("george");
> node1
This:george Left: null Right: null
> TreeNode node1b = new TreeNode("alvin")
> node1.setLeft(node1b)
> node1
This:george Left: This:alvin Left: null Right: null
Right: null
Creating a binary search tree

Simple rule:
bear
• Values on the left
•
branch are less
than values in the
parent.
Values on the right
branch are greater
than values in the
parent.
apple
cat
Inserting in order in a binary
tree

Is the value to insert less than the current
node’s value?
•
•

Does the left branch have a node already?
If not, put it there.
If so, insert it on the left.
The value to insert must be greater than or
equal to the current node’s value.
•
•
Does the right branch have a node already?
If not, put it there.
If so, insert it on the right.
How we compare strings
> "abc".compareTo("abc")
0
> "abc".compareTo("aaa")
1
> "abc".compareTo("bbb")
-1
> "bear".compareTo("bear")
0
> "bear".compareTo("beat")
-2
Code
// Insert in order
public void insert(TreeNode newOne){
if (this.data.compareTo(newOne.data) > 0){
if (this.getLeft() == null)
{this.setLeft(newOne);}
else
{this.getLeft().insert(newOne);}}
else {
if (this.getRight() == null)
{this.setRight(newOne);}
else
{this.getRight().insert(newOne);}
}
}
Testing
> TreeNode node1 = new TreeNode("george");
> TreeNode node2 = new TreeNode("betty");
> TreeNode node3 = new TreeNode("joseph");
> TreeNode node4 = new TreeNode("zach");
> node1
This:george Left: null Right: null
> node1.insert(node2)
> node1
This:george Left: This:betty Left: null Right: null
Right: null
Whole tree
> node1.insert(node3)
> node1
This:george Left: This:betty Left:
null Right: null Right:
This:joseph Left: null Right:
null
> node1.insert(node4)
> node1
This:george Left: This:betty Left:
null Right: null Right:
This:joseph Left: null Right:
This:zach Left: null Right: null
george
betty
joseph
zach
How do we find things here?

Given something to find:
• Is it me? If so, return me.
• Is it less than me?
• Is the left null? If so, give up.
• If not, search the left.
• Otherwise
• Is the right null? If so, give up.
• If not, search the right.
Code
public TreeNode find(String someValue){
if (this.getData().compareTo(someValue) == 0)
{return this;}
if (this.data.compareTo(someValue) > 0){
if (this.getLeft() == null)
{return null;}
else
{return this.getLeft().find(someValue);}}
else {
if (this.getRight() == null)
{return null;}
else
{return this.getRight().find(someValue);}}
}
Testing
> node1.find("betty")
This:betty Left: null Right: null
> node1.find("mark")
null
Algorithm order: O(log n)


For a balanced tree!
A tree can be
unbalanced and still be
a binary search tree.
Do you see
why?
george
betty
joseph
betty
zach
george
joseph
zach
How do we print a tree in order?

Is there a left node?

Print me
Is there a right node?

• Print the left
• Print the right
Code
//In-Order Traversal
public String traverse(){
String returnValue = "";
// Visit left
if (this.getLeft() != null)
{returnValue += "
"+this.getLeft().traverse();}
// Visit me
returnValue += " "+this.getData();
// Visit right
if (this.getRight() != null)
{returnValue += "
"+this.getRight().traverse();}
return returnValue;}
> node1.traverse()
" betty george joseph zach"
There’s more than one way to
traverse…but why?
+
*
3
*
4
x
y
What’s the in-order traversal of
this tree?
+
*
3
*
4
x
It’s the equation, in the order in which you’d compute it:
(3 * 4) + (x * y)
y
Another traversal: Post-order

Is there a left node?

Is there a right node?

Print me
• Print the left
• Print the right
What’s the post-order traversal
of this tree?
+
*
3
*
4
x
y
It’s the equation, in the order in which you’d compute it on an
HP calculator:
34*xy*+
So what’s the big deal?

Binary trees are cute.
• Easy to do useful things with them.
• Searching quickly.
• Using them to evaluate equations.
• Operations are easily written small and
•

recursively.
We know interesting facts about them.
Is that all?
• Turns out that binary trees can do ANYTHING
Binary trees can represent
anything!


We can map an n-ary tree (like a scene
graph) to a binary tree.
We can use a binary tree to represent a
list.
• How about the ability to add to the first and to
the last, like our lists?
addFirst() and addLast()
public void addFirst(TreeNode newOne){
if (this.getLeft() == null)
{this.setLeft(newOne);}
else
{this.getLeft().addFirst(newOne);}
}
public void addLast(TreeNode newOne){
if (this.getRight() == null)
{this.setRight(newOne);}
else
{this.getRight().addLast(newOne);}
}
Playing it out
> TreeNode node1 = new TreeNode("the")
> node1.addFirst(new TreeNode("George of"))
> node1.addLast(new TreeNode("jungle"))
> node1.traverse()
" George of the jungle"
Summary


Binary trees seem simplified, but can actually
do anything that an n-ary or even a linked list
can do.
Binary trees have useful applications (fast
searching, equation representations).
•
•

A binary search tree places lesser items down the left
branch and greater items down the right.
As long as the tree remains balanced, O(log n)
searching.
Binary tree code tends to be small and
recursive.
Download