0% found this document useful (0 votes)
45 views

Data Structures Binary Trees: Phil Tayco Slide Version 1.1 Apr. 2, 2018

The document discusses binary trees, which provide dynamic memory allocation like linked lists while also allowing for efficient binary search operations. Binary trees store data in nodes that can have up to two child nodes, with all left child nodes containing data less than the parent and right child nodes containing greater data. This structure allows binary search to be simulated by recursively searching the left or right subtrees. Code examples demonstrate how to insert nodes and search the tree in O(log n) time by traversing child pointers until finding the appropriate position or target value.

Uploaded by

Alberto Lopez
Copyright
© © All Rights Reserved
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
45 views

Data Structures Binary Trees: Phil Tayco Slide Version 1.1 Apr. 2, 2018

The document discusses binary trees, which provide dynamic memory allocation like linked lists while also allowing for efficient binary search operations. Binary trees store data in nodes that can have up to two child nodes, with all left child nodes containing data less than the parent and right child nodes containing greater data. This structure allows binary search to be simulated by recursively searching the left or right subtrees. Code examples demonstrate how to insert nodes and search the tree in O(log n) time by traversing child pointers until finding the appropriate position or target value.

Uploaded by

Alberto Lopez
Copyright
© © All Rights Reserved
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 90

Data Structures

Binary Trees
Phil Tayco
Slide version 1.1
Apr. 2, 2018
Binary Trees
Back to Linked Lists

• The main benefit with a linked list is its dynamic


memory allocation – we use nodes only when we
need them
• Array memory allocation is static, but sorting them
allows us to use binary search and go from O(n) to
O(log n)
• Sorting linked lists can be done, but would not give
us the benefit of doing so since binary search
cannot be applied
• The goal is to now try to get the best of both worlds
(dynamic memory allocation with the ability to
perform binary search)
Binary Trees
Binary search and dynamic nodes

• Binary search works by looking at the “middle” of


the list and dividing the list in half with each
search iteration
• Linked lists can only provide access at the head
(and tail) – direct access to the middle cannot be
done easily
• If we want to simulate accessing the middle, each
node would have be treated as a middle element
• Middle elements mean they have something to its
left and right, which can also relate to on overall
order to the structure
Binary Trees
Node definition

• Given this, we start by designing the node to hold 3


properties. The data itself and 2 pointers to other Nodes

public class Node {


public int data;
public Node left;
public Node right;
}

To maintain an order, the left and right Node pointers must


point to data that is “less than” and “greater than” the
Node respectively
Binary Trees
Insert algorithm

• As new nodes are added to this structure, the


appropriate location must be determined while
maintaining the design intent:
• If the structure is empty, add the new node as the
first element. We will call this the “root” node
• If root is not empty, traverse the structure by
comparing the new node data value with the current
node (current starts at root)
– If the value is less than current, go to the left Node
– Otherwise, go to the right Node
• Keep traversing this way until you reach an empty
pointer – at this point add the new Node there
Binary Trees
Example: Insert 10 – the root starts as empty so
the new node becomes the root
root

10
Binary Trees
Next, insert 20. 20 is greater than 10 and its right
pointer is null, so we add it there
root

10

20
Binary Trees
Next, insert 5. 5 is less than 10 (we always start at
root) and its left pointer is null, so we add it there
root

10

5 20
Binary Trees
Now insert 15. 15 is greater than 10 so we go right.
20 is there so we check again and find 15 less
than it. 20’s left pointer is null so we add 15
there
root

10

5 20

15
Binary Trees
One more. Insert 25. Starting at root, 25 is greater
than 10 and then greater than 20 so we add it to
the right of 20

root

10

5 20

