Binary Trees
The Long Awaited Sequel
Tree
A data structure which consists of
• a finite set of elements called nodes or vertices.
• a finite set of directed arcs which connect the nodes.
If the tree is nonempty --
• One of the nodes (the root) has no incoming arc.
• Every other node can be reached by following a unique
sequence of consecutive arcs starting at the root.
2
Tree Terminology
3
Binary Tree
A binary tree is a tree with the following
properties:
1. Each branch has at most two children (exactly
two for proper binary trees)
2. The children of a node are an ordered pair
1. We call the children of an internal node
left child and right child
Examples
● Results of multiple coin tosses
● Encoding/decoding messages in dots and dashes
such as Morse code
Binary Tree
Alternative recursive definition: a binary
tree is either
● a tree of a single node
● a tree whose root has an ordered
pair of children, each of which is a
binary tree
Applications:
● Arithmetic expressions
● Decision processes
● Searching
Binary Tree Example
Binary tree associated with an
arithmetic expression
Branches: Operators
Leafs: Operands
Arithmetic expression tree for
the expression:
(2 × (a − 1) + (3 × b))
Binary Tree Example
Binary tree associated with a
decision process
Interior nodes: Questions with
yes/no answer
Branches: Decisions
Leafs: output values
Example: Dining Decision
Binary Tree Terms
a a
b c b c
d e f g d f g
j k l m i l n o
A full or proper binary tree is a tree in which This is an improper binary tree.
every node has either 0 or 2 children.
Binary Tree Terms
a a
b c b c
d e f g d e f g
h i j k l m n o h i l m n o
A perfect binary tree is a tree in which all This is a imperfect tree.
branches have two children and all leaves have
the same depth or same level.
Binary Tree Terms
a a
b c b c
d e f g d e f
h i j k l h i j k l
A complete binary tree is when every level, This is an incomplete binary tree.
except possibly the last, is completely filled, and
all nodes in the last level are as far left as
possible.
Binary Tree Terms
a a
b c b c
d e f g d
h m n o h
A binary tree is balanced if the left and right This binary tree is unbalanced.
subtrees' heights differ by at most one. So the
left subtree must be balanced and the right
subtree must be balanced.
Properties of Binary Trees
● Let T be a nonempty binary tree, then T has the following properties:
1. ℎ + 1 ≤ 𝑛 ≤ 2ℎ+1 − 1
2. 1 ≤ 𝑒 ≤ 2ℎ
3. ℎ ≤ 𝑖 ≤ 2ℎ − 1
4. log(𝑛 + 1) − 1 ≤ ℎ ≤ 𝑛 − 1,
where h - the height of T, n - the number of nodes in T, 𝑒 - the number of
external nodes in T, and 𝑖 - the number of internal node in T
Properties of Full/Proper Binary Trees
Notation:
h ≥ log2(e)
n - number of nodes e=i+1
e - number of leaf / h ≥ log2(n + 1)
n = 2e -
external nodes -1
1
i - number of branch h≤i
/ internal nodes e ≤ 2h
h - height
h ≤ (n - 1) / 2
In a nonempty proper binary tree T, the number of external nodes is one more than the number of internal
nodes.
Implementation
● A binary tree ADT can be implemented either as a
linked structure or as an array.
14
BinaryTree ADT
The BinaryTree ADT extends the Tree ADT, i.e., it inherits all the methods of the
Tree ADT
Additional methods:
● position p.left()
● position p.right()
Update methods may be defined by data structures implementing the BinaryTree
ADT
Proper binary tree: Each node has either 0 or 2 children
//
//
//
//
//
//
//
Node
//
// a node of the tree
struct Node {
Elem elt; // element value
Binary Tree Node* par; // parent
Node* left; // left child
Node* right; // right child
// constructor
Node() : elt(), par(NULL), left(NULL), right(NULL) { }
};
// position in the tree
class Position {
private:
Node* v; // pointer to the node
public:
Position(Node* _v = NULL) : v(_v) { } // constructor
Elem& operator*() { return v->elt; } // get element
// get left, right, parent child
Position
Position left() const { return Position(v->left); }
Position right() const { return Position(v->right); }
Position parent() const { return Position(v->par); }
// is root or external/leaf?
Binary Tree bool isRoot() const { return v->par == NULL; }
bool isExternal() const {
return v->left == NULL && v->right == NULL;
}
friend class LinkedBinaryTree; // give tree access
};
typedef std::list<Position> PositionList; // list of positions
Linked Data Structure for a Binary Tree
Linked Implementation of Binary Trees
● Uses space more efficiently
○ for incomplete trees
● Provides additional flexibility
● Each node has two links
○ One to the left child of the node
○ One to the right child of the node
○ If no child node exists for a node, the link is set to NULL
19
typedef int Elem; // base element type
class LinkedBinaryTree {
protected: // insert Node declaration here...
public: // insert Position declaration here...
public:
LinkedBinaryTree(); // constructor
int size() const; // number of nodes
bool empty() const; // is tree empty?
Interface
Position root() const; // get the root
void addRoot(); // add root to empty tree
PositionList positions() const; // list of nodes
// expand external node
void expandExternal(const Position& p);
Binary Tree // remove p and parent
Position removeAboveExternal(const Position& p);
// housekeeping functions omitted...
protected: // local utilities
void preorder(Node* v, PositionList& pl) const;
private:
Node* _root; // pointer to the root
int n; // number of nodes
};
// constructor
LinkedBinaryTree::LinkedBinaryTree() : _root(NULL), n(0) { }
// number of nodes
int LinkedBinaryTree::size() const {
Simple
return n;
}
Functions
// is tree empty?
bool LinkedBinaryTree::empty() const {
return size() == 0;
}
Binary Tree // get the root
LinkedBinaryTree::Position LinkedBinaryTree::root() const {
return Position(_root);
}
// add root to empty tree
void LinkedBinaryTree::addRoot() {
_root = new Node; n = 1;
}
// list of all nodes
LinkedBinaryTree::PositionList LinkedBinaryTree::positions()
const {
PositionList pl;
preorder(_root, pl); // preorder traversal
return PositionList(pl); // return resulting list
}
Traversal // preorder traversal
void LinkedBinaryTree::preorder(Node* v, PositionList& pl) const
{
Binary Tree pl.push_back(Position(v)); // add this node
if (v->left != NULL) { // traverse left subtree
preorder(v->left, pl);
}
if (v->right != NULL) { // traverse right subtree
preorder(v->right, pl);
}
}
// expand external node
void LinkedBinaryTree::expandExternal(const Position& p) {
Node* v = p.v; // p's node
Expand
v->left = new Node; // add a new left child
v->left->par = v; // v is its parent
v->right = new Node; // and a new right child
Binary Tree v->right->par = v; // v is its parent
n += 2; // two more nodes
}
Binary Tree Remove Node and Parent
// remove p and parent
LinkedBinaryTree::Position
LinkedBinaryTree::removeAboveExternal(const Position& p) {
// get p's node and parent
Node* w = p.v; Node* v = w->par;
Node* sib = (w == v->left ? v->right : v->left);
// child of root?
if (v == _root) {
Removal
_root = sib; // ...make sibling root
sib->par = NULL;
} else {
Node* gpar = v->par; // w's grandparent
if (v == gpar->left) {
Binary Tree gpar->left = sib; // replace parent by sib
} else {
gpar->right = sib;
}
sib->par = gpar;
}
delete w; delete v; // delete removed nodes
n -= 2; // two fewer nodes
return Position(sib);
}
Inorder Traversal
In an inorder traversal a node is
visited after its left subtree and before
its right subtree
Application: draw a binary tree
Algorithm inOrder(v) {
if v.isInternal() {
inOrder(v.left())
}
visit(v)
if v.isInternal() {
inOrder(v.right())
}
}
Methods of Traversal
Preorder Inorder Postorder
1 5 7
2 6 2 7 4 6
3 4 7 1 4 6 1 3 5
5 3 2
Algorithm preOrder(v) { Algorithm inOrder(v) { Algorithm postOrder(v) {
visit(v) if v.isInternal() { if v.isInternal() {
if v.isInternal() { inOrder(v.left()) postOrder(v.left())
preOrder(v.left()) } }
} visit(v) if v.isInternal() {
if v.isInternal() { if v.isInternal() { postOrder(v.right())
preOrder(v.right()) inOrder(v.right()) }
} } visit(v)
} } }
Methods of Traversal
Preorder Inorder Postorder
1 5 7
2 6 2 7 4 6
3 4 7 1 4 6 1 3 5
5 3 2
Algorithm preOrder(v) { Algorithm inOrder(v) { Algorithm postOrder(v) {
visit(v) if v.isInternal() { if v.isInternal() {
if v.isInternal() { inOrder(v.left()) postOrder(v.left())
preOrder(v.left()) } }
} visit(v) if v.isInternal() {
if v.isInternal() { if v.isInternal() { postOrder(v.right())
preOrder(v.right()) inOrder(v.right()) }
} } visit(v)
} } }
Binary trees
● Running time of an n-node binary tree implemented with a linked structure
Operation Time
left, right, parent, isExternal, is root O(1)
size, empty O(1)
root O(1)
expendExternal, removeAboveExternal O(1)
positions O(n)
Array-Based Representation of Binary Trees
Binary trees can also be stored in breadth-first (as opposed to depth-first) order in
arrays
If the tree is a complete binary tree, this method wastes no space
The root of the tree is held at A[0]
The left child of a node is held at 2i + 1, the right child is held at 2i + 2, where i
is the parents index
A parent is held at ⌊(i - 1) / 2⌋ when the root node is at A[0]
Array Binary Trees
0
Arrays benefits from more
compact storage and better 1 2
locality of reference
3 4 5 6
It is expensive to grow and
wastes space proportional to
2h for a tree of depth h with
n nodes. In the worst case,
this can be high as 2𝑛 − 1
Array Implementation of Binary Trees
0
1 2
M T
3 4 5 6
E P U
C
● Store node n in location n of the array.
32
Array Implementation of Binary Trees
● Works OK for complete trees, not for sparse trees
33
Binary search tree
● Everything in left subtree is less than root.
● Everything in right subtree is greater than root. 49
○Recursively!
28 66
● What is the time of searching in a BST?
35 62 80
13
Question:
Draw a (single) binary tree T , such that:
● Each node of T stores a single character
● A preorder traversal of T yields EXAMFUN
● An inorder traversal of T yields MAFXUEN
Question:
What is post order output
of the tree given on the
right?
Question:
Draw the binary tree representation of the following arithmetic expression: (((5+ 4) /(2+1))*(((3+6)-7)/(9-
7))*8)
Question:
Draw an arithmetic expression tree that has four external nodes, storing the number 1,3,5, and 8(with
each number stored in a distinct external node, but not necessary in this order) and has three internal
nodes, each storing an operator from the set {+, -, x, or /}, so that the value of the root is 20. The
operators may return and act on fractions, and operator may be used more than once.
Small Group Activity
Determine how a tree could be utilized to represent an equation. Could
different traversals provide prefix, infix, or postfix notation? Draw a real
example (and cite any sources). Discuss in your small group and post
1-2 paragraphs (with any screenshots necessary for illustration) with
all team members' names included.