Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
By convention, rooted trees are shown to grow downwards with the root
node shown at the top and serves as start or the entry point in to the tree.
All other nodes are said to be descendents of the root node. The direct
descendents (nodes that have a direct link) of a node are called its
children and the node itself is called the parent of those nodes. Children
of the same node are called siblings. The root node does not have any
parent. Every other node has exactly one parent. A node may have 0 or
Page 1 of 16
Quresh
Ghalib Muharib
Taiem Luayy
Zahra Qusayy
Haris Zubair Abu Talib Abdullah Musa'ab Abu Lahab Maqoom Hajl Abbas Mugheera Hamza Zarrar
Muhammad
(PBUH)
Page 2 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
more children. A node with zero children is called a leaf node. Nodes
other than the leaf nodes and the root node are called internal or
intermediate nodes. That is, an intermediate node has exactly one parent
and at least one child.
Figure … shows a rooted tree with root A with nodes B, F, and K as its
children/subtrees. Nodes B, F, K , C, D, and X are internal nodes whereas
H, L, Q, G, M, I, N, and P are leaf nodes.
Level of a node is defined as the distance of the node from the root node.
In Figure … A is at level 0, B, F, and K are at level 1, C, H, D, L and X are
level 2, and the rest are at level 3.
Height of a tree is defined as the maximum level of any node in the tree1.
Height of tree in Figure… is 3.
1
Definition of height and level is not standardized and may slightly vary from one
text to the other.
Page 3 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
Figure… (a) and (b) are examples of binary trees. In Figure…(a), B is the
left child of A and H is the right child of B.
It can be very easily seen that the maximum number of nodes on level i of
a binary tree is 2i and the maximum number of nodes in a binary tree of
height k is 2k+1 – 1.
A binary tree of height k having 2k+1 – 1 nodes is called a full binary tree.
A binary tree is a full binary tree if and only if all leaf nodes are at the
same level and all other nodes have degree 2. Figure… shows a full binary
tree of height 4 with 15 nodes in it.
Page 4 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
A complete binary tree is a binary tree that is completely filled, with the
possible exception of the bottom level, which is filled from left to right.
then the tree is a complete binary tree iff the maximum number thus
assigned is equal to the number of nodes in the tree. Note that full binary
tree is also a complete binary tree.
Page 5 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
data
template <class T>
struct TreeNode {
T data;
TreeNode<T> *left, *right;
};
left right
We can now use this node structure to define our binary tree whose
specification is shown in Figure…
template <class T>
class BinaryTree {
public:
BinaryTree(){root = NULL;} // create an empty binary tree
void buildBinaryTree( T data, BinaryTree<T> &leftSubtree,
BinaryTree<T> &rightSubtree);
/*************************************************************
This method can be used to build a binary tree bottoms up. The
modified tree is rooted at a node with the input data and its
left and right children are made-up of the left and right
subtrees passed as input parameters. The left and right
subtrees passed as input lose their contents and their roots
are set to NULL.
**************************************************************/
~BinaryTree(){clear(root);}
void inOrder(){inOrder(root);} // in-order traversal
void preOrder(){inOrder(root);} // pre-order traversal
void postOrder(){inOrder(root);} // post-order traversal
BinaryTree(const BinaryTree & bt); // copy constructor
const BinaryTree & operator=(const BinaryTree & rhs);
// assignment operator
private:
TreeNode <T> *root;
friend class LNRIterator<T>; // in-order iterator
TreeNode<T> * createTreeNode(T data);
void clear(TreeNode<T> *t); // cleanup tree
void inOrder(TreeNode<T> *t); // in-order workhorse
void preOrder(TreeNode<T> *t); // pre-order workhorse
void postOrder(TreeNode<T> *t); // post-order workhorse
};
Page 6 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
Figure… shows the methods to build the binary from bottom to top.
template <class T>
TreeNode<T> * BinaryTree<T> :: createTreeNode(T data) {
TreeNode<T> *t = new TreeNode<T>;
if (t != NULL) {
t->data = data;
t->left = t->right = NULL;
return t;
}
else
throw OUT_OF_MEMORY;
}
TreeNode<T> *t = createTreeNode(data);
// make the left and right of the new node point to the roots
// of the left and right sub-trees respectively
t->left = leftSubtree->root;
t->right = rightSubtree->root;
leftSubtree->root = NULL;
rightSubtree->root = NULL;
1. This method detaches the nodes present in the trees passed as input
parameters and attaches those nodes to the tree which we are building
from these sub-trees. Hence these trees are effectively destroyed by
assigning NULL value to their roots.
2. The second last statement in the method, clear(root), is very
important. It essentially destroys the target tree by returning any
nodes attached to back to heap. Failing to do so could create garbage.
Page 7 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
Figure …(b to f) demonstrates how this method could be used to build the
tree of Figure….(a).
2 5
root root
2 NULL
t1 t2
root root
1 3
t1 t2
1 3
(c) t1.buildTree(1,nullTree, nullTree);
t2.buildTree(3,nullTree, nullTree); (d) t1.buildTree(2,t1, t2);
root root
4 NULL
t1 t2
2 5
root
5 1 3
t2
(e) t2.buildTree(5, nullTree, nullTree); (f) t1.buildTree(4,t1, t2);
Page 8 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
It is often required to visit (access) each node in the tree and process data
present in there. For that purpose some tree traversal algorithm is used
which provides a systematic approach to access all the nodes in the tree. A
complete traversal generates a linear order of all the nodes in the tree.
N - Node
NLR – process the node, then traverse the left subtree, then traverse the right subtree
NRL – process the node, then traverse the right subtree, then traverse the left subtree
LNR – traverse the left subtree, then process the node, then traverse the right subtree
LRN – traverse the left subtree, then traverse the right subtree, then process the node
RNL – traverse the right subtree, process the node, then then traverse the left subtree
RLN – traverse the right subtree, then traverse the left subtree, then process the node
L R
Left subtree Right subtree
Let N, L, and R denote node, left subtree, and right subtree of a tree. As
shown in Figure…, these three letters (N, L, and R) can be arranged in six
different permutations – NLR, NRL, LNR, LRN, RNL, and RLN. These six
permutations correspond to six different traversals of the binary tree. For
example, LNR corresponds to a traversal in which we complete the tree
traversal by first traversing the left subtree, then visiting the node, and
then traversing the right subtree. If we always traverse left before right
then we are left with three possible traversal – NLR, LNR, and LRN.
These three are called pre-order, in-order, and post-order respectively.
C++ code for in-order and pre-order workhorse functions is given in
Figure…
Page 9 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
B K
C H L X
Q M P
Figure… shows the three tree traversals for an expression tree. Note that
the in-order, pre-order, and post-order traversals generate the expression
in infix, prefix, and postfix respectively.
+ /
A * D *
B C E F
LNR: A + B * C – D / E * F
NLR: – + A * B C / D * E F
LRN: A B C * + D E F * / –
Page 10 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
Exercise
Page 11 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
15. write a member function that deletes all the nodes with degree 1 from
the tree.
16. write a member function that takes two keys as input and inserts a
node with second key as the left most descendent of the node with
the first key if it the first key present in the tree making the new node
the first node to be visited in in-order in the tree rooted at the node
that contains the first key.
17. write a member function that takes two keys as input and inserts a
node with second key as the right most descendent of the node with
the first key if it the first key present in the tree making the new node
the last node to be visited in in-order in the tree rooted at the node
that contains the first key.
Page 12 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
public:
LNRIterator(const BinaryTree<T> &bt):tree(bt), current(NULL){ }
bool isDone() {return current == NULL; }
T getData() {
if (!isDone()) return current->data;
else throw ILLEGAL_REFERNCE_EXCEPTION;
}
};
The constructor, isDone, and getData are trivial and do not need
elaboration. We will therefore only focus on begin and next which are
given in Figure ….
Page 13 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
After visiting a node, the in-order traversal of the right subtree by moving
to its right child and then to the leftmost descendent of the right child
and saving the address of the nodes encountered in the process. This is
like repeating the process similar to begin for the tree rooted at the right
child of a node. Once the traversal on the right is complete, this means
the entire subtree rooted at that node is complete and hence current
moves back one step in the hierarchy by popping the address of its
ancestor. The process continues until NULL is popped from the stack and
assigned to current, indicating end of traversal. The code for the next()
operation is given in Figure…
template <class T>
void LNRIterator<T> :: next() {
if (current == NULL) throw ILLEGAL_REFERENCE_EXCEPTION;
if (current->right != NULL) {
current = gotoTheLeftmostDescendent(current->right);
else current = stk.pop();
}
Page 14 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
We can now use this iterator to for our specific purpose as shown below:
BinaryTree<int> binTree;
// add data to the tree
LNRIterator<int> myIterator(binTree);
Exercise:
Page 15 of 16
Data Structures – Fakhar lodhi – Chapter 5: Trees
ABKCHLXQMP
We start by inserting the root node to the queue. Then we remove a node
from the queue, visit it and put its children, if any, on the queue. The
process continues until there is nothing left on the queue. The code for
level-order traversal is presented in Figure…
template <class T>
void BinaryTree<T> :: levelOrder() {
if (root != NULL) {
TreeNode<T> *t;
Queue<TreeNode<T> *> que;
que.add(root);
while(!que.isEmpty()) {
t = que.remove();
visit(t);
if (t->left != NULL) que.add(t->left);
if (t->right != NULL) que.add(t->right);
}
}
}
Exercise:
1. Write a function that takes a number as input and prints all the nodes
present at that level.
2. Write level-order iterator.
3. Write a recursive function to achieve the task specified in Q. 1
Page 16 of 16