Binary Trees in Computer Science

undefined
CS 143
Lecture 10: Binary Trees
Thanks to Marty Stepp and Stuart Reges for parts of these slides
Recursion Review
 
What do we always need when writing a recursive function?
 
Base case
 
Recursive case
Trees
tree
: A directed, acyclic structure of linked nodes.
directed
 : Has one-way links between nodes.
acyclic
 : No path wraps back around to the same node twice.
binary tree
: One where each node has at most two children.
Recursive definition:
 A tree is either:
empty (
null
), or
a 
root
 node that contains:
data
,
a 
left
 subtree, and
a 
right
 subtree.
(The left and/or right
subtree could be empty.)
Trees in computer science
TreeMap and TreeSet implementations
folders/files on a computer
family genealogy; organizational charts
AI: decision trees
compilers: parse tree
a = (b + c) * d;
cell phone T9
Terminology
node
: an object containing a data value and left/right children
root
: topmost node of a tree
leaf
: a node that has no children
branch
: any internal node;  neither the root nor a leaf
parent
: a node that refers to this one
child
: a node that this node refers to
sibling
: a node with a common parent
subtree
: the smaller tree of nodes on
 
the left or right of the current node
height
: length of the longest path
 
from the root to any node
level
 or 
depth
: length of the path
 
from a root to a given node
height = 3
level 1
level 2
level 3
Recursive data structure
Recursive definition:
 A tree is either:
empty (
null
), or
a 
root
 node that contains:
data
,
a 
left
 tree, and
a 
right
 tree
3
1
root
A tree node for integers
A basic 
tree node object
 stores data, refers to left/right
Multiple nodes can be linked together into a larger tree
IntTreeNode
 class
// An IntTreeNode object is one node in a binary tree of ints.
public class IntTreeNode {
    public int data;            
// data stored at this node
    public IntTreeNode left;    
// reference to left subtree
    public IntTreeNode right;   
// reference to right subtree
    // Constructs a leaf node with the given data.
    public IntTreeNode(int data) {
        this(data, null, null);
    }
    // Constructs a branch node with the given data and links.
    public IntTreeNode(int data, IntTreeNode left,
                                 IntTreeNode right) {
        this.data = data;
        this.left = left;
        this.right = right;
    }
}
IntTree
 class
// An IntTree object represents an entire binary tree of ints.
public class IntTree {
    private IntTreeNode overallRoot;   
// null for an empty tree
    
methods
}
Client code talks to the 
IntTree
,
not to the node objects inside it.
Methods of the 
IntTree
 create
and manipulate the nodes,
their data and links between them.
IntTree
 constructors
For now, assume we have the following constructors:
 
public IntTree(
IntTreeNode overallRoot
)
 
public IntTree(
int height
)
The 2nd constructor will create a tree and
fill it with nodes with random data values
from 1-100 until it is full at the given height.
 
IntTree tree = new IntTree(
3
);
Traversals
traversal
: An examination of the elements of a tree.
A pattern used in many tree algorithms and methods
Common orderings for traversals:
pre-order
:
 
process root node, then its left/right subtrees
in-order
:
 
process left subtree, then root node, then right
post-order
:
 
process left/right subtrees, then root node
Traversal example
pre-order:
 
17 41 29 6 9 81 40
in-order:
 
29 41 6 17 81 9 40
post-order:
 
29 6 41 81 40 9 17
Traversal trick
To quickly generate a traversal:
Trace a path around the tree.
As you pass a node on the
proper side, process it.
pre-order: left side
in-order: bottom
post-order: right side
pre-order:
 
17  41  29  6  9  81  40
in-order:
 
29  41  6  17  81  9  40
post-order:
 
29  6  41  81  40  9  17
 
Give pre-, in-, and post-order
traversals for the following tree:
 
 
 
 
 
 
 
 
 
pre:
 
42 15 27 48 9 86 12 5 3 39
in:
 
15 48 27 42 86 5 12 9 3 39
post:
 
48 27 15 5 12 86 39 3 42
Exercise
Exercise
Add a method 
print
 to the 
IntTree
 class that prints the elements of
