MergeResult 2024 04 06 04 46 13
MergeResult 2024 04 06 04 46 13
Data Structure
Data Structure is a way of collecting and organizing data in such a way that we can
perform operations on these data in an effective way.
Primitive data structures are the basic data structures that directly operate upon the machine
instructions.
They are the fundamental data types which are supported by a programming language.
Some basic data types are integer, real, character, and Boolean.
Non-primitive data Structures
Non-primitive data structures are those data structures which are created using primitive data
structures.
Examples of such data structures include linked lists, stacks, trees, and graphs.
If the elements of a data structure are stored in a linear or sequential order, then it is a
linear data structure.
If the elements of a data structure are not stored in a sequential order, then it is a non-
linear data structure.
This structure is mainly used to represent data containing a hierarchical relationship between
elements.
Traversing- It is used to access each data item exactly once so that it can be processed. This
accessing and processing sometimes called as visiting the record.
Searching- It is used to find out the location of the data item if it exists in the given
collection of data items.
Inserting- It is used to add a new data item in the given collection of data items.
Deleting- It is used to delete an existing data item from the given collection of data items.
Sorting- It is used to arrange the data items in some order i.e. in ascending or descending
order in case of numerical data and in dictionary order in case of alphanumeric data.
Merging- It is used to combine the data items of two sorted files into single file in the sorted
form.
Review of Pointers
o Pointers are used to pass information back and forth between functions.
o Pointers enable the programmers to return multiple data items from a function
via function arguments.
o Pointers are used to create complex data structures, such as trees, linked lists, linked
stacks, linked queues, and graphs.
data_type *ptr_name;
Null Pointers
A null pointer is a special pointer value that does not point to any valid memory address.
*ptr; ptr = 0;
A function that returns pointer values can return a null pointer when it is unable to perform
its task.
Generic Pointers
A generic pointer is a pointer variable that has void as its data type.
The void pointer, or the generic pointer, is a special type of pointer that can point to
Pointer to Pointers
To declare pointers to pointers, just add an asterisk * for each level of reference.
The process of allocating memory to the variables during execution of the program or at run time
is known as dynamic memory allocation.
malloc ()
The above header file is included in any program that calls malloc.
The malloc function reserves a block of memory of specified size and returns a pointer of
type void.
where ptr is a pointer of type cast-type. malloc () returns a pointer (of cast type) to an
area of memory with size byte-size.
Example:
The address of the first byte of memory allocated is assigned to the pointer arr of type int.
calloc ()
It is used to request multiple blocks of storage each of the same size and then sets all
bytes to zero.
Syntax:
The above statement allocates contiguous space for n blocks each of size elem-size bytes.
Example:
free()
The free() function takes a pointer as an argument and returns the memory block
pointed to by that pointer to the free list within the heap.
realloc ()
Realloc () is a function that can be used to change the size of memory that was
previously allocated using calloc() or malloc().
The function takes two arguments: a pointer to the memory to be resized and the new
size of the memory.
Realloc () returns a pointer to the resized memory block, or NULL if the request fails.
If realloc () was able to make the old block of memory bigger, it returns the same
pointer.
Otherwise, realloc () allocates a new block of memory and copies the old data to it.
Difference between malloc() and calloc()
Malloc Calloc
The name malloc stands for memory allocation. The name calloc stands for contiguous allocation.
malloc () doesn’t initializes the allocated calloc () initializes the allocated memory to
Since no initialization, time efficiency is More expensive because of zero fillings. But
specified as arguments. i.e., size in bytes allocated, sizeno. of bytes in each block
Arrays
An array is a data structure consisting of a collection of (mainly of similar data types) elements (values or variables),
each identified by at least one array index or key.
Linear arrays
Linear arrays are called one dimensional arrays which is referenced by one subscript.
Data_type—the kind of values it can store, for example, int, char, float, double.
Example:
In C, the array index starts from zero. This means that the array marks will contain 10
elements in all.
The first element will be stored in marks [0], second element in marks[1], so on and so
forth. Therefore, the last element, that is the 10th element, will be stored in marks[9].
The address of other data elements can simply be calculated using the base address. The
formula to perform this calculation is, Address of data element
Here, A is the array, k is the index of the element of which we have to calculate the address,
BA is the base address of the array A, and w is the size of one element in memory, for
example, size of int is 4.
Ex: Given an array int marks [] = {99,67,78,56,88,90,34,85}, calculate the address of marks [4] if the
base address = 1000.
The length of an array is given by the number of elements stored in it. The general
formula to calculate the length of an array is:
Where upper_bound is the index of the last element and lower_bound is the index of the first
element in the array.
int age[5]={2,4,34,3,4};
int age[]={2,4,34,3,4};
An array can be initialized by inputting values from the keyboard. In this method, a
while/do–while or a for loop is executed to input the value for each element of the array.
If the array size is decided during run time, then it is called dynamically allocated array.
1-D Array:
Two-D Array:
Ex: int x[3][5]; The figure shows array to array representation, where each of 3 pointers
points to 1-D array consisting of 5 locations
Structures
Structure is a user defined data type that can hold data items of different data types.
The major difference between a structure and an array is that an array can store only
information of same data type.
Syntax:
struct {
member1;
member2;
…..
member n;
}; structure name
Example
struct {
char name[10];
int age;
float salary;
} person;
to assign values to the fields, use. (dot) as the structure member operator. This operator is
used to select a particular member of the structure
Ex:
Person.age = 10;
Person.salary = 35000;
Structure Declaration
Struct structure_name
member1;
member2;
member n;
};
Example:
struct person
char name[10];
int age;
float salary;
};
Syntax:
typedef struct
data_type member 1;
data_type member 2;
………………………
………………………
data_type member n;
} TypeName;
typedef is the keyword used at the beginning of the definition and by using typedef user
defined data type can be obtained.
Example:
typedef struct
char name[10];
int age;
float salary
} person;
person person1, person2; This statement declares the variable person1 and person2 are of
type person.
Unions
Union is a derived data type, like structure, i.e. collection of elements of different data
types which are grouped together.
Union allocates one common storage space for all its members, or memory space is
shared between its members.
Syntax:
Method-1:
union tag_name
Type1 member1;
Type2 member2;
….
};
Method-2:
typedef union
Type1 member1;
Type2 member2;
….
};
Thus, unions are used to save memory. They are useful for applications that involve multiple
members, where values need not be assigned to all the members at any one time.
Basis of
Structure Union
comparison
The separate memory location is allotted to each All members of the 'union'
member of the 'structure'.
Basic share the same memory
location.
{ {
…. ….
}Size
variable1, variable2,
of Structure= sum...;
of size of all the }Size
variable1, variable2,
of Union=size of ...;
the
Size
Keyword 'struct'
data members. 'union'
largest members.
Stores distinct values for all the members. Stores same value for all the
Store Value
members.
Way of Provide single way to view each memory Provide multiple way to view
Self-referential structures are those structures that contain a reference to the data of its
same type.
For example, consider the structure node given below. Here, the structure node will contain
two types of data: a character data and a pointer link. The value of link is either the address
in the memory of an instance of a list or the null pointer.
Consider these statements which create 3 structures and assign values to their respective
fields:
axe
For ex:
If any term is not present, then we assign 0’s in the corresponding coefficient.
Structure:
typedef struct
float coef[max_degree];
int degree;
} polynomial;
Array of Structure:
Instead of using one array for each polynomial, we use one array to store all
polynomials, which saves space
Polynomial Addition:
Suppose a is one polynomial and b is another polynomial then c=a+b, where c is the addition of
polynomial a and b. in order to add 2 polynomials, there are different cases to be verified:
Ex:
a = 25x6+10x5+7x2+9 b = 15x6+5x4+4x3
sum is,
25x6+10x5+7x2+9
15x6+5x4+4x3
c=40 x6+………
a =10x5+7x2+9 b = 5x4+4x3
10x5+7x2+9
5x4+4x3
c=10 x5+………
a =7x2+9 b = 5x4+4x3
sum is,
7x2+9
5x4+4x3
4+………
c=5x
Sparse Matrix
A sparse matrix is a matrix in which most of the elements are zero. By contrast, if most of the
elements are nonzero, then the matrix is considered dense.
Triplet Representation
typedef struct
} term;
term a[max];
In this representation, we consider only non-zero values along with their row and column
index values.
Each non zero value is a triplet of the form <R, C, Value> where R represents the row in
which the value appears, C represents the column in which the value appears and Value
represents the nonzero value itself.
In this representation, the 0th row stores total rows, total columns and total non-zero values
in the matrix.
For example:
To transpose a matrix
we just interchange the rows and columns. This means that each element a[i][j] in the
original matrix becomes b[j][i] in the transpose matrix
A multi-dimensional array can be termed as an array of arrays that stores homogeneous data
in tabular form. Data in multidimensional arrays are stored in row-major order. A three-
dimensional (3D) array is an array of arrays of arrays.
Syntax:
Strings
STACK
Stack is a linear data structure which follows a particular order in which the operations are performed.
Every stack has a variable called TOP associated with it, which is used to store the address of
the topmost element of the stack.
There is another variable called MAX, which is used to store the maximum number of
elements that the stack can hold.
If TOP = NULL, then it indicates that the stack is empty and if TOP = MAX–1, then the
stack is full.
Stack Operations
Push: Element is inserted into the top of stack using push operation.
Pop: Element is deleted from the top of stack using pop operation.
Stack Create:
Display (Traverse):
The array is used to implement stack, but the bound (MAX_STACK_ SIZE) should be
known during compile time.
The size of bound is impossible to alter during compilation hence this can be overcome by
using dynamically allocated array for the elements and then increasing the size of array as
needed.
push ():
pop ():
stackFull ():
Infix Expression:
A – (B / C + (D % E * F) / G) * H
( (
A ( A
- (- A
( (-( A
B (-( AB
/ (-(/ AB
C (-(/ ABC
+ (-(+ ABC/
( (-(+( ABC/
D (-(+( ABC/D
% (-(+(% ABC/D
E (-(+(% ABC/DE
* (-(+(* ABC/DE%
F (-(+(* ABC/DE%F
) (-(+ ABC/DE%F*
/ (-(+/ ABC/DE%F*
G (-(+/ ABC/DE%F*G
) (- ABC/DE%F*G/+
* (-* ABC/DE%F*G/+
H (-* ABC/DE%F*G/+H
) ABC/DE%F*G/+H*-
Problem 2: Convert the following infix expression into postfix expression:
Solution:
( (
( ((
( (((
A ((( A
+ (((+ A
( (((+( A
B (((+( AB
- (((+(- AB
C (((+(- ABC
) (((+ ABC-
* (((+* ABC-
D (((+* ABC-D
) (( ABC-D*+
^ ((^ ABC-D*+
E ((^ ABC-D*+E
) ( ABC-D*+E^
+ (+ ABC-D*+E^
F (+ ABC-D*+E^F
) ABC-D*+E^F+
Evaluation of Postfix Expression
Problem 1: Evaluate the following postfix expression FOR A=1, B=2 and C=3:
ABC+*CBA-+*
Solution: 123+*321-+*
Postfix Expression Symbol Scanned Op2 Op1 Res = Op1 Op Op2 Stack
123+*321-+* 1 1
23+*321-+* 2 1,2
3+*321-+* 3 1,2,3
*321-+* * 5 1 1*5=5 5
321-+* 3 5,3
21-+* 2 5,3,2
1-+* 1 5,3,2,1
+* + 1 3 3+1=4 5,4
* * 4 5 5*4=20 20
25
Problem 2: Evaluate the following postfix expression FOR A=1, B=2 and
C=3:
AB+C-BA+C^-
Solution: 12+3-21+3^-
Postfix Expression Symbol Scanned Op2 Op1 Res = Op1 Op Op2 Stack
12+3-21+3^- 1 1
2+3-21+3^- 2 1,2
+3-21+3^- + 2 1 1+2=3 3
3-21+3^- 3 3,3
-21+3^- - 3 3 3-3=0 0
21+3^- 2 0,2
1+3^- 1 0,2,1
3^- 3 0,3,3
^- ^ 3 3 3^3=27 0,27
- - 27 0 0-27=-27 -27
26
Problem 3: Convert the following infix expression to postfix expression and evaluate the
postfix expression FOR A=6, B=3, C=1, D=2, E=4:
A/B-C+D*E-A*C
we get: 63/1-24*+61*-.
Postfix Expression Symbol Scanned Op2 Op1 Res = Op1 Op Op2 Stack
63/1-24*+61*- 6 6
3/1-24*+61*- 3 6,3
/1-24*+61*- / 3 6 6/3=2 2
1-24*+61*- 1 2,1
-24*+61*- - 1 2 2-1=1 1
24*+61*- 2 1,2
4*+61*- 4 1,2,4
+61*- + 8 1 1+8=9 9
61*- 6 9,6
1*- 1 9,6,1
*- * 1 6 6*1=6 9,6
- - 6 9 9-6=3 3
27
Module 2-Queues & Linked Lists
QUEUES
A queue is an ordered list in which insertions (additions, pushes) and deletions (removals
and pops) take place at different ends”.
The end at which new elements are added is called the rear, and that from which old
elements are deleted is called the front.
The condition FRONT = NULL will indicate that the queue is empty.
Queue Operations
dequeue () − remove (access) an item from the queue from rear end.
isfull () / overflow− Checks if the queue is full.
Queue Create
The maximum number of elements that can be entered into queue can be defined as:
#define MAX 5
int q[MAX];
The variables ‘front’ and ‘rear’ are associated with q and holds the index of 1st element
Example:
Elements 10, 20, 30, 40 and 50 is entered into queue as in
Queue Delete and Underflow
The algorithm to delete an element from the queue
Example:
delete 10, 20, 30, 40 and 50 from the queue.
Hence we need to make the initial condition as front=0 and rear = -1 when front>rear.
Queue Display
If queue is having some items, then it should be displayed one after the other. If there is no
item, then it should display error message.
Circular Queues
Circular Queue is also called ring Buffer.
A circular queue is a linear data structure in which the operations are performed based on
FIFO (First In First Out) principle and the last position is connected back to the first
position to make a circle.
In a normal Queue Data Structure, we can insert elements until queue becomes full. For
example, consider the queue in the Fig. 2.8(a).
Now consider the Fig.2.8 (b), the situation after deleting three elements from the queue.
This situation also says that Queue is full and we cannot insert the new element because
'rear' is still at last position.
This is the major problem in a normal queue data structure. To overcome this problem, we
use a circular queue data structure.
When the array is viewed as a circle, each array position has a next and a previous position.
The position next to position MAX-1 is 0, and the position that precedes 0 is MAX-1, the
next element is put into position 0.
If front =-1 and rear =-1 we cannot distinguish between queue empty and queue full. To
avoid this confusion, we set front=0 and rear =0 in circular queue.
int q[MAX];
Insert and Overflow in Circular Queue
In a circular queue, the new element is always inserted at rear position.
Multiple Stacks
Method in which more than one stack is present in the same array of sufficient size.
In Fig. 2.13(a) an array STACK[n] is used to represent two stacks, Stack A and Stack B.
The value of n is such that the combined size of both the stacks will never exceed n.
While operating on these stacks, it is important to note one thing—Stack A will grow from
left to right, whereas Stack B will grow from right to left at the same time.
Extending this concept to multiple stacks, a stack can also be used to represent n number of
stacks in the same array. That is, if we have a STACK[n], then each stack I will be
allocated an equal amount of space bounded by indices b[i] and e[i]. This is shown in Fig.
2.13(b)
Multiple Queues
Method in which more than one queue or multiple queue is in the same array of sufficient
size.
Figure 2.14(a), an array QUEUE[n] is used to represent two queues, QUEUE A and
QUEUE B.
The value of n is such that the combined size of both the queues will never exceed n.
QUEUE A will grow from left to right, whereas QUEUE B will grow from right to left at
the same time.
Extending the concept to multiple queues, a queue can also be used to represent n number
of queues in the same array.
That is, if we have a QUEUE[n], then each QUEUE I will be allocated an equal amount
of space bounded by indices b[i] and e[i].
Linked List
A linked list or one-way list, is a linear collection of data elements, called nodes, where the linear
order is given by means of pointers. That is, each node is divided into two parts:
The first part contains the information of the element, and
The second part, called the link field or next pointer field, contains the address of the
next node in the list.
Representing Chain In C
The following capabilities are needed to make linked representation
A mechanism for defining a node’s structure, that is, the field it contains. So self- referential
structures can be used
} NODE;
A way to remove nodes that no longer needed. The free function handles this operation.
Linked List Operations
Create
Insert to Front
It works same as create function, by inserting new node to front. Here only one node can be inserted
at a time.
Insert to End
Delete from Front
Linked Stacks
The linked representation of a stack is shown
The push operation is used to insert an element into the stack. The new element is added at
the topmost position of the stack.
the algorithm to push an element into a linked stack.
The pop operation is used to delete the topmost element from a stack.
Linked Queue
The linked representation of queue
The delete operation is used to delete the element that is first inserted into the queue.
Polynomial representation
Consider a polynomial 6x3 + 9x2 + 7x + 1. Every individual term in a polynomial consists of
two parts, a coefficient and a power. Every term of a polynomial can be represented as a
node of the linked list.
Polynomial Addition
Consider an example polynomial To add polynomial, we examine their terms starting at the
nodes pointed by a and b. There are three cases:
Fig. 3.11.
here link field of last node points to the 1 st node in the list. So we call this a circular linked
list.
LINKED LISTS
FIRST
FIRST
FIRST1 temp
FIRST2
List is unsorted
List is sorted
Create a Node
Sparse matrices
In linked representation, we use linked list data structure to represent a sparse matrix.
In this linked list, we use two different nodes namely header node and element node.
Header node consists of three fields and element node consists of five fields.
In this representation, H0, H1..., H5 indicates the header nodes which are used to represent
indexes.
Remaining nodes are used to represent non-zero elements in the matrix, except the very first
node which is used to represent abstract information of the sparse matrix (i.e., It is a
matrix of 5 X 6 with 6 non-zero elements).
In this representation, in each row and column, the last node right field points to its respective
header node
Doubly linked list is a linear collection of data elements, called nodes, where each node N
is divided into three parts:
This list also contains pointer field ‘first’ which points to first node and ‘last’ which
points to last node.
Representation
Using first and RLINK we can traverse in forward direction. Using last and LLINK we
can traverse in backward direction.
Structure declaration of doubly linked list is shown in Fig.3.3.1(b)
Operation
s of Doubly Linked List
Create
Insert to end
Insert to front
Delete from Front
Traverse (Display)
In this type the ‘Next’ of the last node points to the first node in a doubly-linked list. The ‘Prev’ of
the first node points to the last node.
A tree is a very popular non-linear data structure used in a wide range of applications.
Node in a tree data structure stores the actual data of that particular element and link to next
element in hierarchical structure.
Tree Definition
Definition: A tree is a finite set of one or more nodes such that: (i) there is a specially designated
node called the root; (ii) the remaining nodes are partitioned into disjoint sets T1, ..., Tn where
each of these sets is a tree. T1, ..., Tn are called the sub-trees of the root.
Basic Terminology
Root node:
The root node R is the topmost node in the tree. If R = NULL, then it means the tree is empty.
Edge:
In a tree data structure, the connecting link between any two nodes is called as EDGE.
In a tree with 'N' number of nodes there will be a maximum of 'N-1' number of edges.
Parent
In a tree data structure, the node which is a predecessor of any node is called as PARENT NODE.
In simple words, the node which has a branch from it to any other node is called a parent node.
Child:
In a tree data structure, the node which is descendant of any node is called as CHILD Node.
Sub-trees:
In a tree data structure, each child from a node forms a subtree recursively.
Internal Nodes:
In a tree data structure, nodes other than leaf nodes are called as Internal Nodes.
A node that has no children is called the leaf node or the terminal node.
Path:
In a tree data structure, the sequence of Nodes and Edges from one node to another node is
called as PATH
In a tree data structure, the total number of children of a node is called as DEGREE of that Node.
The highest degree of a node among all the nodes in a tree is called as 'Degree of Tree'
Level:
Every node in the tree is assigned a level number in such a way that the root node is at level 1,
children of the root node are at level number 2.
All child nodes have a level number given by parent’s level number + 1.
is the maximum distance between the root node of the tree and the leaf node of the tree.
Depth of the tree:
In a tree, the total number of edges from root node to a leaf node in the longest path is said to be
Depth of the tree.
Ancestor node:
An ancestor of a node is any predecessor node on the path from root to that node.
Descendant node:
A descendant node is any successor node on any path from the node to a leaf node.
In-degree:
Out-degree:
Representation of Tree:
Example:
List Representation:
First note that every node has at most one leftmost child
To obtain the degree-two tree representation of a tree, simply rotate the right-sibling
pointers in a left child-right sibling tree clockwise by 45 degrees.
Binary Trees
Definition: A binary tree is a finite set of nodes which is either empty or consists of a root and two
disjoint binary trees called the left subtree and the right subtree.
The first one has an empty right subtree while the second has an empty left subtree.
If T does not contain a root R, then two trees T1 and T2 are called left and right
subtrees of R.
General tree is a tree in which each node can have many Whereas in binary tree, each node can have at most two
children or nodes. nodes.
The subtree of a general tree does not hold the ordered While the subtree of binary tree holds the ordered property.
property.
In general tree, a node can have at most n While in binary tree, a node can have at most
(number of child nodes) nodes. 2(number of child nodes) nodes.
In general tree, there is no limitation on the degree of a While in binary tree, there is limitation on the degree of
node. a node
In general tree, there is either zero subtree or many While in binary tree, there are mainly two subtrees:
subtrees. Left-subtree and Right-subtree.
Boolean IsEmpty(bt): if (bt == empty binary tree) return TRUE else return FALSE
BinTree MakeBT (bt1, item, bt2): return a binary tree whose left subtree is bt1, whose right subtree is bt2, and
whose root node contains the data item.
BinTree Lchild(bt): if (IsEmpty(bt)) return error else return the left subtree of bt.
Element Data(bt): if (IsEmpty(bt)) return error else return the data in the root node of bt.
BinTree Rchild(bt): if (IsEmpty(bt)) return error else return the right subtree of bt
Skewed Tree:
A skewed tree is a tree, skewed to the left or skews to the right. or it is a tree consisting of only left
sub-tree or only right sub-tree
A tree with only left sub-trees is called Left Skewed Binary Tree.
A tree with only right sub-trees is called Right Skewed Binary Tree.
Complete:
In this type all its levels, except possibly the last level, have the maximum number node 2 i, i ≥ 0
and if all the nodes at the last level appears as far left as possible.
A full binary tree of depth ‘k’ is a binary tree of depth k having 2k – 1 nodes, k ≥ 1
Extended Binary tree:
A binary tree T is said to be a 2-tree or an extended binary tree if each node N has either 0 or 2
children.
The nodes with 2 children are called internal nodes and the nodes with 0 children are called external
nodes.
Sometimes the nodes are distinguished in diagrams by using circles for internal nodes and squares for
external nodes
If every non-leaf node in a binary tree has non empty left and right subtrees, the tree is called a
strictly binary tree.
Expression Tree
An expression containing operands and binary operators can be represented by a binary tree.
Properties of Binary Tree
Lemma 1& 2:
Proof:
Step 1: Induction Base: The root is the only node on level i = 1. Hence, the maximum
number of nodes on level i =1 is 2i-1 = 20 = 1.
Step 3: Induction Step: 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. or 2*2i-2= 2i-1
(2) The maximum number of nodes in a binary tree of depth k is 𝒊=𝟏 = ∑𝒌𝒊=𝟏 𝟐𝒊−𝟏 =𝟐𝒌−𝟏
∑𝒌
Lemma– 3:
For any non-empty binary tree, T, if n0 is the number of terminal nodes and n2 the number of
nodes of degree 2, then n0 = n2 + 1.
Proof:
• Consider the binary tree with each node in the tree should have a maximum of 2 children. A node
may not have any child or it can have single child or it can have 2 children. But a node in a binary
tree can not have more that 2 children.
Observe from the tree that the total no of nodes is equal to the total no. of branches (B) plus 1
n = B+1......................................................................................................................2
B = 1n1 + 2n2...................................................................................................................................................................5
Substitute 5 in 2 we get
n = 1n1 + 2n2 + 1.....................................................................................................6
n0 + n1 + n2 = 1n1 + 2n2 + 1
Hence it is proved that for any nonempty binary tree, T, if no is the number of terminal nodes and n2
the number of nodes of degree 2, then n0 = n2 + 1.
Array representation
If T is a binary tree, then it can be maintained in memory using sequential representation as follows:
• If a node n occupies TREE[k], then its left child is stored in TREE[2*k] and right child is
stored in TREE[2*k+1]
Each node will have three fields LCHILD, DATA and RCHILD as in Fig.3.12.2.
Ex:
1. Preorder traversal
2. Postorder traversal
3. Inorder traversal
Iterative Inorder traversal (or) Inorder Tree Traversal without Recursion.
Here we can use a stack to perform inorder traversal of a Binary Tree. Below is the algorithm for
traversing a binary tree using stack.
3. Push the current node to S and set current = current->left until current is NULL
o Go to step 3.
Level Order Traversal technique is defined as a method to traverse a Tree such that all nodes
present in the same level are traversed completely before traversing the next level.
In level order traversal nodes of tree are traversed level-wise from left to right.
Queue data structure is used to store nodes level wise so that each node’s children are visited.
Threaded Binary Trees
A threaded binary tree is a type of binary tree data structure where the empty left and right child
pointers in a binary tree are replaced with threads that link nodes directly to their in-order predecessor or
successor, thereby providing a way to traverse the tree without using recursion or a stack.
To construct the threads, use the following rules(Assume that ptr represents a node):
If ptr→leftChild is null, then replace the null link with a pointer to the inorder predecessor of
ptr.
If ptr →rightChild is null, replace the null link with a pointer to the inorder successor of ptr.
When trees are represented in memory, it should be able to distinguish between threads and pointers. This
can be done by adding two additional fields to node structure, ie., leftThread and rightThread
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 left_thread = TRUE
MODULE 04: Trees and Graphs
Binary search trees (BST), sometimes called ordered or sorted binary trees, are a particular type
of containers: data structures that store "items"
A binary search tree is a binary tree; either it is empty or each node in the tree contains an
identifier and:
all identifiers in the left subtree of T are less (numerically or alphabetically) than the identifier
in the root node T;
all identifiers in the right subtree of T are greater than the identifier in the root node T;
the left and right subtrees of T are also binary search trees.
Create Function
Example:
Create a binary search tree using the following data elements: 45, 39, 56, 12, 34, 78, 32, 10.
Insert Function
The insert function is used to add a new node with a given value at the correct position in the
binary search tree.
Search Function:
The search function is used to find whether a given value is present in the tree or not.
Looser Trees
In a tournament tree, when the internal nodes are used to represent the loser of the match between two,
then the tree obtained is referred to as the loser tree.
When the loser is the smaller value then the loser tree is referred to as the minimum loser tree, and when
the loser is the larger value, then the loser tree is referred to as the maximum loser tree.
Forest
Definition: A forest is a set of n disjoint trees.
When we remove the root of a tree we obtain a forest.
For example, removing the root of any binary tree produces a forest of two trees.
Three-tree forest
Definition: If T1, . . ., Tn is a forest of trees, then the binary tree corresponding to this forest,
denoted by B (T1, . . . , Tn),
(1) is empty, if n = 0
(2) has root equal to root (T1); has left subtree equal to B(T11,T12. . . T1m), where T11, . . .
,T1m are the subtrees of root (T1); and has right subtree B(T2, . . . ,Tn)
Binary tree representation of forest
Preorder Traversal:
The preorder traversal of T is equivalent to visiting the nodes of Fin tree preorder. We define
this as:
Inorder Traversal:
Inorder traversal of T is equivalent to visiting the nodes of F in tree inorder, which is defined
as:
Postorder Traversal:
There is no natural analog for the postorder traversal of the corresponding binary tree of a
forest. Nevertheless, we can define the postorder traversal of a forest, F, as:
4.2.1 Introduction
The use of trees in the representation of sets. assume that the elements of the sets are the
numbers 0, 1, 2,. . .n-1. In practice, these numbers might be indices into a symbol table that
stores the actual names of the elements.
For example, if we have 10 elements numbered 0 through 9, we may partition them into three
disjoint sets, 51 = {0, 6, 7, 8), S2 = {1, 4, 9}, and S3 = {2, 3, 5}.
to obtain the union of S1 and S2Since we have linked the nodes from children to parent, we
simply make one of the trees a subtree of the other.
To implement the set union operation, we simply set the parent field of one of the roots to the
other root. We can accomplish this easily if, with each set name, we keep a pointer to the root
of the tree representing that set.
rather than using the set name S1 we refer to this set as 0. The transition to set names is easy.
We assume that a table, name [ ], holds the set names. If i is an element in a tree with root 7,
and j has a pointer to entry k in the set name table, then the set name is just name[k].
Definition: Weighting rule for union(i, j). If the number of nodes in tree i is less than the
number in tree j then make j the parent of i; otherwise make i the parent of j.
Fig. Union function using weighting rule
Definition [collapsing rule] : If j is a node on the path from i to its root and parent[i] !=
root(i), then set parent [j] to root(i).
if n = 0 or n = 1, there is only one binary tree. If n = 2, then there are two distinct trees and if
n = 3.
Suppose we have the preorder sequence: ABCDEFGHI and the inorder sequence:
BCAEDGHFI of the binary tree. To construct the binary tree from these sequences, we
look at the first letter in the preorder sequence, A. This letter must be the root of the tree
by definition of the preorder traversal (VLR.}. We also know by definition of the inorder
traversal {LVR} that all nodes preceding A in the inorder sequence (B Q are in the left
subtree, while the remaining nodes {ED GHFI) are in the right subtree. Figure 5.49(a) is
our first approximation to the correct tree. Moving right in the preorder sequence, we find
B as the next root. Since no node precedes B in the inorder sequence, B has an empty left
subtree, which means that C is in its right subtree. Figure 5.49(b) is the next
approximation. Continuing in this way, we arrive at the binary tree of Figure 5.49(c). By
formalizing this argument (see the exercises for this section), we can verify that every
binary tree has a unique pair of preorder inorder sequences.
If the nodes of the tree are numbered such that its preorder permutation is 1, 2, • • •
,n, then from our earlier discussion it follows that distinct binary trees define
distinct inorder permutations.
Thus, the number of distinct binary trees is equal to the number of distinct inorder
permutations obtainable from binary trees having the preorder permutation, 1,2, • •
•
n. Using the concept of an inorder permutation, we can show that the number of dis
tinct permutations obtainable by passing the numbers 1 to n through a stack and
deleting in all possible ways is equal to the number of distinct binary trees with n
nodes (see the exercises). If we start with the numbers 1, 2, 3, then the possible
permutations obtain able by a stack are: (1, 2, 3) (1, 3, 2) (2, 1, 3) (2, 3, 1) (3, 2, 1)
Obtaining (3, 1, 2) is impossible.
GRAPHS
Definitions
A graph is an abstract data structure that is used to implement the mathematical concept
of graphs. It is basically a collection of vertices (also called nodes) and edges that
connect these vertices.
V(G) and E(G) will represent the sets of vertices and edges of graph G. We will also
write G = (V, E) to represent a graph.
In an undirected graph each edge is not represented by a directed pair. Thus, the pairs
(v1, v2) and (v2, v1) represent the same edge.
In a directed graph each edge is represented by a directed pair (v1, v2). v1 is the tail and
v2 the head of the edge. Therefore, and represent two different edges.
Complete graph:
If (v1, v2) is an edge in E(G), then we shall say the vertices v1 and v2 are adjacent and
that the edge (v1, v2) is incident on vertices v1 and v2.
The vertices adjacent to vertex 2 in G2 are 4, 5 and 1. The edges incident on vertex 3 in
G2 are (1,3), (3,6) and (3,7).
A subgraph:
A subgraph of G is a graph G' such that V(G')⊆ V(G) and E(G') ⊆ E(G)
Path:
a path from vertex vp to vertex vq in graph G is a sequence of vertices vp, vi1, vi2, ...,
vin, vq such that (vp, vi1), (vi1, vi2), ..., (vin, vq) are edges in E(G).
Length:
Simple Path:
A simple path is a path in which all vertices except possibly the first and last are
distinct.
A path such as (1,2) (2,4) (4,3) we write as 1,2,4,3. Paths 1,2,4,3 and 1,2,4,2 are both of
length 3 in G1. The first is a simple path while the second is not.
Cycle:
A cycle is a simple path in which the first and last vertices are the same.
Connected graph:
An undirected graph G is said to be connected if for every pair of distinct vertices u and v in
V(G) there is a path from u to v in G.
Strongly connected:
A directed graph G is said to be strongly connected if for every pair of distinct vertices
vi, vj in V(G) there is a directed path from vi to vj and also from vj to vi. The graph G3
is not strongly connected as there is no path from v3 to v2.
Degree:
ADT Graph
Graph representations
Adjacency Matrix:
Let G = (V, E) be a graph with n vertices, n>=1. The adjacency matrix of G is a 2- dimensional
nXn array, say A, with the property that A (i, j) = 1 if the edge (vi, vj) (for a directed graph) is in
E(G). A (i, j) = 0 if there is no such edge in G.
Adjacency Lists:
In this representation the n rows of the adjacency matrix are represented as n linked lists.
The nodes in list i represent the vertices that are adjacent from vertex i.
Adjacency Multilists:
For each edge there will be exactly one node, but this node will be in two list (i.e., the
adjacency list for each of the two nodes to which it is incident).
A new field is necessary to determine if the edge is determined and mark it as examined.
These weights may represent the distance from one vertex to another or the cost of
going from one vertex to an adjacent vertex.
2. Select an unvisited vertex w from v’s adjacency and carry a depth first search on w.
4. When we reach a vertex u that has no unvisited vertices on adjacency list, remove a vertex from the stack
and continue processing its adjacency list. Previously visited vertices are discarded and unvisited vertices
are placed on stack
4. When all the vertices in the adjacency list is visited, we remove a vertex from the queue and
proceed by examining each of the vertices in its adjacency list.
5. Visited vertices are ignored and unvisited vertices are placed on the queue
Hashing
Hashing refers to the process of generating a fixed-size output from an input of variable size using the
mathematical formulas known as hash functions.
Hashing enables us to perform the dictionary operations such as search, insert and deleting.
Hash Function
A hash function should hash address such that keys are distributed as evenly as possible
among the various cells of the hash table.
Hash Table
Hash table is a data structure used for storing and retrieving data very quickly.
Insertion, Deletion or Retrieval operation takes place with help of hash value.
Hence every entry in the hash table is associated with some key.
Using the hash key the required piece of data can be searched in the hash table by few or more key
comparisons.
Types of Hash Functions
Division Method:
h(x) = x mod M
Generally, it is best to choose M to be a prime number because making M a prime number increases
the likelihood that the keys are mapped with a uniformity in the output range of values.
Mid-Square Method:
Here, the key K is squared. A number ‘l’ in the middle of K2 is selected by removing the digits from
both ends.
Example: Let key=2345, Its square is K2 =574525 H (2345) =45=>by discarding 57 and 25
Folding Method:
Divide the key value into a number of parts. That is, divide k into parts k1, k2, ..., kn, where each part
has the same number of digits except the last part which may have lesser digits than the other parts.
Add the individual parts. That is, obtain the sum of k1 + k2 + ... + kn. The hash value is produced by
ignoring the last carry, if any.
When two or more keys map to the same memory location, a collision occurs.
A method used to solve the problem of collision is called collision resolution technique.
Suppose new record R with key K is to be added to the memory table T, but that memory with H(k) =
h is already filled, one way of avoiding collision is to assign R to 1st available location following
T[h].
When inserting a new pair whose key is k, we search the hash table in the order
Example: Consider a hash table of size 10. Using linear probing, insert the keys 72, 27, 36, 24, 63,
81, 92, and 101 into the table.
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
H(72) = 72 mod 10 = 2
0 1 2 3 4 5 6 7 8 9
-1 -1 72 -1 -1 -1 -1 -1 -1 -1
H(27) = 27 mod 10 = 7
0 1 2 3 4 5 6 7 8 9
-1 -1 72 -1 -1 -1 -1 27 -1 -1
H(36) = 36 mod 10 = 6
0 1 2 3 4 5 6 7 8 9
-1 -1 72 -1 -1 -1 36 27 -1 -1
H(24) = 24 mod 10 = 4
0 1 2 3 4 5 6 7 8 9
-1 -1 72 -1 24 -1 36 27 -1 -1
H(63) = 63 mod 10 =3
0 1 2 3 4 5 6 7 8 9
-1 -1 72 63 24 -1 36 27 -1 -1
H(81) = 81 mod 10 =1
0 1 2 3 4 5 6 7 8 9
-1 81 72 63 24 -1 36 27 -1 -1
H(92) = 92 mod 10 =2
Collision occurred since 2 is already filled. So go to next position – 3, which is also already filled, go to next
position – 4 which is also already filled. So go to 5 – which is not filled – so insert the key 92 in position 5.
0 1 2 3 4 5 6 7 8 9
-1 81 72 63 24 92 36 27 -1 -1
H(101) = 101 mod 10 = 1
Collision occurred since 1 is already filled. Do linear probing and the next position free is 8, so insert key
101 in position 8.
0 1 2 3 4 5 6 7 8 9
-1 81 72 63 24 92 36 27 101 -1
81 1 1 1
72 2 2 1
63 3 3 1
24 4 4 1
92 2 5 4
36 6 6 1
27 7 7 1
101 1 8 8
Quadratic Probing
Suppose a record R with key k has the hash address H(k)=h then instead of searching
the locations with h, h+1, h+2………. we linearly search locations with h, h+1, h+4,
h+9, ......... h+i2
In double hashing, we use two hash functions rather than a single function.
Double hashing uses the idea of applying a second hash function to the key when a
collision occurs.
Hash2(key) = M - (key % M)
where M is a prime number that is smaller than the size of the table. But any independent
hash function may also be used.
Example: 37,90,45,22,17,49,55
H1(key)=key%10
H2(key)=7-(key%7)
17
22
45
55
37
49
Rehashing
When the hash table becomes nearly full, the number of collisions increases. In such cases,
a better option is to create a new hash table with size double of the original hash table.
All the entries in the original hash table will then have to be moved to the new hash table.
This is done by taking each entry, computing its new hash value, and then inserting it in the new
hash table.
Example: Consider the hash table of size 5 given below. The hash function used is h(x) = x % 5.
Rehash the entries into to a new hash table.
Chaining
If more than one key has same hash value, then all the keys will be inserted at the end of the list
(insert rear) one by one and thus collision is avoided.
Example: Construct a hash table of size and store the following words: like, a, tree, you, first, place,
to
H(like) = 12 + 9 + 11 + 5 = 37 % 5 = 2
H(a) = 1 %5 =1
H(tree) = 20 + 18 + 5 + 5 = 48 % 5 = 3
1 H(you) = 25 + 15 + 21 = 61 % 5 = 1
H(first) = 6 + 9 + 18 + 19 + 20 = 72 % 5 = 2
H(place) = 16 + 12 + 1 + 3 + 5 = 37 % 5 =2
H(to) = 20 + 15 = 35 % 5 =
Types of Hashing
Static Hashing:
Is a hashing technique in which the table(bucket) size remains the same (Fixed during compilation
time) is called static hashing.
As the size is fixed, this type of hashing consists handling overflow of elements (Collision) efficiently.
Dynamic Hashing:
Dynamically increases the size of the hash table as collision occurs. There are two types:
No overflow buckets.
Directory size d= 2t where t is the number of bits used to identify all h(k).
Splitting occurs in turn, in a round robin fashion.one by one from the first bucket to the last bucket.
When all the pages at one level (the current hash function) have been split, a new level is applied.
When 4 inserted overflow occurred. So, we split the bucket and increment pointer.
So we split bucket 0 and rehashed all keys in it. Placed 3 to new bucket as h1 (3 mod 6 = 3 ) and (12
mod 6 = 0 ). Then 11 and 2 are inserted. And now overflow. s is pointing to bucket 1, hence split
bucket 1 by re- hashing it.
Priority Queues
Priority queues are data structures that store elements along with their associated priorities.
The elements in a priority queue are typically retrieved in order of their priority
One way to maintain a priority queue in memory is by means of a one-way list, as follows:
Each node in the list will contain three items of information: an information field INFO, a priority
number PRN and a link number LINK.
A node X precedes a node Y in the list
When both have the same priority but X was added to the list before Y.
Another way to maintain a priority queue in memory is to use a separate queue for each level of
priority (or for each priority number).
Each such queue must have its own pair of pointers, FRONT and REA R.
FRONT[K] and REAR[K] contain, respectively, the front and rear elements of row K of
QUEUE, the row that maintains the queue of elements with priority number K.
In a single-ended priority queue, elements are inserted with their priorities, and retrieval or deletion
is performed on the element with the highest (or lowest) priority.
This type of priority queue is often implemented using a heap data structure, such as a binary heap or a
Fibonacci heap.
Operation:
Also known as a dequeue (pronounced "deck"), a double-ended priority queue allows elements to be
inserted and removed from both ends, considering both minimum and maximum priorities.
Double-ended priority queues can be implemented using various data structures, such as doubly-linked
lists, skip lists, or binary heaps
Operations:
Leftist Trees
A leftist tree, also known as a leftist heap, is a type of binary heap data structure used
for implementing priority queues.
Like other heap data structures, it is a complete binary tree, meaning that all levels are fully filled
except possibly the last level, which is filled from left to right.
Let X be a node in an extended binary tree. Let left-child (x) and right-child (x), respectively, denote
the left and right children of the internal node x.
Define shortest (x) to be the length of a shortest path from x to an external node. It is easy to see that
shortest (x) satisfies the following recurrence:
Height-Biased Leftist Trees.
Operations:
deleteMin() or extractMin() can be done by removing root and calling merge() for left and right
subtrees.
insert() can be done be create a leftist tree with single key (key to be inserted) and calling merge() for
given tree and tree with single node.
2. Push the smaller key into an empty stack, and move to the right child of smaller key.
3. Recursively compare two keys and go on pushing the smaller key onto the stack and move to its right
child.
5. Take the last node processed and make it the right child of the node at top of the stack, and convert it
to leftist heap if the properties of leftist heap are violated.
6. Recursively go on popping the elements from the stack and making them the right child of new stack
top.
Example:
Weight-Biased Leftist Trees.
An Optimal Binary Search Tree (OBST), also known as a Weighted Binary Search Tree, is a
binary search tree that minimizes the expected search cost.
In a binary search tree, the search cost is the number of comparisons required to search for a
given key.
In an OBST, each node is assigned a weight that represents the probability of the key being
searched for.
The expected search cost of a node is the sum of the product of its depth and weight, and the
expected search cost of its children.
10 12
\ /
12 10
I II
Among all possible BSTs, cost of the fifth BST is minimum. Cost of the fifth BST is 1*50 + 2*34
+ 3*8 = 142