DS Module-4 Notes
DS Module-4 Notes
Module-4
Trees: Terminology, Binary Trees, Properties of Binary trees, Array and linked Representation of Binary
Trees, Binary Tree Traversals - Inorder, postorder, preorder; Additional Binary tree operations. Threaded
binary trees, Binary Search Trees – Definition, Insertion, Deletion, Traversal, Searching, Application of
Trees-Evaluation of Expression, Programming Examples
Introduction
Definition of Tree:
A tree is a finite set of one or more nodes such that
There is a special node called the root.
The remaining nodes are partitioned into n ≥ 0 disjoint sets T1, ⋯, Tn, where each of these
sets are called the subtrees of the root.
The tree has 13 nodes and has one character as its information. A tree is always drawn with its root
at the top. Here the node A is the root.
Binary Trees
The Abstract Data type
Definition: A binary tree is a finite set of nodes that is either empty or consists of a root and two
disjoint binary trees called the left subtree and the right subtree.
Objects: a finite set of nodes either empty or consisting of a root node, left Binary_Tree, and right
Binary_Tree.
Induction Base: The root is the only node on level i = 1. Hence, the maximum number of
nodes
on level i = 1 is 2 i-1 = 20 = 1.
Induction Hypothesis: Let i be an arbitrary positive integer greater than 1. Assume that the
maximum number of nodes on level i - 1 is 2i-2.
Induction Step:
The maximum number of nodes on level i - 1 is 2i-2 by the induction hypothesis.
Since each node in a binary tree has a maximum degree of 2, the maximum number of nodes
on level i is two times the maximum number of nodes on level i-1,
i.e 2* 2i-2 = 2i-1
Hence Prooved
Lemma 2: [Relation between number of leaf nodes and degree-2 nodes]: For any non empty binary
tree, T, if n0 is the number of leaf nodes and n2 the number of nodes of degree 2, then n0 = n2 + 1.
Proof:
Let n1 be the number of nodes of degree one and n the total number of nodes. Since all
nodes in T are at most of degree two, we have
n=n0+n1+n2 ---------(1)
If we count the number of branches in a binary tree, we see that every node except the root has
a branch leading into it.
Definition
Full Binary Tree: A full binary tree of depth k is a binary tree of depth k having 2k - 1 nodes, k ≥ 0.
Example
The nodes are numbered in a full binary tree starting with the root on level 1, continuing with the
nodes on level 2, and so on. Nodes on any level are numbered from left to right.
Complete binary tree : A binary tree is complete if the number of nodes in each level i except
possibly the last level is 2i-1. The number of nodes in the last level appears as left as possible.
Example: A complete tree T11 with 11 nodes is shown below. This is not a full binary tree.
Strictly Binary Tree is a tree where every non leaf node in a binary tree has non empty left and
right subtrees.A strictly binary tree with n leaves always contain 2n-1 nodes
Example:
Almost Complete Binary Tree: A binary tree of depth d is an almost complete binary tree if
Example
This representation can be used for any binary tree. In most cases there will be a lot of unutilized
spaces. For complete binary tree such as
Linked Representation
Disadvantage of array representation
The array representation is good for complete binary trees but, it wastes a lot of space for
many other binary trees.
Insertion and deletion of nodes from the middle of a tree require the movement of potentially
many nodes to reflect the change in level number of these nodes.
These problems can be overcome easily through the use of a linked representation.
Leftchild Rightchild
Node Representation
With this node structure it is difficult to determine the parent of a node, If it is necessary to be able to
determine the parent of random nodes, then a fourth field, parent, may be included in the class
TreeNode
Inorder Traversal
Inorder traversal move down the tree toward the left until we can go no farther.
Then "visit" the node,
move one node to the right and continue.
If we cannot move to the right, go back one more node and continue
A precise way of describing this traversal is by using recursion as follows
Preorder Traversal
visit a node
traverse left, and continue.
When you cannot continue, move right and begin again or move back until you can move
right and resume."
}
}
Postorder Traversal
traverse left, and continue.
When you cannot continue, move right and traverse right as far as possible
Visit the node
Example:
Expression Tree: An expression containing operands and binary operators can be represented
by a binary tree.
A node representing an operator is a non leaf. A node representing an operand is a leaf. The root of
the tree contains the operator that has to be applied to the results of evaluating the left subtree and the
right subtree.
When the binary expression trees are traversed preorder we get the preorder expression. When we
traverse the tree postorder we get the postorder expression . When we traverse it inorder we get the
inorder expression.
For Example : consider the traversals for the tree given above
Example:
Result = 3
Testing Equality
Equivalent Binary trees have the same structure and the same information in the
corresponding nodes.
Same structure means every branch in one tree corresponds to a branch in the second tree that
is the branching of the trees is identical.
This function returns true if the two trees are equivalent and false otherwise.
return false;
}
Defintion: The satisfiability problem for formulas of the propositional calculus asks if there is an
assignment of values to the variables that causes the value of the expression to be true.
Example: Representation of the expression (x1 x2) (x1 x3) x3 as a binary tree
x3
x3
x1
X1
X2
Inorder Traversal of the tree is x1 x2 x1 x3 x3 this is the infix form of the expression.
Note: The node containing has only a right branch since is a unary operator.
To determine satisfiability (x1,x2,x3) must take all possible combinations of true or false values and
check the formula for each combination. For n variables ther are 2 n possible combinations of true=t
and false=f.
Example: For n=3 the eight combinations are (t,t,t),(t,t,f),(t,f,t),(t,f,f),(f,t,t), (f,t,f), (f,f,t),(f,f,f).
Analysis: This algorithm will take O(g.2n ) or exponential time, where g is the time to substitute
values for x1,x2, ......... xn and evaluate the expression.
Postorder Evaluation function: To evaluate an expression, the tree is traversed in postorder. When
a node is visited the value of the expression represented by the left and right sub trees of a node are
computed first. So the recursive postorder traversal algorithm is modified to obtain the function that
evaluates the tree.
postorderEval(node->leftchild);
postorderEval(node->rightchild);
switch(node->data)
{
Case not: node->value= ! node->rightchild->value;
Break;
Case and: node->value= node->rightchild->value && node>lefchild->value;
Break;
Case or: node->value= node->rightchild->value || node>lefchild->value;
Break;
Case true: node->value= true; break;
Case false: node->value= false; break;
}
}
Threads
A binary tree has more NULL links than pointers. These null links can be replaced by special
pointers, called threads, to other nodes in the tree.
One way threading: If ptr → rightChild is null, replace ptr → rightChild with a pointer to the
inorder successor of ptr. Ptr->left child remains unchanged.
Note : unless specified we consider threading corresponds to the inorder traversal. To distinguish the
threads from ordinary pointers, threads are always drawn with broken links
Example: consider the binary tree and the corresponding threaded tree given below
Binary tree
When we represent the tree in memory, we must be able to distinguish between threads and
normal pointers.
This is done by adding two additional fields to the node structure, leftThread and
rightThread.
Assume that ptr is an arbitrary node in a threaded tree.
o If ptr → leftThread = TRUE, then ptr→ leftChild contains a thread; otherwise it
contains a pointer to the left child.
o Similarly, if ptr → rightThread = TRUE, then ptr → rightChild contains a thread;
otherwise it contains a pointer to the right child.
In Figure two threads have been left dangling: one in the left child of H, the other in the right
child of G.
To avoid loose threads, a header node is assumed for all threaded binary trees.
The original tree is the left subtree of the header node.
An empty binary tree is represented by its header node as in figure below
t=True
f= False
The variable root points to the header node of the tree, while root → leftChild points to the start of
the first node of the actual tree.
By using the threads, we can perform an inorder traversal without making use of a stack.
For any node, ptr, in a threaded binary tree, if ptr → rightThread = TRUE, the
inorder successor of ptr is ptr → rightChild by definition of the threads.
Otherwise we obtain the inorder successor of ptr by following a path of left-child links from
the right-child of ptr until we reach a node with leftThread = TRUE.
Finding the inorder successor of a node: The function insucc finds the inorder successor of any
node in a threaded tree without using a stack.
ThreadNode * insucc(ThreadNode *tree)
{
ThreadNode * temp;
temp = tree→rightChild;
if (tree→rightThread==’f’)
while (temp→leftThread==’f’)
temp = temp→leftChild;
return temp;
}
printf("%c", temp→data);
}
}
ADT Dictionary
objects: a collection of n > 0 pairs, each pair has a key and an associated item
functions: for all d ∈ Dictionary, item ∈ Item, k ∈ Key, n ∈ integer
To search for a node whose key is k. We begin at the root of the binary search tree.
If the root is NULL, the search tree contains no nodes and the search is unsuccessful.
we compare k with the key in root. If k equals the root's key, then the search terminates
successfully.
If k is less than root's key, then, we search the left subtree of the root.
If k is larger than root's key value, we search the right subtree of the root.
struct node
{
Struct node *lchild;
struct
{
int item; /* Itype represents the data type of the element*/
int key;
}data;
Recursive search of a binary search tree: Return a pointer to the element whose key is k, if there
is no such element, return NULL. We assume that the data field of the element is of type elemenet
and it has two components key and item.
{
while (tree!=null)
{
if (k == tree→data.key)
return (tree);
if (k < tree→data.key)
tree = tree→leftChild;
else
tree = tree→rightChild;
}
return NULL;
}
Analysis of Search(Both iterative and recursive): If h is the height of the binary search tree, then
we can perform the search using either search in O(h). However, recursive search has an additional
stack space requirement which is O(h).
Inserting in to a Binary Search Tree: Binary search tree has distinct values, first we searchthe
tree for the key and if the search is unsuccessful the key is inserted at the point the search
terminated
If k is in the tree pointed at by node do nothing. Otherwise add a new node with data = (k, item)
lastnode=Modifiedsearch(root,k);
Ptr=(TreeNode*)malloc(sizeof(TreeNode));
ptr→data.key = k;
ptr→data.item = Item;
ptr→leftChild = ptr→rightChild = NULL;
if (root==NULL)
{
root=ptr;
return(root);
}
if(lastnode!=NULL)
{
if (k < lastnode→data.key)
lastnode→leftChild = ptr;
else
lastnode→rightChild = ptr;
return (root);
}
If the element is present or if the tree is empty the function Modifiedsearch returns NULL. If the
element is not present it retrun a pointer to the last node searched.
Modifiedsearch(Treenode *root,int k)
TreeNode *temp,*prev;
temp==node;
prev=NULL;
If(temp==NULL)
return(NULL);
while(temp!=NULL)
{
if(temp->data.key==k)
{
printf(“element already found”);
return(NULL);
}
if(key<temp->data.key)
{
prev=temp;
temp=temp->lchild;
}
else
{
Prev=temp;
Temp=temp->rchild;
}
}
retrun(prev);
Deletion from a binary search tree: Suppose T is a a binary search tree. The function to
delete an item from tree T first search the tree to find the location of the node with the item
and the location of the parent of N and the deletion of the node N depends on three cases:
Case 1: N has no children. Then N is deleted from T by replacing the location of the node N in the
parent(N) by the NULL pointer
Deleting node
Case 2: If N has exactly one child. Then N is deleted from T by replacing the location of N in Parent
(N) by the location of the only child of N.
Deleting node 75
Case 3: N has Two children. Let S(N) denote the inorder successor of N(S(N) does not have a left
child).Then N is deleted from T by first deleting S(N) from T (by using case1 or cae 2) and then
replacing node N in T by the node S(N).
if (node == NULL)
return node;
else
{
// node with only one child
if (node->lchild == NULL)
{
temp = node->rchild;
free(node);
return temp;
}
else if (node->rchild == NULL)
{
temp = node->lchild;
free(node);
return temp;
}
// node with two children
else
{
temp = node->rchild;
while(temp->lchild!=NULL) //Get the inorder successor
temp=temp->lchild;
node->data.item = temp->data.item;
node->data.key=temp->data.key;
node->rlink = delete_element(node->rchild, temp->data.key);
return node;
}
}}