the tree, separated by spaces.
A node's left subtree should be printed before it, and its right subtree should
be printed after it.
Example: 
tree.print();
 
29 41 6 17 81 9 40
Exercise solution
// An IntTree object represents an entire binary tree of ints.
public class IntTree {
    private IntTreeNode overallRoot;   
// null for an empty tree
    ...
    public void print() {
        
print(overallRoot);
        System.out.println();   
// end the line of output
    }
    private void print(IntTreeNode root) {
        // (base case is implicitly to do nothing on null)
        if (root != null) {
            // recursive case: print left, center, right
            
print(overallRoot.left);
            System.out.print(overallRoot.data + " ");
            
print(overallRoot.right);
        }
    }
}
Template for tree methods
public class IntTree {
    private IntTreeNode overallRoot;
    ...
    public 
type
 
name
(
parameters
) {
        name(overallRoot, 
parameters
);
    }
    private 
type
 
name
(IntTreeNode root, 
parameters
) {
        ...
    }
}
Tree methods are often implemented recursively
with a public/private pair
the private version accepts the root node to process
Exercise
Add a method 
contains
 to the 
IntTree
 class that searches the tree
for a given integer, returning 
true
 if it is found.
If an 
IntTree
 variable 
tree
 referred to the tree below, the following calls
would have these results:
tree.contains(87)
 
 
true
tree.contains(60)
 
 
true
tree.contains(63)
 
 
false
tree.contains(42)
 
 
false
Exercise solution
// Returns whether this tree contains the given integer.
public boolean contains(int value) {
    return 
contains(overallRoot, value);
}
private boolean 
contains
(IntTreeNode node, int value) {
    if (node == null) {
        return false;   
// base case: not found here
    } else if (node.data == value) {
        return true;    
// base case: found here
    } else {
        
// recursive case: search left/right subtrees
        return 
contains(node.left, value) ||
               
contains(node.right, value);
    }
}
Exercise
Add a method named 
printSideways
 to the 
IntTree
 class that prints
the tree in a sideways indented format, with right nodes above roots above
left nodes, with each level 4 spaces more indented than the one above it.
Example: Output from the tree below:
        19
    14
        11
9
        7
    6
Exercise solution
// Prints the tree in a sideways indented format.
public void printSideways() {
    printSideways(overallRoot, "");
}
private void printSideways(IntTreeNode root,
                           String indent) {
    if (root != null) {
        printSideways(root.right, indent + "    ");
        System.out.println(indent + root.data);
        printSideways(root.left, indent + "    ");
    }
}
Adding to a BST
 
Suppose we want to add new values to the BST below.
Where should the value 14 be added?
Where should 3 be added?  7?
 
If the tree is empty, where
should a new value be added?
 
What is the general algorithm?
overall root
Adding exercise
Draw what a binary search tree would look like if the following values
were added to an initially empty tree in this order:
50
20
75
98
80
31
150
39
23
11
77
50
Exercise
Add a method 
add
 to the 
SearchTree
 class that adds a given integer
value to the BST.
Add the new value in the proper place to maintain BST ordering.
tree.add(49)
;
An incorrect solution
// Adds the given value to this BST in sorted order.
public void add(int value) {
    add(overallRoot, value);
}
private void add(IntTreeNode node, int value) {
    if (node == null) {
        node = new IntTreeNode(value);
    } else if (node.data > value) {
        add(node.left, value);
    } else if (node.data < value) {
        add(node.right, value);
    }
    // else node.data == value, so
    // it's a duplicate (don't add)
}
Why doesn't this solution work?
undefined
The x = change(x)
pattern
 
A tangent: Change a point
 
What is the state of the object referred to by 
p
 after this code?
 
public static void main(String[] args) {
    Point p = new Point(1, 2);
    change(p);
    System.out.println(p);
}
 
public static void change(Point thePoint) {
    thePoint.x = 3;
    thePoint.y = 4;
}
 
// answer: (3, 4)
Change point, version 2
 
What is the state of the object referred to by 
p
 after this code?
 
public static void main(String[] args) {
    Point p = new Point(1, 2);
    change(p);
    System.out.println(p);
}
 