15 25
Binary Trees
public class BinaryTree
{
private Node root;

public BinaryTree()
{
root = null;
}
Binary Trees
public void insert(int n)
{
Node current = root;
Node newNode = new Node();

newNode.data = n;
newNode.left = null;
newNode.right = null;

if (root == null)
root = newNode;
Binary Trees
else
while(true)
if (newNode.data > current.data)
if (current.right == null)
{
current.right = newNode;
break;
}
else
current = current.right;
else
if (current.left == null)
{
current.left = newNode;
break;
}
else
current = current.left;
}
Binary Trees
Code analysis

• The code follows the algorithm earlier stated


– First, create a new node with no children (the new node will be
a leaf)
– If the root is null, simply set the root to the new node
– Otherwise, perform the following loop until a null child pointer
is found
• If the new value is greater than the current node’s value, it
belongs on the “right” of the current node. If “right” is null, set it
to the new node and exit the loop. Otherwise, traverse down the
“right” pointer
• Otherwise, the new node belongs on the “left” of the current node.
If “left” is null, set it to the new node and exit the loop. Otherwise,
traverse down the “left” pointer
• The loop will eventually reach a null pointer so there is
no danger of an infinite loop
Binary Trees
Efficiency

• Each node “visited” effectively cuts off the other half of the list
• If the values being added have a random distribution of values,
the performance is like a binary search and is thus, O(log n)
• Note that there is a dependency on the manner in which Nodes
are inserted
– If the root is too small or too large, subsequent levels will be on one
side of it
– If this pattern continues (such as inserting numbers in numeric order),
the tree degrades into a linked list
– Efficiency in such “unbalanced” trees degrades to O(n) for all functions
• There are ways to counter unbalancing in more advanced tree
structures which we’ll look at later
• As you can imagine, the other 3 major functions will follow a
similar algorithm and efficiency. Let’s look at “search” next
Binary Trees
Binary search enabled

• As more elements get added and continue to


follow these rules, the structure starts to take the
shape of a tree
• We call this a binary tree because the number of
elements from each node is 2
• The binary tree structure and rules enable binary
search to be simulated
– If the search value is not equal to the root, traverse the
left or right pointer based on the current node and
search values (go left if search value is less, otherwise
go right)
– If you reach null, the search value is not present
Binary Trees
public Node search(int n)
{
Node current = root;

while (current != null)


if (current.data == n)
return current;
else if (current.data > n)
current = current.left;
else
current = current.right;
return null;
}
Binary Trees
Code analysis

• We start with setting a temporary node to root (so


we don’t accidentally change root during the search)
• As long as the current node is not null, perform the
following checks
– If the current node value equals the search value, we found
the node and we return it
– Otherwise, if the new value is greater than the current
node’s value, the potential node we are looking for is on the
“right” of the current node so we traverse down the right
– Otherwise, the new node belongs on the “left” of the current
node and we traverse down the “left” pointer
• If we reach this point, the current node ended up as
null, meaning the search value doesn’t exist
Binary Trees
Efficiency

• Once again, each node “visited” effectively


cuts off the other half of the list
• As long as the tree is fairly balanced, the
performance will be O(log n)
• If node values are maintained such that
the tree is unbalanced, the performance
degrades towards O(n)
Binary Trees
Terminology

• Because this data structure takes the form


of a tree graphically, tree terms are often
used
• Familiarity with these terms is important
for not only binary trees, but also for use
with more advanced tree structures
Binary Trees
“Root” is the first node of the tree

root

10

5 20

15 25
Binary Trees
“Parent” nodes have either left and/or right pointers
of it pointing to existing nodes. 10 is the parent
of 5 and 20. 20 is the parent of 15 and 25

root

10

5 20

15 25
Binary Trees
“Child” nodes are nodes with a parent. 5 is a child
of 10 and so is 20. 15 and 25 are children of 20.
These nodes are also “siblings” to each other
because they share the same parent
root

10

5 20

15 25
Binary Trees
“Leaf” nodes are nodes with no
children. 5, 15 and 25 are such
leaves
root

10

5 20

15 25
Binary Trees
Each “generation” of nodes is called a “level”. 10 is
at level 0, 5 and 20 are at level 1 and 15 and 25
at level 2. The number of levels a tree has is
called its “height”
root

10

5 20

15 25
Binary Trees
Traversing a tree is similar to traversing a linked list
in that you follow the node pointers to get where
you want. In a tree, such traversals are called a
“path”
root

10

5 20

15 25

This example shows a path to node 15


Binary Trees
Subsets of a tree that form their own tree are called “subtrees”.
All nodes in a subtree are connected

root

10

5 20

Subtree 20 with children 15 15


and 25 are
25 highlighted. Note that
20 and 5 together is not considered a subtree (they are not
directly connected)
Binary Trees
Update and Delete

• The remaining 2 functions is where the complexity of tree


structures begin to show
• Update is usually what we would tackle next, but let’s think about
what happens here:
– An update is a search and change in value. Search is no problem
– However, when the search results in an existing node to change, the
new node value will very likely put it out of order in the tree
– The node would then have to move to the correct place in the tree
• Such an update would be a challenge to do to find the new node’s
appropriate location relative to where the node was changed from
• It makes more sense instead to perform an update as a delete of
the old value for the update followed by an insert of the new value
if the node was found
• Thus, we’ll look at the delete function first…
Binary Trees
Delete

• Okay, no problem right? Simply perform a search and find


the node. If we find it, remove it
• However, with linked lists, we saw this was not everything
because we also needed to maintain visibility to the
“previous” node of the “current” node to appropriately
maintain the pointers after the current node is removed
• Removing a node in the linked list had the previous “next”
pointer point to the current node’s “next” pointer
• The same idea is used here treating a node’s “parent” as its
“previous”
• However, in a tree, the “next” pointer of node could be
either the left or right child. Thus, the parent’s child pointer
must point to the correct current node’s child node
Binary Trees
Situations

• How do we algorithmically maintain the structure? Start


with understanding that when a node is found to be
removed, there will be 3 possible situations:
– The node is a leaf (no children)
– The node has 1 child on its left or right
– The node has 2 children
• As you can probably see, the complexity increases as the
node has 0, 1 or 2 children
• Note that we are also only looking at the node’s direct
descendants. We don’t care about the entire subtrees of
the node, nor should we so we can keep it “simple”
Binary Trees
These situations are best seen with examples.
Looking at situation 1, that would be trying to
delete 5, 15 or 25 below. Let’s delete 25

root

10

5 20

15 25
Binary Trees
Because 25 has no children, its parent node’s
“right” pointer can simply point to null

root

10

5 20

15
Binary Trees
Easy enough. Next situation is removing a node
with 1 child. That would be 10 and 20 in the tree
below. Let’s delete 20

root

10

5 20

15
Binary Trees
Now we have to make sure 20’s parent points to
the correct child of 20. More specifically, since 20
is on the “right” of 10, 10’s “right” pointer must
point to the correct child of 20
root

10

5 20

15
Binary Trees
It turns out this is not terribly difficult because 20 (in this
situation) only has one child to choose from. Since that
child is on 20’s “left”, we make 10’s “right” point to 20’s
“left” which is 15

root

10

5 15
Note that the order of the entire tree is maintained even
though 15 was on the “left” of 20 (this was because 15
was first added by going to the “right” of 10 during insert)
Binary Trees
What if the one child of 20 was a large subtree?
Because of the way the pointers are set up and
how insert works, the overall tree order still
remains intact. For example:
root

10

5 20

15

12

11 14
Binary Trees
If we remove 20, 20 still only has 1 direct child, so
when we assign 20’s parent’s right child to 20’s
left child, that entire subtree becomes 10’s “right”
child and the order is still intact
root

10

5 15

12

11 14
Binary Trees
Situations 1 and 2 addressed

• No children of a node to remove is simple:


remove it and set its parent’s child pointer to null
• 1 child is not too bad: remove the node and have
the parent’s child pointer point to the one child of
the node being removed
• The idea is the same with 2 children, but now we
have to choose which child the parent will take on
• Let’s take a look at the same tree on the previous
slide and note the two nodes that have two
children. Can you spot them?
Binary Trees
10 and 12 are both nodes that have 2 direct
children. Notice that there is a difference, though,
if we delete 12 versus 10. The situations differ as
far as picking the “correct” child node goes
root

10

5 20

15

12

11 14
Binary Trees
If we remove 12, note that either 11 and 14 can
take its place and the structure order will remain
intact

root

10

5 20

15

11 14
Binary Trees
15 can take 11 as its left child and 14 would then
become the right child of 11

root

10

5 20

15

11

14
Binary Trees
Similarly, 14 could also be the left child of 15 and
11 would then have to become 14’s left child

root

10

5 20

15

14

11
Binary Trees
Situation 3

• The selection of which child to replace 12 when it is


removed is arbitrary. Either 11 or 14 will work
• Both 11 and 14 are leaves and since they are part of the
left subtree of 15, picking either one keeps the tree order
intact
• The child links still need to be arranged with the replacing
node inheriting the child node of the one removed:
– When 11 replaced 12, it took 12’s right child as its own right
child
– When 14 replaced 12, it took 12’s left child on its left
• Most delete situations with nodes having 2 children,
though, will not have children that are leaves
Binary Trees
Here’s another example with a slightly larger tree.
Let’s look at removing 10. Note we are still in
situation 3: node 10 has 2 children
root
30

10
50

5 20 75

15

12

11 14
Binary Trees
If we replaced it with node 5, the structure is intact
implying that if one of the child nodes is a leaf, it
can replace the node being removed
root
30

5
50

20 75

15

12

11 14
Binary Trees
We could not do the same with 20. Notice in this
example that 20 already has a left child and 10
had one as 5. If 20 takes its place, where does 5
go?
root
30

50

5 20 75

15

12

11 14
Binary Trees
Situation 3

• Deleting a node with 2 children is easier when one of the


nodes is a leaf
• The problem with this is that most of the time with larger
trees, the child nodes will not be leaves making an initial
check to see if they are leaf nodes effectively unnecessary
• We need to find an algorithm that identifies the correct
replacing node in an arbitrary subtree (versus a subtree
with specific situations)
• Take a look at the subtree with 10 removed. Which node
can replace 10 with minimal work required to rearrange
node pointers?
Binary Trees
A leaf node is a good candidate because it has no
child nodes to deal with. If we go with a leaf node
in the subtree, it would have to be either 11 or
14.
root
30

50

5 20 75

15

12

11 14
Binary Trees
14 would not work though because subtree 12
should not be on the “right” of 14

root
30

14
50

5 20 75

15

12

11
Binary Trees
However, 11 works and works very well!

root
30

11
50

5 20 75

15

12

14
Binary Trees
Situation 3 – almost there!

• Replacing 10 with 11 looks like it worked because it was a leaf


node
• This appears to be the case because the pointer management
after replacing 10 was minimal
• So far out algorithm for situation 3 is:
– Go down the right subtree (it will turn out that whether it is left or
right doesn’t matter as long as we’re consistent)
– Descend the subtree until you reach the correct leaf node and use it
to replace the node being removed updating the parent and child
pointers appropriately
• “Correct” leaf node, though, is challenging to define. In the
example, the choice was 11 or 14. We did not choose 14 because
the order would have been broken.
• What made 11 better than 14? The answer lies in the node value
that was being removed, which was 10. The fact that 11 is closer
to 10 than 14 in number has a lot to do with it
• Now look what happens when we try to delete 11…
Binary Trees
11 is gone. According to our algorithm, 14 is the
only leaf node in the right subtree…

root
30

50

5 20 75

15

12

14
Binary Trees
Replacing 11 with 14 is a problem because 12 is on
the “right” of 14 (it’s the same issue as before
when selecting 14 to replace 10)
root
30

14
50

5 20 75

15

12
Binary Trees
This rules out “always” selecting a leaf node. What
do we do now? First, identify which node in the
subtree should replace 11…
root
30

50

5 20 75

15

12

14
Binary Trees
11 was good to replace 10 because it was the
closest value on the right of it. If we did the same
thing here to replace 11, 12 would be the winner
root
30

12
50

5 20 75

15

14
Binary Trees
But 12 was not a leaf, so what do we do with its
children? It turns out that 12 will only have 1
child and it will be on the right (if it had one on
the left, that child would be better to use as a
root
replacement node!)
30

12
50

5 20 75

15

14
Binary Trees
Note also that 12’s parent will always be its left
child. Thus, the parent left child takes the right
child (and thus, subtree) of the replacing node.
Order is intact!
root
30

12
50

5 20 75

15

14
Binary Trees
The Situation 3 algorithm

• Go down the right subtree


• If the “right” child is a leaf, simply replace the deleted
node with it
• Otherwise, go as far left as possible until you reach a node
with no left child – call this the “successor” node
• Before replacing the deleted node with the successor, set
the “right” child of the successor to its parent’s “left” child
• Replace the deleted node with the successor and ensure
the deleted node’s parent link is correct and the “right”
child of the deleted node is now the “right” child of the
successor
– Exception: If the deleted node is root, replace the node with
the successor as root
Binary Trees
Put it all together

• It may seem like a lot of checks, but the code follows the
logic effectively
• First check if the tree is empty (as always) – we’re done if
it is
• Search the tree (using the same search algorithm) for the
node to remove keeping track of not only the parent and
current nodes, but whether the current node is on the left
or right of the parent
• If current ends up as null, the node to remove is not found
and we’re done
• At this point, the node is found and we handle the 3
situations as previously discussed
• Let’s look at the code to see this all in action
Binary Trees
public boolean remove(int n)
{
// Check empty tree
if (root == null)
return false;

// Prepare search for node


Node current = root;
Node parent = root;
boolean currentIsLeft = true;
Binary Trees
while (current.data != n)
{
// currentIsLeft is true when current is finds n
// and is a “left” child of parent
parent = current;
if (current.data > n)
{
currentIsLeft = true;
current = current.left;
}
else
{
currentIsLeft = false;
current = current.right;
}

// If current is null, node n was not found


if (current == null)
return false;
}
Binary Trees
// At this point, current is the node to delete
// Now, we check for the situations

// Situation 1 - leaf node


if (current.left == null && current.right == null)

// Check if current node is root


if (parent == current)
root = null;

// Check which child pointer of parent to set


else if (currentIsLeft)
parent.left = null;
else
parent.right = null;
Binary Trees
// Situation 2 - one child. Parent inherits child
// or if current is root, root takes child
else if (current.left == null)
if (parent == current)
root = current.right;
else if (currentIsLeft)
parent.left = current.right;
else
parent.right = current.right;
else if (current.right == null)
if (parent == current)
root = current.left;
else if (currentIsLeft)
parent.left = current.left;
else
parent.right = current.left;
Binary Trees
// Situation 3: two children
else
{
Node successor = getSuccessor(current);

// Replace current node with successor


if (parent == current)
root = successor;
else if (currentIsLeft)
parent.left = successor;
else
parent.right = successor;

// Successor will always come from the right, so


// it must also take deleted node’s left child
successor.left = current.left;
}
return true;
}
Binary Trees
private Node getSuccessor(Node removedNode)
{
// Prepare successor search by keeping track
// of parent and current
Node successorParent = removedNode;
Node successor = removedNode;
Node current = successor.right;

// Starting at the right child of the node to be


// removed, go down the subtree’s left children
// until there are no more children on the left
while (current != null)
{
successorParent = successor;
successor = current;
current = current.left;
}
Binary Trees
// if the successor is somewhere down the subtree,
// the parent’s left child must take the
// the successor’s right child. Then, the
// successor’s right child takes the node
// to delete’s right child (because successor will
// be replacing it.
if (successor != removedNode.right)
{
successorParent.left = successor.right;
successor.right = removedNode.right;
}

// Note that if the successor is the immediate


// right child of the node to delete, we just
// return that node (it has no left children and what
// ever is on successor’s right stays that way even
// after successor replaces the removed node.
return successor;
}
Binary Trees
An easy way out

• The code is complex as there are many selection


statements implying a large number of test cases
• Another approach is to add a property to the
node class flagging if the node “is deleted”.
There are pros and cons to this:
+ The complexity of delete is not required
+ It allows for an easier “undo” of a delete
+ Useful in situations where delete is not often
– Data space will be used indefinitely
– Physical removal requires traversing entire tree and
recreating with balance
Binary Trees
Update

• The 4th function is update, which requires a search,


followed by a change in value
• In order to maintain the order of the structure though, the
update will likely require moving the node to a new
location in the tree
• The “move” is the equivalent of removing the node,
changing its value and re-inserting it back into the tree
• This is much easier to do instead of developing a way for
nodes to move around in the tree from a relative position
• The question is efficiency, specifically how well do search,
insert and delete perform?
Binary Trees
public boolean update(int oldValue,
int newValue)
{
Node n = search(oldValue);
if (n == null)
return false;

remove(oldValue);
insert(newValue);
return true;
}
Binary Trees
Efficiency

• With a random distribution of adding nodes, search and insert


perform at O(log n)
• With delete, a search is performed followed by a series of checks
for the different situations. This is at least O(log n)
• In the first 2 situations, the code is constant. The 3rd situation
only uses an additional loop to find the successor node
• In a more balanced tree, the number of nodes visited to find the
successor is not significant enough to alter the performance
category (a worst case successor search is an unbalanced tree
leading to O(n) performance anyway which is an already
accepted risk)
• Updates will perform a delete and insert making it O(2 log n).
This is still logarithmic performance
• Thus, we get the same O(log n) category performance for all 4
functions as sorted arrays and we also get dynamic memory
management!
Binary Trees
Sorted Arrays Binary Trees

Search O(log n) O(log n)


Insert O(n) O(log n)

Update O(n) O(log n)

Delete O(n) O(log n)


• Dynamic memory
usage
• All degrade to
O(n) if tree
Static memory becomes more
usage unbalanced
Binary Trees
Arrays revisited

• With binary trees, the question now is why bother with


sorted arrays?
• The code is simpler to implement and use
• Binary trees still have the risk of O(n) performance based
on the manner in which data is inserted
• While the categories are the same for performance
between binary trees and sorted arrays, array performance
is slightly better and more consistent
• Traversing arrays is also easier using the index values
(good for report tables). In fact, how would we traverse
the elements of a binary tree?
Binary Trees
Tree Traversal

• Say you need to display all the elements


in sorted order
• Given an infinite number of different
possible trees, the algorithm to traverse a
tree requires some thought
• We can start small and work our way to
larger trees to find patterns in the logic to
develop the algorithm
• Does this process sound familiar…?
Binary Trees
Tree Traversal

• Start with an empty tree. This may sound


redundant, but it helps with the
algorithm. Put simply, if there is no tree,
don’t display anything (duh!)
• Okay, so big deal. Then, we want to do
something if there is a tree of course,
right?
• Let’s take a look at a balanced 2 level tree
to get an idea of what we do when there
is a tree to display
Binary Trees
Remember that all access begins with the root. This
would start us at 10

root

10

5 15
Binary Trees
If we want to show this tree in sorted order, 10
would not be the first number. From looking at it,
we know we want to display 5 first. However,
how do we state this in logical coding terms?
root

10

5 15
Binary Trees
One way to state it is, “if there is a node to the left,
display the node’s value”. This is then followed
by, “then show my value and then if there is a
node to the right, show its value”
root

10

5 15
Binary Trees
However, trees are not always 2 levels. That logic is
incomplete starting at node 10

root

10

5 15

1 8 12 18
Binary Trees
If we look at the subtree 1-5-8, that does fit our
logic of display left node, then current, then right

root

10

5 15

1 8 12 18
Binary Trees
From the perspective of node 10, we can then
modify our logic to not say “display the node to
the left (or right)”, but “display the subtree to the
left (or right)”
root

10

5 15

1 8 12 18
Binary Trees
Back to recursion!

• It turns out the code for traversing a tree is a very


“simple” form of recursion. As before, we need our base
case and inductive case
• The redundant statement of the obvious a few slides back
turns out to be the base case. If there’s no tree, don’t do
anything
• We can reword that to say, “if there is a tree, do the
following”, and that would be the inductive case:
– Display the tree on the left
– Print the current node’s value
– Display the tree on the right
• As you would guess, the code easily follows this logic
Binary Trees
public void display()
{
displayInOrder(root);
}

void displayInOrder(Node current)


{
if (current != null)
{
displayInOrder(current.left);
System.out.println(current.data);
displayInOrder(current.right);
}
}
Binary Trees
Traversals

• Note that because the code uses recursion, the function to


display the tree actually makes the call to the recursive
function using root as the parameter
• This is the most popular form of traversing a tree. Imagine
writing the code to traverse a tree without recursion. It’s
not impossible, but certainly the recursive case is a lot
easier to code (once the recursive logic is understood of
course!)
• This logic can also be used to take advantage of other
types of traversals. Imagine taking the same 3 level tree
and displaying the currrent node first followed by the
recursive calls to display the trees on the left, then right
Binary Trees
void displayPreOrder(Node current)
{
if (current != null)
{
System.out.println(current.data);
displayPreOrder(current.left);
displayPreOrder(current.right);
}
}
Binary Trees
The output of doing this traversal is:

10 5 1 8 15 12 18

root

10

5 15

This traversal is called


1 “preorder”.
8 12 Another
18 approach is
“postorder”. Display the left and right subtrees first and then
print the current node
Binary Trees
void displayPostOrder(Node current)
{
if (current != null)
{
displayPostOrder(current.left);
displayPostOrder(current.right);
System.out.println(current.data);
}
}
Binary Trees
The output of doing postorder traversal is:

1 8 5 12 18 15 10

root

10

5 15

1 8 12 18
Binary Trees
Traversals

• Why bother with pre and post order


traversals?
• Remember that just because the data in
the tree is ordered, it doesn’t necessarily
mean the data is sorted by values
• Information can be inserted into the tree
to follow a particular order as well
• Observe the following tree…
Binary Trees
Preorder traversal: * 5 + 12 18
Postorder: 5 12 18 + *

root

5 +

Both traversals present a calculation


12 18 notation that can be
used to solve equations entered into a tree (makes for an
interesting insert function)
Binary Trees
Summary

• Binary trees merge the best of both


worlds with sorted arrays and dynamic
memory management
• The code is more complex, but the
resulting performance is comparable
• The primary concern with binary trees is
the potential for the tree to degrade into a
linked list
• Our next topic continues with the tree
type structure, while emphasizing balance

You might also like