public static void change(Point thePoint) {
    thePoint = new Point(3, 4);
}
 
 
// answer: (1, 2)
Changing references
If a method 
dereferences a variable
  (with 
.
 ) and modifies the object it
refers to, that change will be seen by the caller.
public static void change(Point thePoint) {
    
thePoint.x = 3;
                
// affects p
    
thePoint.setY(4);
              
// affects p
If a method 
reassigns a variable to refer to a new object,
 that change will
not 
affect the variable passed in by the caller.
public static void change(Point thePoint) {
    
thePoint = new Point(3, 4);
    
// p unchanged
    
thePoint = null;
               
// p unchanged
What if we want to make the variable passed in become 
null
?
Change point, version 3
 
What is the state of the object referred to by 
p
 after this code?
 
public static void main(String[] args) {
    Point p = new Point(1, 2);
    change(p);
    System.out.println(p);
}
 
public static 
Point
 change(Point thePoint) {
    thePoint = new Point(3, 4);
    return thePoint;
}
 
// answer: (1, 2)
Change point, version 4
 
What is the state of the object referred to by 
p
 after this code?
 
public static void main(String[] args) {
    Point p = new Point(1, 2);
    p =
 change(p);
    System.out.println(p);
}
 
public static Point change(Point thePoint) {
    thePoint = new Point(3, 4);
    return thePoint;
}
 
// answer: (3, 4)
p
x = change(x);
If you want to write a method that can change the object that a variable
refers to, you must do three things:
1.
 
 
pass 
in the original state of the object to the method
2.
 
 
return 
the new (possibly changed) object from the method
3.
 
 
re-assign
 the caller's variable to store the returned result
    p = change(p);    
// in main
public static Point 
change
(Point thePoint) {
    thePoint = new Point(99, -1);
    return thePoint;
We call this general algorithmic pattern  
x = change(x);
also seen with strings:  
s =
 s.toUpperCase();
The problem
 
Much like with linked lists, if we just modify what a local variable refers to,
it won't change the collection.
 
 
private void add(IntTreeNode node, int value) {
    if (node == null) {
        node = new IntTreeNode(value);
    }
 
In the linked list case, how did we
actually modify the list?
by changing the 
front
by changing a node's 
next
 field
Applying x = change(x)
 
Methods that modify a tree should have the following pattern:
input (parameter):
 
old state of the node
output (return):
 
new state of the node
 
 
 
In order to actually change the tree, you must reassign:
 
 
node        = 
change
(node, 
parameters
);
 
node.left   = 
change
(node.left, 
parameters
);
 
node.right  = 
change
(node.right, 
parameters
);
 
overallRoot = 
change
(overallRoot, 
parameters
);
your
method
node
before
node
after
parameter
return
A correct solution
// Adds the given value to this BST in sorted order.
public void add(int value) {
    
overallRoot =
 
add(overallRoot, value);
}
private 
IntTreeNode
 add(IntTreeNode node, int value) {
    if (node == null) {
        node = new IntTreeNode(value);
    } else if (node.data > value) {
        
node.left = 
add(node.left, value);
    } else if (node.data < value) {
        
node.right = 
add(node.right, value);
    } 
// else a duplicate; do nothing
    
return node;
}
What happens when 
node 
is a leaf?
Slide Note
Embed
Share

Binary trees are a fundamental data structure in computer science with various applications. This content covers the basics of binary trees, including terminology, recursive definitions, node structures, and implementations in computer science. It touches on important concepts such as recursion, tree traversal, and tree node properties. Examples and images are provided to aid in understanding the concepts presented.

  • Binary Trees
  • Data Structures
  • Computer Science
  • Recursion
  • Tree Terminology

Uploaded on Oct 05, 2024 | 0 Views


Download Presentation

Please find below an Image/Link to download the presentation.

The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. Download presentation by click this link. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.

E N D

Presentation Transcript


  1. CS 143 Lecture 10: Binary Trees Thanks to Marty Stepp and Stuart Reges for parts of these slides

  2. Recursion Review What do we always need when writing a recursive function? Base case Recursive case 2

  3. Trees tree: A directed, acyclic structure of linked nodes. directed : Has one-way links between nodes. acyclic : No path wraps back around to the same node twice. binary tree: One where each node has at most two children. root Recursive definition: A tree is either: empty (null), or a root node that contains: 1 data, a left subtree, and 2 3 a right subtree. (The left and/or right subtree could be empty.) 4 5 6 7 3

  4. Trees in computer science TreeMap and TreeSet implementations folders/files on a computer family genealogy; organizational charts AI: decision trees = compilers: parse tree a = (b + c) * d; a * cell phone T9 + d b c 4

  5. Terminology node: an object containing a data value and left/right children root: topmost node of a tree leaf: a node that has no children branch: any internal node; neither the root nor a leaf parent: a node that refers to this one child: a node that this node refers to sibling: a node with a common parent root height = 3 1 level 1 subtree: the smaller tree of nodes on the left or right of the current node height: length of the longest path from the root to any node level or depth: length of the path from a root to a given node 2 3 level 2 4 5 6 7 level 3 5

  6. Recursive data structure Recursive definition: A tree is either: empty (null), or a root node that contains: data, a left tree, and a right tree root root root root root 1 1 1 1 3 2 3 7 6

  7. A tree node for integers A basic tree node object stores data, refers to left/right Multiple nodes can be linked together into a larger tree left data right 42 left data right 59 left data right 27 left data right 86 7

  8. IntTreeNode class // An IntTreeNode object is one node in a binary tree of ints. public class IntTreeNode { public int data; // data stored at this node public IntTreeNode left; // reference to left subtree public IntTreeNode right; // reference to right subtree // Constructs a leaf node with the given data. public IntTreeNode(int data) { this(data, null, null); } // Constructs a branch node with the given data and links. public IntTreeNode(int data, IntTreeNode left, IntTreeNode right) { this.data = data; this.left = left; this.right = right; } } left data right 8

  9. IntTree class // An IntTree object represents an entire binary tree of ints. public class IntTree { private IntTreeNode overallRoot; // null for an empty tree methods } overallRoot 1 Client code talks to the IntTree, not to the node objects inside it. 2 3 Methods of the IntTree create and manipulate the nodes, their data and links between them. 4 5 6 7 9

  10. IntTree constructors For now, assume we have the following constructors: public IntTree(IntTreeNode overallRoot) public IntTree(int height) The 2nd constructor will create a tree and fill it with nodes with random data values from 1-100 until it is full at the given height. overallRoot 17 IntTree tree = new IntTree(3); 41 9 29 6 81 40 10

  11. Traversals traversal: An examination of the elements of a tree. A pattern used in many tree algorithms and methods Common orderings for traversals: pre-order: process root node, then its left/right subtrees in-order: process left subtree, then root node, then right post-order: process left/right subtrees, then root node overallRoot 17 41 9 29 6 81 40 11

  12. Traversal example overallRoot 17 41 9 29 6 81 40 pre-order: in-order: post-order: 17 41 29 6 9 81 40 29 41 6 17 81 9 40 29 6 41 81 40 9 17 12

  13. Traversal trick overallRoot To quickly generate a traversal: Trace a path around the tree. As you pass a node on the proper side, process it. 17 41 9 pre-order: left side in-order: bottom post-order: right side 29 6 81 40 pre-order: in-order: post-order: 17 41 29 6 9 81 40 29 41 6 17 81 9 40 29 6 41 81 40 9 17 13

  14. Exercise overallRoot Give pre-, in-, and post-order traversals for the following tree: 42 15 9 27 86 3 48 12 39 pre: in: 15 48 27 42 86 5 12 9 3 39 post: 48 27 15 5 12 86 39 3 42 42 15 27 48 9 86 12 5 3 39 5 14

  15. Exercise Add a method print to the IntTree class that prints the elements of the tree, separated by spaces. A node's left subtree should be printed before it, and its right subtree should be printed after it. overallRoot Example: tree.print(); 17 29 41 6 17 81 9 40 41 9 29 6 81 40 15

  16. Exercise solution // An IntTree object represents an entire binary tree of ints. public class IntTree { private IntTreeNode overallRoot; // null for an empty tree ... public void print() { print(overallRoot); System.out.println(); // end the line of output } private void print(IntTreeNode root) { // (base case is implicitly to do nothing on null) if (root != null) { // recursive case: print left, center, right print(overallRoot.left); System.out.print(overallRoot.data + " "); print(overallRoot.right); } } } 16

  17. Template for tree methods public class IntTree { private IntTreeNode overallRoot; ... public typename(parameters) { name(overallRoot, parameters); } private typename(IntTreeNode root, parameters) { ... } } Tree methods are often implemented recursively with a public/private pair the private version accepts the root node to process 17

  18. Exercise Add a method contains to the IntTree class that searches the tree for a given integer, returning true if it is found. If an IntTree variable tree referred to the tree below, the following calls would have these results: overallRoot tree.contains(87) true tree.contains(60) true tree.contains(63) false tree.contains(42) false 55 87 29 -3 42 60 60 18

  19. Exercise solution // Returns whether this tree contains the given integer. public boolean contains(int value) { return contains(overallRoot, value); } private boolean contains(IntTreeNode node, int value) { if (node == null) { return false; // base case: not found here } else if (node.data == value) { return true; // base case: found here } else { // recursive case: search left/right subtrees return contains(node.left, value) || contains(node.right, value); } } 19

  20. Exercise Add a method named printSideways to the IntTree class that prints the tree in a sideways indented format, with right nodes above roots above left nodes, with each level 4 spaces more indented than the one above it. Example: Output from the tree below: overall root 9 19 14 11 9 7 6 6 14 7 11 19 20

  21. Exercise solution // Prints the tree in a sideways indented format. public void printSideways() { printSideways(overallRoot, ""); } private void printSideways(IntTreeNode root, String indent) { if (root != null) { printSideways(root.right, indent + " "); System.out.println(indent + root.data); printSideways(root.left, indent + " "); } } 21

  22. Adding to a BST Suppose we want to add new values to the BST below. Where should the value 14 be added? overall root Where should 3 be added? 7? 8 If the tree is empty, where should a new value be added? 5 11 What is the general algorithm? 2 10 19 7 4 25 22 22

  23. Change point, version 2 What is the state of the object referred to by p after this code? public static void main(String[] args) { Point p = new Point(1, 2); change(p); System.out.println(p); } 1 2 x y p public static void change(Point thePoint) { thePoint = new Point(3, 4); } // answer: (1, 2) 3 4 x y 28

  24. Changing references If a method dereferences a variable (with . ) and modifies the object it refers to, that change will be seen by the caller. public static void change(Point thePoint) { thePoint.x = 3; // affects p thePoint.setY(4); // affects p If a method reassigns a variable to refer to a new object, that change will not affect the variable passed in by the caller. public static void change(Point thePoint) { thePoint = new Point(3, 4); // p unchanged thePoint = null; // p unchanged What if we want to make the variable passed in become null? 29

  25. Change point, version 3 What is the state of the object referred to by p after this code? public static void main(String[] args) { Point p = new Point(1, 2); change(p); System.out.println(p); } 1 2 x y p public static Point change(Point thePoint) { thePoint = new Point(3, 4); return thePoint; } // answer: (1, 2) 3 4 x y 30

  26. Change point, version 4 What is the state of the object referred to by p after this code? public static void main(String[] args) { Point p = new Point(1, 2); p = change(p); System.out.println(p); } 1 2 p x y public static Point change(Point thePoint) { thePoint = new Point(3, 4); return thePoint; } // answer: (3, 4) 3 4 x y 31

  27. x = change(x); If you want to write a method that can change the object that a variable refers to, you must do three things: 1. pass in the original state of the object to the method 2. return the new (possibly changed) object from the method 3. re-assign the caller's variable to store the returned result p = change(p); // in main public static Point change(Point thePoint) { thePoint = new Point(99, -1); return thePoint; We call this general algorithmic pattern x = change(x); also seen with strings: s = s.toUpperCase(); 32

  28. Applying x = change(x) Methods that modify a tree should have the following pattern: old state of the node new state of the node input (parameter): output (return): parameter return node before node after your method In order to actually change the tree, you must reassign: node = change(node, parameters); node.left = change(node.left, parameters); node.right = change(node.right, parameters); overallRoot = change(overallRoot, parameters); 34

More Related Content

giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#