SCSA1205
SCSA1205
1
Unit-I
I. ALGORITHM
An algorithm is a well-defined computational procedure having well defined steps for solving
a particular problem. Algorithm is finite set of logic or instructions, written in order for
accomplishing the certain predefined task.
Each algorithm must have:
• Specification: Description of the computational procedure.
• Pre-conditions: The condition(s) on input.
• Body of the Algorithm: A sequence of clear and unambiguous instructions.
• Post-conditions: The condition(s) on output.
Characteristics of an Algorithm
An algorithm must follow the mentioned below characteristics:
• Input: An algorithm must have 0 or well- d e f i n e d inputs.
• Output: An algorithm must have 1 or well-defined outputs, and should match with the
desired output.
• Feasibility: An algorithm must be terminated after the finite number of steps.
• Independent: An algorithm must have step-by-step directions which is independent of
any programming code.
• Unambiguous: An algorithm must be unambiguous and clear. Each of their steps and
input/outputs must be clear and lead to only one meaning.
The performance of algorithm is measured on the basis of following properties:
• Time complexity: It is a way of representing the amount of time needed by a program to
run to the completion.
• Space complexity: It is the amount of memory space required byan algorithm, during a
course of its execution. Space complexity is required in situations when limited memory is
available and for the multi user system.
2
2.INTRODUCTION TO DATA STRUCTURES
2.1 Data
In the modern context, data stands for both singular and plural. Data means a value or set of
values. Data can be defined as an elementaryvalue or the collection of values, for example,
student’s name and its idare the data about the student.
2.2 Structure
A building is a structure. A bridge is structure. In general, a structure is made up of
components. It has a form or shape. It is made up of parts.A structure is an arrangement of and
relations between parts or elements.
2.3 Data Structures
A data structure is an arrangement of data elements. Data Structure can be defined as the group
of data elements which provides an efficient way of storing and organizing data in the computer
so that it can be used efficiently. Some examples of Data Structures are arrays, Linked List, Stack,
Queue, etc. Data Structures are widely used in almost every aspectof Computer Science i.e.
Operating System, Compiler Design, Artificial Intelligence, Graphics and many more.
2.3.1 Needs
As applications are getting complex and amount of data is increasing day by day, the following
issues might be araised:
Processor speed: To handle very large amount of data, high speed processing is required, but as the
data is growing day by day tothe billions of files per entity, processor may fail to deal with that
much amount of data.
Data Search: Consider an inventory size of 106 items in a store;if our application needs to
search for a particular item, it needs to traverse 106 items every time, results in slowing down the
search process.
Multiple requests: If thousands of users are searching the data simultaneously in a web server, it
fails to process the requests.
In order to solve the above problems, data structures are used. Data is organized to form
a data structure in such a way that all items arenot required to be searched and required data
can be searched instantly.
3
the management of huge amounts of data, such as large integrated collection of databases.
3. Some programming languages emphasize data structures, rather than algorithms, as the key
organizing factor in software design.
4
Fig. 1 Classification of Data Structure
5
languages. It is named as stack because it behaveslike a real-world stack, for example, piles
of plates or deck of cards etc.
Queue: Queue is a linear list in which elements can be inserted only atone end called rear
and deleted only at the other end called front. It isa First-In-First-Out Linear data structure.
It is an abstract data structure, similar to stack. Queue is opened atboth end therefore it
follows First-In-First-Out (FIFO) methodology for storing the data items.
Graphs: Graphs can be defined as the pictorial representation of the set of elements (represented
by vertices) connected by the links known as edges. A graph is different from tree in the sense
that a graph can have cycle while the tree cannot have the one.
6
Operations applied on non-linear data structures
The following list of operations applied on non-linear data structures.
1. Add elements
2. Delete elements
• The data is generally stored in key sequence in a list which has a head structure consisting of
count, pointers and address of compare function needed to compare the data in the list is
shown in fig.3.
7
• The data node contains the pointer to a data structure and a self-referential pointer which
points to the next node in the list.
void *DataPtr;
} Node;
typedef struct{
int count;
Node *pos;
Node *head;
Node *rear;
A list contains elements of the same type arranged in sequential order and following
operations can be performed on the list.
• remove() – Remove the first occurrence of any element from anon-empty list.
• removeAt() – Remove the element at a specified location from anon-empty list.
• replace() – Replace an element at any position by anotherelement.
• size() – Return the number of elements in the list.
• isEmpty() – Return true if the list is empty, otherwise returnfalse.
• isFull() – Return true if the list is full, otherwise return false.
The List ADT Functions is shown in Fig.4.
8
Fig. 4 List ADT Functions
9
//Stack ADT Type Definitions
typedefstruct node{
void *DataPtr;
} StackNode;
typedefstruct{
int count;
StackNode *top;
} STACK;
All operations take place at a single end that is top of the stackand following
operations can be performed:
• push() – Insert an element at one end of the stack called top.
• pop() – Remove and return the element at the top of the stack,if it is not empty.
• peek() – Return the element at the top of the stack withoutremoving it, if the stack is not
empty.
• size() – Return the number of elements in the stack.
• isEmpty() – Return true if the stack is empty, otherwise returnfalse.
• isFull() – Return true if the stack is full, otherwise return false.
4.3 Queue ADT
✱ The queue Abstract Data Type (ADT) follows the basic design of the stack abstract data
type is shown in fig.6.
✱ A Queue contains elements of the same type arranged in sequential order. Operations take place at
both ends, insertion is done at theend and deletion is done at the front. Following operations can
be performed.
• enqueue() – Insert an element at the end of the queue.
• dequeue() – Remove and return the first element of the queue,if the queue is not empty.
• peek() – Return the element of the queue without removing it,if the queue is not empty.
• size() – Return the number of elements in the queue.
• isEmpty() – Return true if the queue is empty, otherwise returnfalse.
• isFull() – Return true if the queue is full, otherwise return false.
10
//Queue ADT Type Definitions
typedefstructnode {
void*DataPtr;
structnode *next;
} QueueNode;
typedefstruct {
QueueNode *front;
QueueNode *rear;
intcount;
Fig
} QUEUE; 6. Queue ADT
6.ARRAYS
The number of data items chunked together into a unit is known as data structure. When the
data structure consists simply a sequence of data items, the data structure of this simple variety
is referred as an array.
Definition: Array is a collection of homogenous (same data type) dataelements that are stored
in contiguous memory locations.
Array Syntax
Syntax to declare an array:
✱ dataType [ ] arrayName;
arrayName= new dataType[n]; //keyword new performs dynamicmemory location
(or)
✱ dataType [ ] arrayName = new dataType[n];
Example:
int [ ] x; x=new int [10];(or)
int [] x=new int [10];
11
Array Initialization
The values of an array can be initialized as follows,
Example 1:
int [] j=new int [1]; j[0] =10;(or)int [] j= {25};
Example 2:
int [] myarray= {5, 10};
(iii) The name of array represents the starting address of the elements.
(iv) When data objects are stored in array, individual objects areselected by an index.
(v) By default an array index starts from 0 and ends with (n-1). Indexis also referred as
subscripts.
(vi) The size of the array is mentioned at the time of declaring array.
(vii) While declaring 2D array, number of columns should be specifiedwhereas for
number of rows there is no such rule.
(viii) Size of array can’t be changed at run time.
5.2Array Types
1.One-Dimensional Array or Linear arrays
12
2. Multi-Dimensional Array
3.Two dimensional (2D) Arrays or Matrix Arrays
6.STORAGE REPRESENTATION
13
6.1 Row Major Order
The table 1 shows the linear arrangement of data in row major order.
Example
• Rows :3
• Columns :4
Data (A):
1 2 3 4
5 6 7 8
9 10 11 12
Row 1 2 3
(1,1 (1,2 (1,3 (1,4 (2,1 (2,2 (2,3 (2,4 (3,1 (3,2 (3,3 (3,4
Index
) ) ) ) ) ) ) ) ) ) ) )
Memor
100 102 104 106 108 110 112 114 116 118 120 122
y
Data 1 2 3 4 5 6 7 8 9 10 11 12
14
N : Number of columns in the Array
Example
N=4
j=3
k=2
= 118
The table 2 shows the linear arrangement of data in column major order.
• Rows : 3
• Columns :4
Data (A):
1 2 3 4
5 6 7 8
9 10 11 12
15
Linear Arrangement of Array A
Colum
1 2 3 4
n
(1,1 (2,1 (3,1 (1,2 (2,2 (3,2 (1,3 (2,3 (3,3 (1,4 (2,4 (3,4
Index
) ) ) ) ) ) ) ) ) ) ) )
Memor
100 102 104 106 108 110 112 114 116 118 120 122
y
Data 1 5 9 2 6 10 3 7 11 4 8 12
Example
Base (A) = 100
w = 2 Bytes (integer type)
M=3
j=3
k=2
16
Location ( A [3, 2] ) = 100 + 2 [ (3 * (2-1) + (3-1) ]
= 110
Examples:
Input : arr[] = {1, 2, 3} Output : arr[] = {3, 2, 1}
Input : arr[] = {4, 5, 1, 2} Output : arr[] = {2, 1, 5, 4}
Algorithm
1) Initialize start and end indexes as start = 0, end = n-1.
2) In a loop, swap arr[start] with arr[end] and change start and end as follows :
start = start +1, end = end – 1
8.Array Counting
1. Create a function arraycounting(array, size)
4. for j = 0 to size
17
Example A={4,2,2,8,3,3,1}
1. Find out the maximum element (let it be max) from the given array.
2. Initialize an array of length max+1 with all elements 0. This arrayis used for storing
the count of the elements in the array.
3. Store the count of each element at their respective index in count array. For example: If
the count of element “4” occurs 2 times then2 is stored in the 4th position in the
count array. If element “5” isnot present in the array, then 0 is stored in 5th
✱ Traverse array elements from second and compare every elementwith current max
✱ Find the largest element in the array and assign it as max
Example: A={56,78,34,23,70}
18
Step 2: Repeat step 3 until n
Step 3: 56>0 yes, Assign max=56
78>56, yes Assign max=78
34>78, No
23>78, No
70>78, No
Step 4: print Max Output:78
9. RECURSION
Recursion is a programming technique using function or algorithm that calls itself one or more
times until a specified condition is met at which time the rest of each repetition is processed
from the last one calledto the first.
19
(c) Combine the base case and the general cases into an algorithm.
(d) Each recursive call must reduce the size of the problem and moveit toward
the base case.
(e) The base case, when reached, must terminate without a call to therecursive
algorithm; that is, it must execute a return.
9.2 Broad Categories of Recursion
Recursion is a technique that is useful for defining relationships, andfor designing algorithms
that implement those relationships. It is a natural way to express many algorithms in an optimized
way. Recursive function is defined in terms of itself.
✱ Linear Recursion
✱ Binary Recursion
Linear Recursion:
Linear recursion is by far the most common form of recursion. In this style of recursion, the
function calls itself repeatedly until it hits the termination condition (Base condition).
Binary Recursion
Binary recursion is another popular and powerful method. This formof recursion has the
potential for calling itself twice instead of once asbefore. This is pretty useful in scenarios
such as binary tree traversal,generating a Fibonacci sequence, etc.
Tail Recursion
A function call is said to be tail recursive if there is nothing to doafter the function returns
except return its value. Since the current recursive instance is done executing at that point,
saving its stack frameis a waste
For example the following C function print () is tail recursive.
20
10. FIBONACCI SERIES
Fibonacci Series generates subsequent number by adding two previous numbers. Fibonacci
series starts from two numbers F0 & F1. The initial values of F0 & F1 can be
✱ 0 and 1
✱ 1 and 1 respectively.
F8 = 0 1 1 2 3 5 8 13
Fibonacci RecursiveAlgorithm
11.FACTORIAL
The factorial of a positive number is the product of the integral values from 1 to the number:
Factorial of the given number can be calculated as
Algorithm
RecursiveFactorial (n)if (N equals 0)
Return 1
else
Return (n*recursiveFactorial (n-1))
end if
21
end recursiveFactorial
Fig.6 shows the steps for calculating the factorial using Recursion for n=3.
Towers
Disks
Smallest
Largest
22
✱ Only one disk can be moved among the towers at any given time.
Step: 0
Step: 2
23
Step: 6
24
Done!
25
SCHOOL OF COMPUTING
26
UNIT 2
LINKED LIST
Array Vs Linked List – Singly linked list - Representation of a linked list in memory -
Operations on a singly linked list - Merging two singly linked lists into one list - Reversing a
singly linked list – Polynomial Manipulation using List - Advantages and disadvantages of
singly linked list - Circular linked list - Doubly linked list - Circular Doubly Linked List.
Array supports Random Access, which Linked List supports Sequential Access, which
means elements can be accessed directly means to access any element/node in a linked list,
using their index. we have to sequentially traverse the complete linked
list, up to that element.
In an array, elements are stored In a linked list, new elements can be stored
in contiguous memory location or anywhere in the memory. Address of the memory
consecutive manner in the memory. location allocated to the new element is stored in the
previous node of linked list, hence forming a link
between the two nodes/elements.
In array, Insertion and Deletion operation In case of linked list, a new element is stored at the
takes more time, as the memory locations first free and available memory location, with only
are consecutive and fixed. a single overhead step of storing the address of
memory location in the previous node of linked
list.Insertion and Deletion operations are fast in
linked list.
27
Memory is allocated as soon as the array is Memory is allocated at runtime, as and when a new
declared, at compile time. It's also known node is added. It's also known as Dynamic Memory
as Static Memory Allocation. Allocation.
In array, each element is independent and In case of a linked list, each node/element points to
can be accessed using it's index value. the next, previous, or maybe both nodes.
Array can be single dimensional, two Linked list can be Linear(Singly) linked
dimensional or multidimensional. list, Doubly linked list or Circular linked list linked
list.
Size of the array must be specified at time Size of a Linked list is variable. It grows at runtime,
of array declaration. as more nodes are added to it.
Array gets memory allocated in Whereas, linked list gets memory allocated
the Stack section. in Heap section.
• The first node is the head node and it points to next node in the sequence.
• The last node’s reference is null indicating the end of the list is shown in Fig.2.1
28
• Every node has two pointers, one for pointing to next node and the other for pointing to the
previous node.
• The next pointer of the last node and the previous pointer of the first node (head) are null is shown
in Fig 2.2
• Circular Linked List is very similar to a singly linked list except that, here the last node points to
the first node making it a circular list as shown in fig 2.3
29
A linked list is represented by a pointer to the first node of the linked list. The first node is called
the head. If the linked list is empty, then the value of the head is NULL. In C, we can represent a
node using structures.
Step 4 - If it is Not Empty then, set newNode→next = head and head = newNode.
30
Algorithm
Addatbeg()
Begin
Newnode->data=K
Newnode->next=NULL
If(Head==NULL)
Head=Newnode
Else
Newnode->next=Head
Head=Newnode
Endif
End
The fig.2.5 shows how a node is added at the beginning of the linked list.
Step 1 - Create a newNode with given value and newNode → next as NULL.
31
Step 2 - Check whether list is Empty (head == NULL).
Step 4 - If it is Not Empty then, define a node pointer temp and initialize with head.
Step 5 - Keep moving the temp to its next node until it reaches to the last node in the list
(until temp → next is equal to NULL).
Algorithm
Addatend()
Begin
Newnode->data=K
Newnode->next=NULL
If(Head==NULL)
Head=Newnode
Else
Temp=Head
While(temp->next !=NULL)
temp=temp->next
endwhile
temp->next=Newnode
Endif
end
The Fig 2.6 shows how the node is added at the end of the list.
32
Fig 2.6 Node added at the end of the list
Step 3 - If it is Empty then, set newNode → next = NULL and head = newNode.
Step 4 - If it is Not Empty then, define a node pointer temp and initialize with head.
Step 5 - Keep moving the temp to its next node until it reaches to the node after which we
want to insert the newNode (until temp1 → data is equal to location, here location is the
node value after which we want to insert the newNode).
Step 6 - Every time check whether temp is reached to last node or not. If it is reached to last
node then display 'Given node is not found in the list!!! Insertion not possible!!!' and
terminate the function. Otherwise move the temp to next node.
Step 7 - Finally, Set 'newNode → next = temp → next' and 'temp → next = newNode'
33
The operation ‘Insert’ inserts the given element x in the kth position. A temporary pointer Temp is
created and made to point to Head. Now the Temp pointer is moved to the k – 1 th node. A new node
with value x is created and the link of the new node is made to point to the position where the link
of temp is pointing. Then the link of temp is made to point to the new node. Thus the given element
is inserted in the position k is shown in fig.2.7.
Algorithm
Function insertin_mid()
Begin
Write "Enter the position:"
Read pos;
If head==NULL AND pos=1
then
Insert the node at the beginning
End if
If head->next==NULL AND pos=2
then
insert the node
End if
Else if pos>=2 AND pos<=ct
34
then
prev=head
for I = 2 to pos - 1 step +1
do
prev=prev->link
END FOR
next=prev->link
temp=new node
Write”Enter the data:"
Read temp->data
temp->link=next
prev->link=temp
ct=ct+1
else
Write "Enter a valid position & try again"
End if
End
Deletion
In a single linked list, the deletion operation can be performed in three ways. They are as follows...
We can use the following steps to delete a node from beginning of the single linked list...
Step 2 - If it is Empty then, display 'List is Empty!!! Deletion is not possible' and
terminate the function.
Step 3 - If it is Not Empty then, define a Node pointer 'temp' and initialize with head.
Step 4 - Check whether list is having only one node (temp → next == NULL)
Step 5 - If it is TRUE then set head = NULL and delete temp (Setting Empty list
conditions)
Step 6 - If it is FALSE then set head = temp → next, and delete temp.
35
Step 2 - If it is Empty then, display 'List is Empty!!! Deletion is not possible' and
terminate the function.
Step 3 - If it is Not Empty then, define two Node pointers 'temp1' and 'temp2' and
initialize 'temp1' with head.
Step 4 - Check whether list has only one Node (temp1 → next == NULL)
Step 5 - If it is TRUE. Then, set head = NULL and delete temp1. And terminate the
function. (Setting Empty list condition)
Step 6 - If it is FALSE. Then, set 'temp2 = temp1 ' and move temp1 to its next node.
Repeat the same until it reaches to the last node in the list. (until temp1 →
next == NULL)
We can use the following steps to delete a specific node from the single linked list...
Step 2 - If it is Empty then, display 'List is Empty!!! Deletion is not possible' and
terminate the function.
Step 3 - If it is Not Empty then, define two Node pointers 'temp1' and 'temp2' and initialize
'temp1' with head.
Step 4 - Keep moving the temp1 until it reaches to the exact node to be deleted or to the last
node. And every time set 'temp2 = temp1' before moving the 'temp1' to its next node.
Step 5 - If it is reached to the last node then display 'Given node not found in the list!
Deletion not possible!!!'. And terminate the function.
Step 6 - If it is reached to the exact node which we want to delete, then check whether list is
having only one node or not
Step 7 - If list has only one node and that is the node to be deleted, then
set head = NULL and delete temp1 (free(temp1)).
Step 8 - If list contains multiple nodes, then check whether temp1 is the first node in the list
(temp1 == head).
Step 9 - If temp1 is the first node then move the head to the next node (head = head →
next) and delete temp1.
Step 10 - If temp1 is not first node then check whether it is last node in the list (temp1 →
next == NULL).
36
Step 11 - If temp1 is last node then set temp2 → next = NULL and
delete temp1 (free(temp1)).
Step 12 - If temp1 is not first node and not last node then set temp2 → next = temp1 →
next and delete temp1 (free(temp1)).
Algorithm
Function del()
Begin
if(head= NULL)
then
Write “Empty list"
else
Write “Enter the position:"
Read pos
if(pos==1)
then
next=head->link
head=next
ct=ct-1
else
if((pos>=2)&&(pos<=ct))
prev=head
for(int i=2;i<=pos-1;i++)
Do
prev=prev->link
End FOR
temp=prev->link
next=temp->link
prev->link=next
ct=ct-1
End if
End If
End
We can use the following steps to display the elements of a single linked list...
Step 2 - If it is Empty then, display 'List is Empty!!!' and terminate the function.
Step 3 - If it is Not Empty then, define a Node pointer 'temp' and initialize with head.
Step 4 - Keep displaying temp → data with an arrow (--->) until temp reaches to the last
node
37
Step 5 - Finally display temp → data with arrow pointing to NULL (temp → data --->
NULL).
Counting
count()
begin
int co=0;
do
co++;
c=c->link;
while(c!=NULL);
return co;
end
Searching
The operation Search( x ), searches the given value x in the list. If found returns the node
position where it is found. A temporary pointer Temp is created and made to point to the Head.
Now info part of Temp is compared with the value x. If the value matches the node position number
is returned otherwise Temp pointer is moved to the next node. This is repeated till the end of the list
is reached or till the element to be searched is found.
Algorithm
Function search()
Begin
flag=0
if(head=NULL)
then
Write “Empty list"
else
Write ”Enter the element to be searched:"
Read e
cur=head
FOR I = 1 to ct Step +1
Do
if(cur->data= e)
then
pos=I
flag++
break
else
cur=cur->link
End if
ENDFOR
If (flag =1)
38
then
Write "Element found in position:" pos
else
End Search
2.3 Merging
if(list2 == null){
return list1;
}
if(list1.data < list2.data){//initialize mergedList pointer to list1 if list1's data is lesser
mergedList = list1;
}else{//initialize mergedList pointer to list2 if list2's data is lesser or equal
mergedList = list2;
}
while(list1!=null && list2!=null){
if(list1.data < list2.data){
mergedList->next = list1;
list1 = list1->next;
}else{
mergedList->next = list2;
list2 = list2->next;
}
}
if(list1 == null){//remaining nodes of list2 appended to mergedList when list1 has
reached its end.
mergedList->next = list2;
}else{//remaining nodes of list1 appended to mergedList when list2 has reached its end
mergedList->next = list1;
}
return mergedList;
}
39
Traversing
The operation Display( ), displays all the value in each node of the list. A temporary pointer is
created and made to point to Head initially. Now info part of Temp is printed and Temp is moved
to the next node. This is repeated till the end of the list is reached.
Algorithm
Function display()
Begin
cur=head
cout<<"\nNo.of nodes is:"<<ct
cout<<"\nThe data is:"
while (cur< >NULL)
Do
Write "["<<cur->data<<"]->"
cur=cur->link
End while
End
40
2.5 Polynomial Manipulation using List
5x2 + 3x1 + 1
12x3 – 4x1
5x4 – 8x3 + 2x2 + 4x1 + 9x0
It is not necessary to write terms of the polynomials in decreasing order of degree. In other words
the two polynomials 1 + x and x + 1 are equivalent.
The computer implementation requires implementing polynomials as a list of pairs of coefficient and
exponent. Each of these pairs will constitute a structure, so a polynomial will be represented as a list
of structures. A linked list structure that represents polynomials 5x4 – 8x3 + 2x2 + 4x1 + 9x0
illustrates in fig 2.8
41
{
temp = p;
while(temp->next != NULL )
temp = temp->next;
temp->next = newnode;
}
}
return p;
}
void display (node *p)
{
node *t = p;
while (t != NULL)
{
printf("+ %.2f", t -> coef);
printf("X^ %d", t -> expo);
t=t -> next;
}
}
• the Requirement will less memory when compared to doubly, circular or doubly
• the Singly linked list is the very easy data structure to implement.
• Insertion and deletion of elements don’t need the movement of all the elements when
compared to an array.
• therefore, Accessing the preceding node of a current node is not possible as there is no
backward traversal.
42
2.7 Circular linked list
Circular Linked List: Circular linked list is a linked list which consists of collection of nodes each
of which has two parts, namely the data part and the link part. The data part holds the value of the
element and the link part has the address of the next node. The last node of list has the link pointing
to the first node thus making the circular traversal possible in the list is shown in Fig 2.9
Logical representation of the circular linked list:
43
newnode -> next = start;
• If the list is not empty, follow the steps given below:
last = start;
while(last -> next != start)
last= last -> next;
newnode -> next = start;
start = newnode;
last -> next = start;
The function cll_insert_beg(), is used for inserting a node at the beginning. Figure shows inserting a
node into the circular single linked list at the beginning.
44
Fig.2.11 Inserting node at the end
45
2.13 Deleting the node at the end
The following steps are followed, to traverse a list from left to right:
• If list is empty then display ‘Empty List’ message.
• If the list is not empty, follow the steps given below:
temp = start;
do
{
printf("%d", temp -> data);
temp = temp -> next;
} while(temp != start);
In a doubly linked list, the head always points to the first node. The prev pointer of the first
node points to NULL and the next pointer of the last node points to NULL shown in Fig.2.14
46
Addatbeg(x)
The operation Addatbeg(x) adds a given element x at the beginning of the list. A new node
R is created and the value x is store in the data part of R. The prev pointer of R is made to point to
NULL and the next pointer is made to point to head. Then the prev pointer of head is made to point
to R and head is now moved to point to R making it the first node. Thus the new node is added at
the beginning of the doubly linked list.
Algorithm
Function create()
Begin
temp=new node
Write"Enter the data:"
Read temp->data
End
Function insert_begin()
Begin
Call create()
tmp->flink=head
head=tmp
head->blink=NULL
ct=ct+1
End
Addatend(x)
The Addatend(x) operation adds the given element x at the end of the doubly linked list. If
the given list is empty then create a new node R and store the value of x in the data part of R. Now
make the prev pointer and the next pointer of R point to NULL. Then head is pointed to R. If the
list already contains some elements then, a temporary pointer is created and made to point to head.
The temp pointer is now moved to the last node and then a new node R is created. The value x is
stored in the data part of R and next pointer of R is made to point to NULL. The prev pointer of R
is made to point to temp and next pointer of Temp is made to point to R. Thus the new node is added
at the end of the doubly linked list is shown in fig.2.15.
Algorithm
Function append()
Begin
if(head=NULL)
then
insert_begin()
else
create()
47
temp->flink=NULL
prev=head
while(prev->flink< >NULL)
Do
prev=prev->flink
End while
prev->flink=temp
temp->blink=prev
ct=ct+1
End if
End
Insert(x, k)
The Insert(x) operation inserts a given element x at the specified position k. A temporary
pointer is created and made to point to head. Then it is moved to the k-1th node. Now a new node
R is created and the data part is stored with value of x. The next pointer of R is made to point to
next(temp) and the prev pointer of next(temp) is made to point to R. Thus the links on the right side
of the new node is established. Now the next of Temp is made to point to R and the prev pointer of
R is made to point to temp thus establishing the links on the left side of the new node. Now the new
node is inserted at the position k is shown in Fig.2.16.
Algorithm
Function insertin_mid()
Begin
48
Write "Enter the position:"
Read pos;
If head->flink=NULL AND pos=1
then
Call insert_begin()
End if
If head->flink==NULL AND pos=2
then
Call append()
End if
Else if pos>=2 AND pos<=ct
then
prev=head
for I = 2 to pos - 1 step +1
do
prev=prev->flink
END FOR
next=prev->link
temp=new node
Write”Enter the data:"
Read temp->data
temp->flink=next
prev->flink=temp
temp->blink=prev;
next->blink=temp;
ct=ct+1
else
Write "Enter a valid position & try again"
End if
End
49
Delete(x)
The Delete(x) operation deletes the element x from the doubly linked list. A temporary
pointer is created and made to point to head. Now the data of temp is compared with x and if it
matches that is the node to be deleted otherwise move to the next node and again compare. If the
node to be deleted is first node, then prev(next(temp)) is made to point to NULL and head is pointed
to next(temp). The node pointed by temp is deleted. When the node to be deleted is not the first
node, then next(prev(temp)) is made to point to next(temp) and prev(next(temp)) is made to point to
prev(temp). The node pointed by temp is deleted is shown in Fig.2.17.
Algorithm
Function del()
Begin
if(head= NULL)
then
cout<<"Empty list"
else
Write Enter the position\n"
Read pos
pre=head
if(pos<1 OR pos>ct)
Write Enter a valid position"
else
if(pos==1)
then
pre=pre->flink
head=pre
Write "node gets deleted\n"
Ct=ct -1
else
for(i=2;i<pos;i++)
pre=pre->flink
End For
tmp=pre->flink
nxt=tmp->flink
pre->flink=nxt
nxt->blink=pre
Write”node gets deleted\n"
Ct=ct -1
End if
End if
50
Fig.2.17 Deletion
51
• Deletion.
• Traversing.
Create node
create_node(int info)
begin
new->val = info;
new->next = NULL;
new->prev = NULL;
return new;
end
insert_at_first()
begin
Read info
new = create_node(info); // create the new node
if (first == last && first == NULL) // if the list is empty
begin
first = last = new;
first->next = last->next = NULL;
first->prev = last->prev = NULL;
end
else
begin
52
new->next = first;
first->prev = new;
first = new;
first->prev = last;
last->next = first;
end
end
insert_at_end()
begin
Read info;
new = create_node(info);
if (first == last && first == NULL)
begin
first = last = new;
first->next = last->next = NULL;
first->prev = last->prev = NULL;
endif
else
begin
last->next = new;
new->prev = last;
last = new;
first->prev = last;
last->next = first;
endif
end
insert_at_position()
begin
Declare info, pos, len = 0, i;
Node *prevnode;
Read info and pos
new = create_node(info);
if (first == last && first == NULL)
begin
if (pos == 1)
begin
first = last = new;
first->next = last->next = NULL;
first->prev = last->prev = NULL;
endif
else
53
printf " empty linked list you cant insert at that particular position"
endif
else
begin
if (number < pos) // total number of node is stored in the variable number
print “ node cant be inserted as position is exceeding the linkedlist length"
else
54
number--;
last->next = prevnode->next;
ptr->prev = prevnode->prev;
first = ptr;
printf("%d is deleted", prevnode->val);
free(prevnode);
break;
end
else if (i == pos - 1)
begin
number--;
prevnode->next = ptr->next;
ptr->next->prev = prevnode;
printf("%d is deleted", ptr->val);
free(ptr);
break;
end
end
end
end
end
Searching
search()
begin
int count = 0, key, i, f = 0;
read the value to be searched in the variable key
if (first == last && first == NULL)
print "list is empty no elemnets in list to search"
else
for (ptr = first,i = 0;i < number;i++,ptr = ptr->next)
begin
count++;
if (ptr->val == key)
begin
Print " the value is found at position count ”
f = 1;
end
end
if (f == 0)
print "the value is not found in linkedlist"
end
end
55
DISPLAYING IN BEGINNING
Algorithm
display_from_beg()
begin
int i;
if (first == last && first == NULL)
print "list is empty no elemnts to print"
else
begin
Store total number of node in the variable , number
for (ptr = first, i = 0;i < number;i++,ptr = ptr->next)
print ptr->val
end
end
56
SCHOOL OF COMPUTING
57
Unit:III
Introduction – Array Representation of a Stack – Linked List Representation of a Stack - Stack
Operations - Algorithm for Stack Operations - Stack Applications: Tower of Hanoi - Infix to
postfix Transformation - Evaluating Arithmetic Expressions. Queue – Introduction – Array
Representation of Queue – Linked List Representation of Queue - Queue Operations -
Algorithm for Queue Operations - . Queue Applications: Priority Queue.
3.1 Introduction
A stack is an Abstract Data Type (ADT), commonly used in most programming languages. It is
named stack as it behaves like a real-world stack, for example – a deck of cards or a pile of plates,
etc.
This feature makes it LIFO data structure. LIFO stands for Last-in-first-out. Here, the element which
is placed (inserted or added) last, is accessed first. In stack terminology, insertion operation is
called PUSH operation and removal operation is called POP operation.
Stack Representation
The following fig 3.1 depicts a stack and its operations −
A stack can be implemented by means of Array, Structure, Pointer, and Linked List. Stack can
either be a fixed size one or it may have a sense of dynamic resizing. Here, we are going to implement
stack using arrays, which makes it a fixed size stack implementation. First we have to allocate a
58
memory block of sufficient size to accommodate the full capacity of the stack. Then, starting from
the first location of the memory block, the items of the stack can be stored in a sequential fashion.
In Fig 3.2 a, Itemi denotes the ith item in the stack; l and u denote the index range of
the array in use; usually the values of these indices are 1 and SIZE respectively. TOP is a
pointer to point the position of the array up to which it is filled with the items of the stack.
Although array representation of stacks is very easy and convenient but it allows the
representation of only fixed sized stacks. In several applications, the size of the stack may
vary during program execution. An obvious solution to this problem is to represent a stack
using a linked list. A single linked list structure is sufficient to represent any stack. Here,
the DATA field is for the ITEM, and the LINK field is, as usual, to point to the next' item.
Above Figure b depicts such a stack using a single linked list. In the linked list
representation, the first node on the list is the current item that is the item at the top of the
stack and the last node is the node containing the bottom-most item. Thus, a PUSH
operation will add a new node in the front and a POP operation will remove a node from
the front of the list is shown in Fig 3.2 b.
3.4 Stack Operations
Stack operations may involve initializing the stack, using it and then de-initializing it. Apart
from these basic stuffs, a stack is used for the following two primary operations −
• push() − Pushing (storing) an element on the stack.
• pop() − Removing (accessing) an element from the stack.
59
When data is PUSHed onto stack.
To use a stack efficiently, we need to check the status of stack as well. For the same purpose, the
following functionality is added to stacks −
• peek() − get the top data element of the stack, without removing it.
• isFull() − check if stack is full.
• isEmpty() − check if stack is empty.
At all times, we maintain a pointer to the last PUSHed data on the stack. As this pointer always
represents the top of the stack, hence named top. The top pointer provides top value of the stack
without actually removing it.
3.5 Algorithm for Stack Operations
Push Operation
The process of putting a new data element onto stack is known as a Push Operation is shown in
fig.3.3. Push operation involves a series of steps −
Step 1 − Checks if the stack is full.
Step 2 − If the stack is full, produces an error and exit.
Step 3 − If the stack is not full, increments top to point next empty space.
Step 4 − Adds data element to the stack location, where top is pointing.
Step 5 − Returns success.
if stack is full
return null
endif
top ← top + 1
stack[top] ← data
end procedure
60
Pop Operation
Accessing the content while removing it from the stack, is known as a Pop Operation. In an array
implementation of pop() operation, the data element is not actually removed, instead top is
decremented to a lower position in the stack to point to the next value. But in linked-list
implementation, pop() actually removes data element and deallocates memory space is shown in
Fig.3.4.
A Pop operation may involve the following steps −
Step 1 − Checks if the stack is empty.
Step 2 − If the stack is empty, produces an error and exit.
Step 3 − If the stack is not empty, accesses the data element at which top is pointing.
Step 4 − Decreases the value of top by 1.
Step 5 − Returns success.
if stack is empty
return null
endif
data ← stack[top]
top ← top - 1
return data
Displays the elements of a Stack
We can use the following steps to display the elements of a stack...
Step 2 - If it is EMPTY, then display "Stack is EMPTY!!!" and terminate the function.
Step 3 - If it is NOT EMPTY, then define a variable 'i' and initialize with top.
Display stack[i] value and decrement i value by one (i--).
61
3.6 Stack Using Linked List
In linked list implementation of a stack, every new element is inserted as 'top' element. That
means every newly inserted element is pointed by 'top'. Whenever we want to remove an element
from the stack, simply remove the node which is pointed by 'top' by moving 'top' to its previous
node in the list. The next field of the first element must be always NULL.
Example
We can use the following steps to insert a new node into the stack...
62
Algorithm
push(int value)
begin
newNode->data = value;
if(top == NULL)
newNode->next = NULL;
else
newNode->next = top;
top = newNode;
end
We can use the following steps to delete a node from the stack...
Step 3 - If it is Not Empty, then define a Node pointer 'temp' and set it to 'top'.
63
Algorithm
void pop()
begin
if(top == NULL)
print("\nStack is Empty!!!\n");
else
top = temp->next;
free(temp);
endif
end
We can use the following steps to display the elements (nodes) of a stack...
Step 2 - If it is Empty, then display 'Stack is Empty!!!' and terminate the function.
Step 3 - If it is Not Empty, then define a Node pointer 'temp' and initialize with top.
Step 4 - Display 'temp → data --->' and move it to the next node. Repeat the same
until temp reaches to the first node in the stack. (temp → next != NULL).
64
Algorithm
void display()
begin
if(top == NULL)
print("\nStack is Empty!!!\n");
else{
struct Node *temp = top;
while(temp->next != NULL)
begin
print("%d--->",temp->data);
temp = temp -> next;
end
print("%d--->NULL",temp->data);
end
Disks
Smallest
Largest
65
arrangement. The below mentioned are few rules which are to be followed for Tower of Hanoi
• Only one disk can be moved among the towers at any given time.
• Only the “top” disk can be removed.
• No large disk can sit over a small disk.
Step: 0
Step: 2
66
Step: 6
67
Done!
END
3.7.2 Infix to postfix Transformation
There is an algorithm to convert an infix expression into a postfix expression. It uses a stack;
but in this case, the stack is used to hold operators rather than numbers. The purpose of the stack is
to reverse the order of the operators in the expression. It also serves as a storage structure, since no
operator can be printed until both of its operands have appeared.
In this algorithm, all operands are printed (or sent to output) when they are read. There are
more complicated rules to handle operators and parentheses.
Example:
1. A * B + C becomes A B * C +
The order in which the operators appear is not reversed. When the '+' is read, it has lower precedence
than the '*', so the '*' must be printed first.
We will show this in a table with three columns. The first will show the symbol currently being read.
The second will show what is on the stack and the third will show the current contents of the postfix
string. The stack will be written from left to right with the 'bottom' of the stack to the left.
68
current symbol operator stack postfix string
1 A A
2 * * A
3 B * AB
5 C + AB*C
6 AB*C+
The rule used in lines 1, 3 and 5 is to print an operand when it is read. The rule for line 2 is to push
an operator onto the stack if it is empty. The rule for line 4 is if the operator on the top of the stack
has higher precedence than the one being read, pop and print the one on top and then push the new
operator on. The rule for line 6 is that when the end of the expression has been reached, pop the
operators on the stack one at a time and print them.
2. A + B * C becomes A B C * +
Here the order of the operators must be reversed. The stack is suitable for this, since operators will
be popped off in the reverse order from that in which they were pushed.
1 A A
2 + + A
3 B + AB
4 * +* AB
5 C +* ABC
6 ABC*+
In line 4, the '*' sign is pushed onto the stack because it has higher precedence than the '+' sign which
is already there. Then when the are both popped off in lines 6 and 7, their order will be reversed.
69
3. A * (B + C) becomes A B C + *
A subexpression in parentheses must be done before the rest of the expression.
1 A A
2 * * A
3 ( *( AB
4 B *( AB
5 + *(+ AB
6 C *(+ ABC
7 ) * ABC+
8 ABC+*
Since expressions in parentheses must be done first, everything on the stack is saved and the left
parenthesis is pushed to provide a marker. When the next operator is read, the stack is treated as
though it were empty and the new operator (here the '+' sign) is pushed on. Then when the right
parenthesis is read, the stack is popped until the corresponding left parenthesis is found. Since postfix
expressions have no parentheses, the parentheses are not printed.
4. A - B + C becomes A B - C +
When operators have the same precedence, we must consider association. Left to right association
means that the operator on the stack must be done first, while right to left association means the
reverse.
1 A A
2 - - A
3 B - AB
70
4 + + AB-
5 C + AB-C
6 AB-C+
In line 4, the '-' will be popped and printed before the '+' is pushed onto the stack. Both operators
have the same precedence level, so left to right association tells us to do the first one found before
the second.
5. A * B ^ C + D becomes A B C ^ * D +
Here both the exponentiation and the multiplication must be done before the addition.
1 A A
2 * * A
3 B * AB
4 ^ *^ AB
5 C *^ ABC
6 + + ABC^*
7 D + ABC^*D
8 ABC^*D+
When the '+' is encountered in line 6, it is first compared to the '^' on top of the stack. Since it has
lower precedence, the '^' is popped and printed. But instead of pushing the '+' sign onto the stack
now, we must compare it with the new top of the stack, the '*'. Since the operator also has higher
precedence than the '+', it also must be popped and printed. Now the stack is empty, so the '+' can be
pushed onto the stack.
71
6. A * (B + C * D) + E becomes A B C D * + * E +
1 A A
2 * * A
3 ( *( A
4 B *( AB
5 + *(+ AB
6 C *(+ ABC
7 * *(+* ABC
8 D *(+* ABCD
9 ) * ABCD*+
10 + + ABCD*+*
11 E + ABCD*+*E
12 ABCD*+*E+
72
7. If the incoming symbol has lower precedence than the symbol on the top of the stack, pop
the stack and print the top operator. Then test the incoming operator against the new top of
stack.
8. At the end of the expression, pop and print all operators on the stack. (No parentheses
should remain.)
Algorithm
int top = -1;
Infixtopostfix()
begin
print("\n\nRead the Infix Expression ? ");
Read infx
push('#');
while ((ch = infx[i++]) != '\0')
begin
if (ch == '(')
push(ch);
else if (isalnum(ch))
pofx[k++] = ch;
else if (ch == ')')
begin
while (s[top] != '(')
begin
pofx[k++] = pop();
elem = pop(); /* Remove ( */
end
else
while (pr(s[top]) >= pr(ch))
pofx[k++] = pop();
push(ch);
end
end
73
operators and operands in an arithmetic expression does not uniquely determine the order in which
the operations are to be performed.
1. Polish notation (prefix notation) –
It refers to the notation in which the operator is placed before its two operands . Here no
parentheses are required, i.e., +AB
The procedure for getting the result is:
1. Convert the expression in Reverse Polish notation( post-fix notation).
2. Push the operands into the stack in the order they are appear.
3. When any operator encounter then pop two topmost operands for executing the operation.
4. After execution push the result obtained into the stack.
5. After the complete execution of expression the final result remains on the top of the stack.
For example –
Infix notation: (2+4) * (4+6)
Post-fix notation: 2 4 + 4 6 + *
Result: 60
6. The stack operations for this expression evaluation is shown below:
3.8 Queue
3.8.1 Introduction
Queue is also an abstract data type or a linear data structure, just like stack data structure, in
which the first element is inserted from one end called the REAR(also called tail), and the removal
74
of existing element takes place from the other end called as FRONT (also called head). This makes
queue as FIFO (First in First Out) data structure, which means that element inserted first will be
removed first. The process to add an element into queue is called Enqueue and the process of
removal of an element from queue is called Dequeue.
ADDQ(x)
If rear = MAX – 1
Then
Print “Queue is full”
Return
Else
Rear = rear + 1
A[rear] = x
If front = -1
Then
Front = 0
End if
End if
End ADDQ( )
75
Del( )
The del( ) operation deletes the element from the front of the queue. Before deleting and
element, it is checked if the queue is empty. If not the element pointed by front is deleted from the
queue and front is now made to point to the next element in the queue.
DELQ( )
If front = -1
Then
Print “Queue is Empty”
Return
Else
Item = A[front]
A[front] = 0
If front = rear
Then
Front = rear = -1
Else
Front = front + 1
End if
Return item
End if
End DELQ( )
Queue can be represented using a linked list. Linked lists do not have any restrictions on the
number of elements it can hold. Space for the elements in a linked list is allocated dynamically;
hence it can grow as long as there is enough memory available for dynamic allocation. The queue
represented using linked list would be represented as shown. The front pointer points to the front of
the queue and rear pointer points to the rear of the queue is shown in Fig 3.9.
76
Fig 3.9 Linked List
Addq(x)
In linked list representation of queue, the addition of new element to the queue takes place at
the rear end. It is the normal operation of adding a node at the end of a list.
ADDQ(x)
If front = NULL
Then
Rear = front = temp
Return
End if
Link(rear) = temp
Rear = link(rear)
End ADDQ( )
Delq( )
The delq( ) operation deletes the first element from the front end of the queue. Initially it is
checked, if the queue is empty. If it is not empty, then return the value in the node pointed by front,
and moves the front pointer to the next node.
DELQ( )
If front = NULL
Print “Queue is empty”
Return
Else
While front ≠ NULL
Temp = front
Front = link(front)
Delete temp
End while
End if
End DELQ( )
77
3.8.5 Queue Applications
3.8.5.1 Priority Queue
Priority Queue is more specialized data structure than Queue. Like ordinary queue, priority
queue has same method but with a major difference. In Priority queue items are ordered by key value
so that item with the lowest value of key is at front and item with the highest value of key is at rear
or vice versa is shown in Fig.3.10.
Basic Operations
• insert / enqueue − add an item to the rear of the queue.
• remove / dequeue − remove an item from the front of the queue.
Priority Queue Representation
78
void insert(int data){
int i = 0;
if(!isFull()){
// if queue is empty, insert the data
if(itemCount == 0){
intArray[itemCount++] = data;
}else{
// start from the right end of the queue
for(i = itemCount - 1; i >= 0; i-- ){
// if data is larger, shift existing item to right end
if(data > intArray[i]){
intArray[i+1] = intArray[i];
}else{
break;
}
}
// insert the data
intArray[i+1] = data;
itemCount++;
}
}
}
Remove / Dequeue Operation
Whenever an element is to be removed from queue, queue get the element using item count. Once
element is removed. Item count is reduced by one.
int removeData(){
return intArray[--itemCount];
}
79
SCHOOL OF COMPUTING
80
UNIT IV
Preliminaries of Tree ADT - Binary Trees - The Search Tree ADT–Binary Search Trees - AVL
Trees - Tree Traversals - B-Trees - Heap Tree – Preliminaries of Graph ADT - Representation of
Graph – Graph Traversal - BFS – DFS – Applications of Graph – Shortest - Path Algorithms –
Dijkstra’s Algorithm Minimum Spanning Tree – Prims Algorithm
Degree of tree =3
Parent = node that has subtrees
Children = the roots of the subtrees of parent
81
A binary tree is a tree in which no node can have more than two children. Each node can have 0, 1
or 2 children is shown Fig 4.2.
2 3
5 6
In this tree, node 1,2 and 3 contains two points i.e, left and right pointer pointing to the left and right
node respectively. Similarly nodes 3, 5 and 6 are the leaf nodes so these nodes have NULL pointer
on both left and right parts.
Properties of Binary Tree
a) At each level of i, the maximum number of nodes is 2i.
b) The height of tree is defines as the longest path from the root node to the leaf node. Her example
has height 3 and the maximum number of nodes at height 3 is (1+2+4+8)=15.
c) The minimum number of nodes possible at height h is equal to h+1.
d) If the number of nodes is minimum, then the height of the tree would be maximum. Similarly, if
the number of nodes is maximum, then the height of the tree would be minimum.
2 3
4 5 6 7
8 82
Fig 4.3 complete binary tree
83
Fig 4.5Binary search tree
Basic Operations
1. Search
2. Insert
3. Pre-order Traversal
4. In-order Traversal
5. Post-order Traversal
1. Search Operation
Whenever an element is to be searched, start searching from the root node. If the data is less than
the key value, then search for the element in the left subtree. Otherwise, search for the element in
the right subtree. Fig 4.6 shows the example of search operation.
84
Fig 4.7 Find Min and max values
2. Insertion Operation
When a binary search tree is constructed, the keys are added one at a time. As the keys are inserted,
a new node is created for each key and linked into its proper position within the tree. Suppose we
want to build a binary search tree from the key list [60, 25, 100, 35, 17, 80] by inserting the keys in
the order they are listed is shown in Fig 4.8.
85
Fig 4.9 Removing leaf node
✓ Removing an interior node with one child shown in Fig 4.10.
86
✓ Removing an interior node with two children is shown in Fig 4.11.
For node 12, its predecessor is node 4 and its successor is node 23. For removing an interior node
with two children requires three steps:
1. Find the logical successor, S, of the node to be deleted, N.
2. Copy the key from node S to node N.
3. Remove node S from the tree.
87
With each node in an AVL tree, we associate a balance factor, which indicates the height
difference between the left and right branch. The balance factor can be one of three states:
left high (>): When the left subtree is higher than the right subtree.
equal high (=): When the two subtrees have equal height.
right high (<): When the right subtree is higher than the left subtree
Insertions
Inserting a key into an AVL tree begins with the same process used with a binary search tree. We
search for the new key in the tree and add a new node at the child link where we fall off the tree.
When a new key is inserted into an AVL tree, the balance property of the tree must be maintained.
If the insertion of the new key causes any of the subtrees to become unbalanced, they will have to
be rebalanced is shown in Fig.4.13.
88
i) Case 1: When the balance factor of the pivot node (P) is left high before the insertion and the new
key is inserted into the left child (C) of the pivot node. To rebalance the subtree, the pivot node has
to be rotated right over its left child. The rotation is accomplished by changing the links such that P
becomes the right child of C and the right child of C becomes the left child of P is shown in Fig 4.15.
ii) Case 2: the pivot (P), the left child of the pivot (C), and the right child (G) of C. For this case to
occur, the balance factor of the pivot is left high before the insertion and the new key is inserted into
either the right subtree of C. Node C has to be rotated left over node V and the pivot node has to be
rotated right over its left child. The right child of G as the new left child of the pivot node, changing
the left child of G to become the right child of C, and setting C to be the new left child of G is shown
in Fig 4.16.
89
Deletions
When an entry is removed from an AVL tree, we must ensure the balance property is maintained.
For example, suppose we want to remove key 17 from the AVL tree in Figure 14.21(a). After
removing the leaf node, the subtree rooted at node 25 is out of balance, as shown below. A left
rotation has to be performed pivoting on node 25 to correct the imbalance is shown in Fig 4.18.
90
(3) Process the root R.
Observe that each algorithm contains the same three steps, and that the left subtree of R is
always traversed before the right subtree. The difference between the algorithms is the time at which
the root R is processed. The three algorithms are sometimes called, respectively, the node-left-right
(NLR) traversal, the left-node-right (LNR) traversal and the left-right-node (LRN) traversal.
Traversal algorithms
Preorder Traversal
Consider the following case where we have 6 nodes in the tree A, B, C, D, E, F. The traversal
always starts from the root of the tree. The node A is the root and hence it is visited first. The value
at this node is processed. Now we check if there exists any left child for this node if so apply the
preorder procedure on the left subtree. Now check if there is any right subtree for the node A, the
preorder procedure is applied on the right subtree.
Since there exists a left subtree for node A, B is now considered as the root of the left subtree
of A and preorder procedure is applied. Hence we find that B is processed next and then it is checked
if B has a left subtree is shown in Fig. 4.19
91
The algorithm for the above method is presented in the pseudo-code form below:
Algorithm
PREORDER( ROOT )
Temp = ROOT
If temp = NULL
Return
End if
Print info(temp)
If left(temp) ≠ NULL
PREORDER( left(temp))
End if
If right(temp) ≠ NULL
PREORDER(right(temp))
End if
End PREORDER
Inorder Traversal
In the Inorder traversal method, the left subtree of the current node is visited first and then
the current node is processed and at last the right subtree of the current node is visited. In the
following example, the traversal starts with the root of the binary tree. The node A is the root and it
is checked if it has the left subtree. Then the inorder traversal procedure is applied on the left subtree
of the node A. Now we find that node D does not have left subtree. Hence the node D is processed
and then it is checked if there is a right subtree for node D. Since there is no right subtree, the control
returns back to the previous function which was applied on B. Since left of B is already visited, now
B is processed. It is checked if B has the right subtree. If so apply the inorder traversal method on
the right subtree of the node B. This recursive procedure is followed till all the nodes are visited is
shown in Fig.4.20.
92
Fig 4.20 Inorder Traversal
Algorithm
INORDER( ROOT )
Temp = ROOT
If temp = NULL
Return
End if
If left(temp) ≠ NULL
INORDER(left(temp))
End if
Print info(temp)
If right(temp) ≠ NULL
INORDER(right(temp))
End if
End INORDER
93
Postorder Traversal
In the postorder traversal method the left subtree is visited first, then the right subtree and at
last the current node is processed. In the following example, A is the root node. Since A has the left
subtree the postorder traversal method is applied recursively on the left subtree of A. Then when
left subtree of A is completely is processed, the postorder traversal method is recursively applied on
the right subtree of the node A. If right subtree is completely processed, then the current node A is
processed is shown in Fig 4.21.
Algorithm
POSTORDER( ROOT )
Temp = ROOT
If temp = NULL
Return
End if
If left(temp) ≠ NULL
POSTORDER(left(temp))
End if
If right(temp) ≠ NULL
POSTORDER(right(temp))
End if
Print info(temp)
End POSTORDER
94
4.6 B TREES
An extension of a multiway search tree of order m is a B-tree of order m. This type of tree will be
used when the data to be accessed / stored is located on secondary storage devices because they allow
for large amounts of data to be stored in a node. A B-tree of order m is a multiway search tree in
which:
1. The root has at least two subtrees unless it is the only node in the tree.
2. Each nonroot and each nonleaf node have at most m nonempty children and at least m/2 nonempty
children.
3. The number of keys in each nonroot and each nonleaf node is one less than the number of its
nonempty children.
4. All leaves are on the same level.
Searching
An algorithm for finding a key in B-tree is simple. Start at the root and determine which pointer to
follow based on a comparison between the search value and key fields in the root node. Follow the
appropriate pointer to a child node. Examine the key fields in the child node and continue to follow
the appropriate pointers until the search value is found or a leaf node is reached that doesn't contain
the desired search value.
Insertion
The condition that all leaves must be on the same level forces a characteristic behavior of Btrees,
namely that B-trees are not allowed to grow at the their leaves; instead they are forced to grow at the
root. When inserting into a B-tree, a value is inserted directly into a leaf is shown in Fig 4.22 and
Fig.4.23. This leads to three common situations that can occur:
1. A key is placed into a leaf that still has room.
2. The leaf in which a key is to be placed is full.
3. The root of the B-tree is full.
95
Fig 4.23 steps in B-tree insertion operation
96
Deletion
The deletion process will basically be a reversal of the insertion process - rather than splitting nodes,
it's possible that nodes will be merged so that B-tree properties, namely the requirement that a node
must be at least half full, can be maintained is shown in Fig 4.24 ,Fig 4.25 and Fig 4.26.
There are two main cases to be considered:
1. Deletion from a leaf
2. Deletion from a non-leaf
97
Fig 4.25 Deletion
98
Fig 4.26 steps in B Tree deletion operation
4.7 HEAP TREE
Heap is a special case of balanced binary tree data structure where the root-node key is compared
with its children and arranged accordingly. A heap is a complete binary tree in which the nodes are
organized based on their data entry values. There are two variants of the heap structure. A max-heap
has the property, known as the heap order property, that for each non-leaf node V, the value in V is
greater than the value of its two children. The largest value in a max-heap will always be stored in
the root while the smallest values will be stored in the leaf nodes. The min-heap has the opposite
property. For each non-leaf node V, the value in V is smaller than the value of its two children is
shown in Fig.4.27 and Fig.4.28.
99
Example
100
4.8 PRELIMINARIES OF GRAPH ADT
Graph is a non linear data structure; A map is a well-known example of a graph. In a map various
connections are made between the cities. The cities are connected via roads, railway lines and aerial
network. We can assume that the graph is the interconnection of cities by roads. A graph contains a
set of points known as nodes (or vertices) and set of links known as edges (or Arcs) which connects
the vertices.
A graph is defined as Graph is a collection of vertices and arcs which connects vertices in the graph.
A graph G is represented as G = ( V , E ), where V is set of vertices and E is set of edges.
Example: graph G can be defined as G=(V,E) Where V={A,B,C,D,E} and E=
{(A,B),(A,C)(A,D),(B,D),(C,D),(B,E),(E,D)}. This is a graph with 5 vertices and 6 edges is shown
in Fig.4.29.
2. Directed Graph
A graph with only directed edges is said to be directed graph.
3. Complete Graph
101
A graph in which any V node is adjacent to all other nodes present in the graph is known as a
complete graph. An undirected graph contains the edges that are equal to edges = n(n-1)/2 where n
is the number of vertices present in the graph. The following figure shows a complete graph.
4. Regular Graph
Regular graph is the graph in which nodes are adjacent to each other, i.e., each node is accessible
from any other node.
5. Cycle Graph
A graph having cycle is called cycle graph. In this case the first and last nodes are the same. A closed
simple path is a cycle.
6. Acyclic Graph
A graph without cycle is called acyclic graphs.
7. Weighted Graph
A graph is said to be weighted if there are some non negative value assigned to each edges of the
graph. The value is equal to the length between two vertices. Weighted graph is also called a network.
Outgoing Edge
A directed edge is said to be outgoing edge on its orign vertex.
Incoming Edge
A directed edge is said to be incoming edge on its destination vertex.
Degree
Total number of edges connected to a vertex is said to be degree of that vertex.
Indegree
Total number of incoming edges connected to a vertex is said to be indegree of that vertex.
Outdegree
Total number of outgoing edges connected to a vertex is said to be outdegree of that vertex.
Parallel edges or Multiple edges
If there are two undirected edges to have the same end vertices, and for two directed edges to have
the same origin and the same destination. Such edges are called parallel edges or multiple edges.
Self-loop
An edge (undirected or directed) is a self-loop if its two endpoints coincide.
Simple Graph
A graph is said to be simple if there are no parallel and self-loop edges.
Adjacent nodes
When there is an edge from one node to another then these nodes are called adjacent nodes.
102
Incidence
In an undirected graph the edge between v1 and v2 is incident on node v1 and v2.
Walk
A walk is defined as a finite alternating sequence of vertices and edges, beginning and ending with
vertices, such that each edge is incident with the vertices preceding and following it.
Closed walk
A walk which is to begin and end at the same vertex is called close walk. Otherwise it is an open
walk. If e1,e2,e3,and e4 be the edges of pair of vertices (v1,v2),(v2,v4),(v4,v3) and (v3,v1)
respectively ,then v1 e1 v2 e2 v4 e3 v3 e4 v1 be its closed walk or circuit.
Path
A open walk in which no vertex appears more than once is called a path. If e1 and e2 be the two
edges between the pair of vertices (v1,v3) and (v1,v2) respectively, then v3 e1 v1 e2 v2 be its path.
Length of a path
The number of edges in a path is called the length of that path. In the following, the length of the
path is 3.
Circuit
A closed walk in which no vertex (except the initial and the final vertex) appears more than once is
called a circuit. A circuit having three vertices and three edges.
Sub Graph
A graph S is said to be a sub graph of a graph G if all the vertices and all the edges of S are in G, and
each edge of V(G) and E(G’) S has the same end vertices in S as in G. A subgraph of G is a
graph G’ such that V(G’) E(G)
Connected Graph
A graph G is said to be connected if there is at least one path between every pair of vertices in G.
Otherwise, G is disconnected. This graph is disconnected because the vertex v1 is not connected
with the other vertices of the graph.
Degree
In an undirected graph, the number of edges connected to a node is called the degree of that node or
the degree of a node is the number of edges incident on it. In the above graph, degree of vertex v1 is
1, degree of vertex v2 is 3, degree of v3 and v4 is 2 in a connected graph.
103
Indegree
The indegree of a node is the number of edges connecting to that node or in other words edges
incident to it.
Outdegree
The outdegree of a node (or vertex) is the number of edges going outside from that node.
In this representation, graph can be represented using a matrix of size total number of vertices
by total number of vertices; means if a graph with 4 vertices can be represented using a matrix of
4X4 size. In this matrix, rows and columns both represent vertices. This matrix is filled with either
1 or 0. Here, 1 represents there is an edge from row vertex to column vertex and 0 represents there
is no edge from row vertex to column vertex.
Adjacency Matrix: let G = (V, E) with n vertices, n≥1. The adjacency matrix of G is a 2-dimensional
n x n matrix, A, A(i, j) = 1 iff (vi vj)ϵE(G) (<vi, vj> for a diagraph), A(i, j) = 0 otherwise.
example : for undirected graph
The adjacency matrix for an undirected graph is symmetric; the adjacency matrix for a
digraph need not be symmetric. The space needed to represent a graph using adjacency matrix is n2
bits. To identify the edges in a graph, adjacency matrices will require at least O(n2 ) time.
• Adjacency List
In this representation, every vertex of graph contains list of its adjacent vertices. The n rows of the
adjacency matrix are represented as n chains. The nodes in chain I represent the vertices that are
adjacent to vertex i.
It can be represented in two forms. In one form, array is used to store n vertices and chain is used to
store its adjacencies.
104
So that we can access the adjacency list for any vertex in O(1) time. Adjlist[i] is a pointer to to first
node in the adjacency list for vertex i. example: consider the following directed graph representation
implemented using linked list
• Adjacency Multilists
In the adjacency-list representation of an undirected graph each edge (u, v) is represented by two
entries one on the list for u and the other on that list for v. This can be accomplished easily if the
adjacency lists are actually maintained as multilists (i.e., lists in which nodes may be shared among
several lists). For each edge there will be exactly one node but this node will be in two lists (i.e. the
adjacency lists for each of the two nodes to which it is incident).
• Weighted edges
In many applications the edges of a graph have weights assigned to them. These weights may
represent the distance from one vertex to another or the cost of going from one; vertex to an adjacent
vertex In these applications the adjacency matrix entries A [i][j] would keep this information too.
When adjacency lists are used the weight information may be kept in the list nodes by including an
additional field weight. A graph with weighted edges is called a network.
105
For example, in the following graph, we start traversal from vertex 2. When we come to vertex 0,
we look for all adjacent vertices of it. 2 is also an adjacent vertex of 0. If we don’t mark visited
vertices, then 2 will be processed again and it will become a non-terminating process. Breadth First
Traversal of the following graph is 2, 0, 3, 1.
106
be used for crawlers, but the advantage with Breadth First Traversal is, depth or levels of built tree
can be limited.
4) Social Networking Websites: In social networks, we can find people within a given distance ‘k’
from a person using Breadth First Search till ‘k’ levels.
5) GPS Navigation systems: Breadth First Search is used to find all neighboring locations.
6) Broadcasting in Network: In networks, a broadcasted packet follows Breadth First Search to
reach all nodes.
7) In Garbage Collection: Breadth First Search is used in copying garbage collection using
Cheney’s algorithm.
8) Cycle detection in undirected graph: In undirected graphs, either Breadth First Search or Depth
First Search can be used to detect cycle. In directed graph, only depth first search can be used.
9) Ford–Fulkerson algorithm In Ford-Fulkerson algorithm, we can either use Breadth First or
Depth First Traversal to find the maximum flow. Breadth First Traversal is preferred as it reduces
worst case time complexity to O(VE2 ).
10) To test if a graph is Bipartite We can either use Breadth First or Depth First Traversal.
11) Path Finding We can either use Breadth First or Depth First Traversal to find if there is a path
between two vertices.
12) Finding all nodes within one connected component: We can either use Breadth First or Depth
First Traversal to find all nodes reachable from a given node.
107
The DFS forms a depth-first forest comprised of more than one depth-first trees. Each tree is made
of edges (u, v) such that u is gray and v is white when edge (u, v) is explored. The following
pseudocode for DFS uses a global timestamp time.
108
4.11 SHORTEST PATH ALGORITHM
Given a graph where edges are labeled with weights (or distances) and a source vertex, what is the
shortest path between the source and some other vertex? Problems requiring us to answer such
queries are broadly known as shortest-paths problems. Shortest-paths problem come in several
flavors. For example, the single-source shortest path problem requires finding the shortest paths
between a given source and all other vertices; the single-pair shortest path problem requires finding
the shortest path between given a source and a given destination vertex; the all-pairs shortest path
problem requires finding the shortest paths between all pairs of vertices.
Dijkstra’s algorithm is an iterative algorithm that provides us with the shortest path from one
particular starting mode to all other nodes in the graph. To keep track of the total cost from the start
node to each destination we will make use of the distance instance variable in the vertex class. The
distance instance variable will contain the current total weight of the smallest weight path from the
start to the vertex. Dijkstra’s algorithm finds the shortest path in a weighted graph containing only
positive edge weights from a single source. It uses a priority based dictionary or a queue to select a
node / vertex nearest to the source that has not been edge relaxed. Time complexity of Dijkstra’s
algorithm is O((E+V) Log(V)) for an adjacency list implementation of a graph. V is the number of
vertices and E is the number of edges in a graph.
On repeating the above steps until the set contains all vertices of given graph. Then we get the
following Shortest Path.
109
Step 4: Step 5:
Prim’s algorithm is also a greedy algorithm technique. It starts with an empty spanning tree. The
idea is to maintain two sets of vertices:
At every step, it considers all the edges and picks the minimum weight edge. After picking the
edge, it moves the other endpoint of edge to set containing MST.
1. Create MST set that keeps track of vertices already included in MST.
2. Assign key values to all vertices in the input graph. Initialize all key values as INFINITE (∞).
Assign key values like 0 for the first vertex so that it is picked first.
3. While MST set doesn't include all vertices.
a. Pick vertex u which is not is MST set and has minimum key value. Include 'u'to MST set.
b. Update the key value of all adjacent vertices of u. To update, iterate through all adjacent vertices.
For every adjacent vertex v, if the weight of edge u.v less than the previous key value of v, update
key value as a weight of u.v.
Example:
110
Step 1: Step 2: Step 3:
Step 4: Step 5:
111
SCHOOL OF COMPUTING
UNIT V
112
Divide and Conquer Strategy – Greedy Algorithm – Dynamic Programming – Backtracking
Strategy - List Searches using Linear Search - Binary Search - Fibonacci Search - Sorting Techniques
- Insertion sort - Heap sort - Bubble sort - Quick sort - Merge sort - Analysis of sorting techniques.
5.1 DIVIDE AND CONQUER STRATEGY
Divide and conquer is an algorithmic paradigm. A typical Divide and Conquer algorithm solves a
problem using following three steps:
1. Divide: This step involves breaking the problem into smaller sub-problems. Sub-problems should
represent a part of the original problem. This step generally takes a recursive approach to divide the
problem until no sub-problem is further divisible. At this stage, sub-problems become atomic in
nature but still represent some part of the actual problem.
2. Conquer: This step receives a lot of smaller sub-problems to be solved. Generally, at this level, the
problems are considered ‘solved’ on their own.
3. Merge/Combine: When the smaller sub-problems are solved, this stage recursively combines them
until they formulate a solution of the original problem. This algorithmic approach works recursively
and conquer & merge steps works so close that they appear as one.
The some examples of Divide and conquer problem based algorithms are
• Merge Sort
• Quick Sort
• Binary Search
• Master Theorem
• Fibonacci Search
• Strassen’s Matrix multiplication
• Karatsuba Algorithm
• The complexity for the multiplication of two matrices using the naïve method is O(n3), whereas
using the divide and conquer approach. This approach also simplifies other problems, such as
the Tower of Hanoi.
• This approach is suitable for multiprocessing systems.
• It makes efficient use of memory caches.
113
A greedy algorithm is an approach for solving a problem by selecting the best option
available at the moment, without worrying about the future result it would bring. In other words, the
locally best choices aim at producing globally best results. This algorithm may not be the best option
for all the problems. It may produce wrong results in some cases. This algorithm never goes back to
reverse the decision made.
A greedy algorithm is designed to achieve optimum solution for a given problem. In greedy
algorithm approach, decisions are made from the given solution domain. As being greedy, the closest
solution that seems to provide an optimum solution is chosen. Greedy algorithms try to find a
localized optimum solution, which may eventually lead to globally optimized solutions. However,
generally greedy algorithms do not provide globally optimized solutions. This algorithm works in a
top-down approach.
114
Dynamic programming approach is similar to divide and conquer in breaking down the problem into
smaller and yet smaller possible sub-problems. But, unlike, divide and conquer, these sub-problems
are not solved independently. Here the results of these smaller sub-problems are remembered and
used for similar or overlapping sub-problems.
In backtracking problem, the algorithm tries to find a sequence path to the solution which has some
small checkpoints from where the problem can backtrack if no feasible solution is found for the
problem.
Example:
115
Fig 5.1 Backtracking algorithm method
In fig 5.1, Green is the start point, blue is the intermediate point, red are points with no feasible
solution, dark green is end solution. Here, when the algorithm propagates to an end to check if it is
a solution or not, if it is then returns the solution otherwise backtracks to the point one step behind it
to find track to the next point to find solution.
Algorithm
Backtrack(x)
if x is not a solution
return false
if x is a new solution
backtrack(expand x)
Let’s use this backtracking problem to find the solution to N-Queen Problem.
In N-Queen problem, we are given an NxN chessboard and we have to place n queens on the board
in such a way that no two queens attack each other. A queen will attack another queen if it is placed
in horizontal, vertical or diagonal points in its way. Here, we will do 4-Queen problem is shown in
Fig 5.2.
116
Fig 5.2 N Queens Problem
Here, the binary output for n queen problem with 1’s as queens to the positions are placed.
{0 , 1 , 0 , 0}
{0 , 0 , 0 , 1}
{1 , 0 , 0 , 0}
{0 , 0 , 1 , 0}
For solving n queens problem, we will try placing queen into different positions of one row. And
checks if it clashes with other queens. If current positioning of queens if there are any two queens
attacking each other. If they are attacking, we will backtrack to previous location of the queen and
change its positions. And check clash of queen again.
A space state tree is a tree representing all the possible states (solution or non-solution) of the
problem from the root as an initial state to the leaf as a terminal state .
Linear search is the simplest method of searching. In this method, the element to be found
is sequentially searched in the list (Hence also called sequential search). This method can be applied
to a sorted or an unsorted list. Hence, it is used when the records are not stored in order.
117
Algorithm :
ALGORITHM LINEARSEARCH(K, N, X )
// K is the array containing the list of data items
// N is the number of data items in the list
// X is the data item to be searched
Repeat For I = 0 to N -1 Step 1
If K( I ) = X
Then
WRITE(“ELEMENT IS PRESENT AT LOCATION ” I)
RETURN
End If
End Repeat
WRITE(“ELEMENT NOT PRESENT IN THE COLLECTION”)
End LINEARSEARCH
In the above algorithm, K is the list of data items containing N data items. X is the data item,
which is to be searched in K. If the data item to be searched is found then the position where it is
found will be displayed. If the data item to be searched is not found then the appropriate message
will be displayed to indicate the user, that the data item is not found.
The data item X is compared with each and every element in the list K During this
comparison, if X matches with a data item in K, then the position where the data item was found will
gets displayed and the control comes out of the loop and the procedure comes to an end. If X does
not match with any of the data items in K, then finally the element not found will be displayed.
Example:
X → Number to be searched : 40
45 56 15 76 43 92 35 40 28 65
X K[0]
118
45 56 15 76 43 92 35 40 28 65
X K[1]
45 56 15 76 43 92 35 40 28 65
X K[2]
45 56 15 76 43 92 35 40 28 65
X K[3]
45 56 15 76 43 92 35 40 28 65
X K[4]
45 56 15 76 43 92 35 40 28 65
X K[5]
45 56 15 76 43 92 35 40 28 65
X K[6]
45 56 15 76 43 92 35 40 28 65
X = K[7] → I = 7 : Number found at location 7 i.e., as a 8th element
The search( ) function gets the number to be searched in the variable ‘x’ as a argument and compares
it with each and every element in the array K. If the number ‘x’ is found in the array, then the
position ‘i’, where it is found will gets printed. If the number is not found in the entire list, then the
function will display the “not found message” to the user.
In the main( ) function receives the n values from the user and stored in the array K. The user
is prompted to enter the number to be searched and is passed to the search( ) function as a argument.
The search which receives the value x will give the appropriate message.
Advantages:
1. Simple and straight forward method.
2. Can be applied on both sorted and unsorted list.
119
Disadvantages:
1. Inefficient when the number of data items in the list increases.
Analysis
Best Case:Ω(1)
Average Case:Ө(n)
Principle: The data item to be searched is compared with the approximate middle entry of the list.
If it matches with the middle entry, then the position will be displayed. If the data item to be searched
is lesser than the middle entry, then it is compared with the middle entry of the first half of the list
and procedure is repeated on the first half until the required item is found. If the data item is greater
than the middle entry, then it is compared with the middle entry of the second half of the list and
procedure is repeated on the second half until the required item is found. This process continues
until the desired number is found or the search interval becomes empty.
Algorithm:
ALGORITHM BINARYSEARCH(K, N, X)
// K is the array containing the list of data items
// N is the number of data items in the list
// X is the data item to be searched
Lower 0, Upper N – 1
While Lower Upper
Mid ( Lower + Upper ) / 2
If (X < K[Mid])Then
Upper Mid -1
Else If (X>K[Mid]) Then
Lower Mid + 1
Else
Write(“ELEMENT FOUND AT”, MID)
120
Quit
End If
End If
End While
Write(“ELEMENT NOT PRESENT IN THE COLLECTION”)
End BINARYSEARCH
In Binary Search algorithm given above, K is the list of data items containing N data items.
X is the data item, which is to be searched in K. If the data item to be searched is found then the
position where it is found will be printed. If the data item to be searched is not found then “Element
Not Found” message will be printed, which will indicate the user, that the data item is not found.
Initially lower is assumed 0 to point the first element in the list and upper is assumed as N-1
to point the last element in the list because the range of any array is 0 to N-1. The mid position of
the list is calculated by finding the average between lower and upper and X is compared with K[mid].
If X is found equal to K[mid] then the value mid will gets printed, the control comes out of the loop
and the procedure comes to an end. If X is found lesser than K[mid], then upper is assigned mid –
1, to search only in the first half of the list. If X is found greater than K[mid], then lower is assigned
mid + 1, to search only in the second half of the list. This process is continued until the element
searched is found or the collection becomes becomes empty.
Example:
X → Number to be searched : 40
U → Upper
L → Lower=N-1
M→ Mid
1 22 35 40 43 56 75 83 90 98
L=0 M = (0+9)/2 =4 U=9
X< K[4] → U = 4 – 1 = 3
1 22 35 40 43 56 75 83 90 98
L = 0 M = (0+3)/2=1 U = 3
X > K[1] → L = 1 + 1 = 2
121
1 22 35 40 43 56 75 83 90 98
L, M = 2 U = 3
K > A [2] → L = 2 + 1 = 3
1 22 35 40 43 56 75 83 90 98
L, M, U = 3
K = A[3] → P = 3 : Number found at position 3
The binarysearch( ) function gets the element to be searched in the variable X. Initially lower
is assigned 0 and upper is assumed N – 1. The mid position is calculated and if K[mid] is found
equal to X, then mid position will gets displayed. If X is less than K[mid] upper is assigned mid – 1
to search only in first half of the list else lower is assigned mid + 1 to search only in the second half
of the list. This is process is continued until lower is less than or equal to upper. If the element is
not found even after the loop is completed, then the Not Found Message will be displayed to the
user indicating that the element is not found.
Advantages:
1. Searches several times faster than the linear search.
2. In each iteration, it reduces the number of elements to be searched from n to n/2.
Disadvantages:
1. Binary search can be applied only on a sorted list.
Analysis of Binary Search
Bestcase :O(1)
Worst Case: O(log 2 𝑛)
Average Case: O(log 2 𝑛)
122
2. A Divide and Conquer Algorithm.
3. Has Log n time complexity.
Differences:
Algorithm:
1. Find the smallest Fibonacci Number greater than or equal to n. Let this number be fibM [m’th
Fibonacci Number]. Let the two Fibonacci numbers preceding it be fibMm1 [(m-1)’th
Fibonacci Number] and fibMm2 [(m-2)’th Fibonacci Number].
2. While the array has elements to be inspected:
1. Compare x with the last element of the range covered by fibMm2
2. If x matches, return index
3. Else if x is less than the element, move the three Fibonacci variables two Fibonacci down,
indicating elimination of approximately rear two-third of the remaining array.
4. Else x is greater than the element, move the three Fibonacci variables one Fibonacci down.
Reset offset to index. Together these indicate the elimination of approximately front one-third
of the remaining array.
3. Since there might be a single element remaining for comparison, check if fibMm1 is 1. If Yes,
compare x with that remaining element. If match, return index.
Analysis
123
• However, binary search involves division operation, where as in Fibonacci search only addition
and subtraction operation is involved. Average performance of Fibonacci search may be better
than binary search where division is more time consuming than addition or subtraction.
5.7 Sorting
Sorting is an operation of arranging data, in some given order, such as ascending or descending
with numerical data, or alphabetically with character data.
Let A be a list of n elements A1, A2,…An in memory. Sorting A refers to the operation of rearranging
the contents of A so that they are increasing in order (numerically or lexicographically), that is, A1
A2 A3 ….An
Sorting methods can be characterized into two broad categories:
• Internal Sorting
• External Sorting
Internal Sorting : Internal sorting methods are the methods that can be used when the list to be
sorted is small enough so that the entire sort can be carried out in main memory.
The key principle of internal sorting is that all the data items to be sorted are retained in the
main memory and random access in this memory space can be effectively used to sort the data items.
The various internal sorting methods are:
• Bubble Sort
• Selection Sort
• Insertion Sort
• Quick Sort
• Merge Sort
• Heap Sort
External Sorting : External sorting methods are the methods to be used when the list to be sorted
is large and cannot be accommodated entirely in the main memory. In this case some of the data is
present in the main memory and some is kept in auxiliary memory such as hard disk, floppy disk,
tape, etc.
Objectives involved in design of sorting algorithms.
The main objectives involved in the design of sorting algorithm are:
1. Minimum number of exchanges
2. Large volume of data block movement
This implies that the designed and desired sorting algorithm must employ minimum number of
exchanges and the data should be moved in large blocks, which in turn increase the efficiency of the
sorting algorithm.
124
5.7.1 INSERTION SORT
The main idea behind the insertion sort is to insert the ith element in its correct place in the ith
pass. Suppose an array K with n elements K[1], K[2],…K[N] is in memory. The insertion sort
algorithm scans K from K[0] to K[N-1], inserting each element K[I] into its proper position in the
previously sorted subarray K[0], K[1],..K[I-1].
Principle: In Insertion Sort algorithm, each element K[I] in the list is compared with all the elements
before it ( K[1] to K[I-1]). If any element K[J] is found to be greater than K[I] then K[J] is inserted
in the place of K[J}. This process is repeated till all the elements are sorted.
Algorithm:
ALGORITHM INSERTIONSORT(K, N)
// K is the array containing the list of data items
// N is the number of data items in the list
Repeat For I = 1 to N-1
Repeat For J = 0 to I – 1
If (K[I] < K[J])Then
Temp K[I]
Repeat For L = I-1 to J
K[L +1] K[L]
End Repeat
K[J] Temp
End If
End Repeat
End Repeat
End INSERTIONSORT
In Insertion Sort algorithm, N represents the total number of elements in the array K. I is
made to point to the second element in the list. In every pass the J is incremented to point to the next
element and is continued till it reaches the last element. During each pass K[I] is compared all
elements before it. If K[I] is lesser than K[J] in the list, then K[I] is inserted in position J. Finally,
a sorted list is obtained.
For performing the insertion operation, a variable temp is used to safely store K[I] in it and
then shift right elements starting from K[J] to K[I-1].
125
Example:
N = 10 → Number of elements in the list
L → Last
i=0 i =1 i=2 i=3 i=4 i=5 i=6 i=7 i=8 i=9
42 23 74 11 65 58 94 36 99 87
I=1 K[I] < K[0] → Insert K[I] at 0 L=9
23 42 74 11 65 58 94 36 99 87
I=2 L=9
K[I] is greater than all elements before it. Hence No Change
23 42 74 11 65 58 94 36 99 87
I=3 K[I] < K[0] → Insert K[I] at 0 L=9
11 23 42 74 65 58 94 36 99 87
I=4 L=9
K[I] < K[3] → Insert K[I] at 3
11 23 42 65 74 58 94 36 99 87
I=5 L=9
K[I] < K[3] → Insert K[I] at 3
11 23 42 58 65 74 94 36 99 87
I=6 L=9
K[I] is greater than all elements before it. Hence No Change
126
11 23 42 58 65 74 94 36 99 87
I=7 L=9
K[I] < K[2] → Insert K[I] at 2
11 23 36 42 58 65 74 94 99 87
I=8 L=9
K[I] is greater than all elements before it. Hence No Change
11 23 36 42 58 65 74 94 99 87
I, L=9
K[I] < K[7] → Insert K[I] at 7
Sorted List:
11 23 36 42 58 65 74 87 94 99
Advantages:
• Sorts the list faster when the list has less number of elements.
• Efficient in cases where a new element has to be inserted into a sorted list.
Disadvantages:
• Very slow for large values of n.
• Poor performance if the list is in almost reverse order.
127
Principle: A pivotal item near the middle of the list is chosen, and then items on either side are
moved so that the data items on one side of the pivot element are smaller than the pivot element,
whereas those on the other side are larger. The middle or the pivot element is now in its correct
position. This procedure is then applied recursively to the 2 parts of the list, on either side of the
pivot element, until the whole list is sorted.
Algorithm:
ALGORITHM QUICKSORT(K, Lower, Upper)
// K is the array containing the list of data items
// Lower is the lower bound of the array
// Upper is the upper bound of the array
If (Lower < Upper) Then
BEGIN
I Lower
J Upper
pivotK[Lower]
If (lower < Upper)
then
While (I < J)
Begin
While (K[I] <= pivot)
II+1
End While
While (K[J] > pivot)
JJ–1
End While
If (I < J)Then
K[I] K[J]
End If
End While
K[J] K[Lower]
128
QUICKSORT(K, Lower, J – 1)
QUICKSORT(K, J + 1, Upper)
End If
End QUICKSORT
In Quick sort algorithm, Lower points to the first element in the list and the Upper points to
the last element in the list. Now I is made to point to the next location of Lower and J is made to
point to the Upper. K[Lower] is considered as the pivot element and at the end of the pass, the
correct position of the pivot element will be decided. Keep on incrementing I and stop when K[I] >
Key. When I stops, start decrementing J and stop when K[J] < Key. Now check if I < J. If so, swap
K[I] and K[J] and continue moving I and J in the same way. When I meets J the control comes out
of the loop and K[J] and K[Lower] are swapped. Now the element at position J is at correct position
and hence split the list into two partitions: (K{Lower] to K[J-1] and K[J+1] to K[Upper] ). Apply
the Quick sort algorithm recursively on these individual lists. Finally, a sorted list is obtained.
Example:
42 23 74 11 65 58 94 36 99 87
L=0 I=0 U, J=9
Initially I=L+1 and J=U, Key=K[L]=42 is the pivot element.
42 23 74 11 65 58 94 36 99 87
L=0 I=2 J=7 U=9
K[2] > Key hence I stops at 2. K[7] < Key hence J stops at 7
Since I < J → Swap K[2] and A[7]
129
42 23 36 11 65 58 94 74 99 87
L=0 J=3 I=4 U=9
K[4] > Key hence I stops at 4. K[3] < Key hence J stops at 3
Since I > J → Swap K[3] and K[0]. Thus 42 go to correct position.
The list is partitioned into two lists as shown. The same process is applied to these lists individually
as shown.
List 1 → List 2 →
11 23 36 42 65 58 94 74 99 87
L=0, I=1 J,U=2
(applying quicksort to list 1)
11 23 36 42 65 58 94 74 99 87
L=0, I=1 U=2 J=0 Since I>0 K[L] &K[J] gets swapped i.e., K[0] gets swapped with same
element because L,J=0
11 23 36 42 65 58 94 74 99 87
L=4 J=5 I=6 U=9
(applying quicksort to list 2)
(after swapping 58 & 65)
11 23 36 42 58 65 94 74 99 87
L=6 I=8 U, J=9
11 23 36 42 58 65 94 74 87 99
L=6 J=8 U, I=9
11 23 36 42 58 65 87 74 94 99
L=6 U, I, J=7
Sorted List:
11 23 36 42 58 65 74 87 94 99
130
Advantages:
1. Faster than any other commonly used sorting algorithms.
2. It has a best average case behavior.
Disadvantages:
1. As it uses recursion, stack space consumption is high.
Principle: The given list is divided into two roughly equal parts called the left and the right subfiles.
These subfiles are sorted using the algorithm recursively and then the two subfiles are merged together
to obtain the sorted file. Given a sequence of N elements K[0],K[1] ….K[N-1], the general idea is to
imagine them split into various subtables of size is equal to 1. So each set will have a individually
sorted items with it, then the resulting sorted sequences are merged to produce a single sorted sequence
of N elements. Thus this sorting method follows Divide and Conquer strategy. The problem gets
divided into various subproblems and by providing the solutions to the subproblems the solution for the
original problem will be provided.
Algorithm:
131
LL+1
End If
End While
132
The first algorithm MERGE can be applied on two sorted lists to merge them. Initially, the
index variable I points to low and J points to mid + 1. K[I] is compared with K[J] and if K[I] found
to be lesser than K[J] then K[I] is stored in a temporary array and I is incremented otherwise K[J] is
stored in the temporary array and J is incremented. This comparison is continued till either I crosses
mid or J crosses high. If I crosses the mid first then that implies that all the elements in first list is
accommodated in the temporary array and hence the remaining elements in the second list can be
put into the temporary array as it is. If J crosses the high first then the remaining elements of first
list is put as it is in the temporary array. After this process we get a single sorted list. Since this
method merges 2 lists at a time, this is called 2-way merge sort.
In the MERGESORT algorithm, the given unsorted list is first split into N number of lists,
each list consisting of only 1 element. Then the MERGE algorithm is applied for first 2 lists to get
a single sorted list. Then the same thing is done on the next two lists and so on. This process is
continued till a single sorted list is obtained.
Example:
Let L → low, M→ mid, H → high
42 23 74 11 65 58 94 36 99 87
U M H
In each pass the mid value is calculated and based on that the list is split into two. This is done
recursively and at last N number of lists each having only one element is produced as shown.
Now merging operation is called on first two lists to produce a single sorted list, then the same
thing is done on the next two lists and so on. Finally a single sorted list is obtained.
133
5.7.4 HEAP SORT
Heap: A Heap is a compete binary tree with the property that the value at each node is at least as
large as the values of its children (if they exist). If the value at the parent node is larger than the
values on its children then it is called a Max heap and if the value at the parent node is smaller than
the values on its children then it is called the Min heap.
Heap Sort is the sorting technique based on the interpretation of the given sequence of
elements as a binary tree. For interpretation the principle given below has to be used.
➢ If a given node is in position I then the position of the left child and the right child can be calculated
using Left (L) = 2I and Right (R) = 2I + 1.
➢ To check whether the right child exists or not, use the condition R ≤ N. If true, Right child exists
otherwise not.
➢ The last node of the tree is N/2. After this position tree has only leaves.
Principle: The Max heap has the greatest element in the root. Hence the element in the root node is
pushed to the last position in the array and the remaining elements are converted into a max heap.
The root node of this new max heap will be the second largest element and hence pushed to the last
but one position in the array. This process is repeated till all the elements get sorted.
HEAPSORT ALGORITHM:
FUNCTION HEAPSORT()
BEGIN
CALL BUILDHEAP(A)
FOR I=HEAPSIZE DOWN TO 2
DO
(*SWAP BETWEEN A[1] AND A[I]*)
A[1]↔A[I]
134
HEAPSIZE=HEAPSIZE-1
CALL HEAPIFY(A,1)
END FOR
END FUNCTION HEAPSORT
FUNCTION BUILDHEAP(A)
BEGIN
N=HEAPSIZE
FOR I= N/2 DOWN TO 1 STEP -1
CALL HEAPIFY(A,I)
END FOR
END BUILDHEAP
FUNCTION HEAPIFY(A,I)
L=2 *I
R=L+1
IF L<=HEAPSIZE AND A[L]>A[I]
THEN
LARGE=L
ELSE
LARGE=I
END IF
IF R<=HEAPSIZE AND A[R]>A[LARGE]
THEN
LARGE=R
END IF
IF I<>LARGE
THEN
(*SWAP A[I] AND A[LARGE]*)
A[I] ↔A[LARGE]
135
CALL HEAPIFY(A,LARGE)
END IF
END HEAPIFY
Example:
Given a list A with 8 elements:
42 23 74 11 65 58 94 36
Phase 1:
The rearranged tree elements after the first phase is
Max heap is constructed.
136
Phase 2:
137
5.7.5 BUBBLE SORT
Bubble sort is a simple sorting algorithm where number of comparisons and number of swaps are
more.
Algorithm
Function Bubble sort( )
Read n
For I= 0 to n-1
Read a[I]
End for
//sort
For I=0 to n-2
For J=I+1 to n-1
If a[I]>a[J]
Then
T=a[I]
a[I]=a[J]
a[J]=T
138
End If
End For J
End For I
//print the sorted array
For I=0 to n-1
Write a[I]
End For
End bubble sort
Example:
N = 10 → Number of elements in the list
L → Points to last element ( Last )
Pass 1
42 23 74 11 65 58 94 36 99 87
Out of order → Swap L=9
23 42 74 11 65 58 94 36 99 87
Out of order → Swap L=9
23 42 11 74 65 58 94 36 99 87
Out of order → Swap L=9
23 42 11 65 74 58 94 36 99 87
Out of order → Swap L=9
23 42 11 65 58 74 94 36 99 87
Out of order → Swap L=9
139
23 42 11 65 58 74 36 94 99 87
Out of order → Swap L=9
Pass 2
23 42 11 65 58 74 36 94 87 99
Out of order → Swap L=8
23 11 42 65 58 74 36 94 87 99
Out of order → Swap L=8
23 11 42 58 65 74 36 94 87 99
Out of order → Swap L=8
23 11 42 58 65 36 74 94 87 99
Out of order → Swap L=8
Pass 3
23 11 42 58 65 36 74 87 94 99
Out of order → Swap L=7
23 11 42 58 65 36 74 87 94 99
Out of order → Swap L=7
Pass 4
23 11 42 58 36 65 74 87 94 99
140
Out of order → Swap L=6
11 23 42 58 36 65 74 87 94 99
Out of order → Swap L=6
Pass 5
11 23 42 36 58 65 74 87 94 99
Out of order → Swap L=5
Pass 6
Adjacent numbers are compared up to L=4. But no swapping takes place. As there was no swapping
taken place in this pass, the procedure comes to an end and we get a sorted list:
11 23 36 42 58 65 74 87 94 99
Advantages:
1. Simple and works well for list with less number of elements.
Disadvantages:
1. Inefficient when the list has large number of elements.
Requires more number of exchanges for every pass.
141
QUICK SORT DIVIDE AND CONQUER O(n log n)
TECHNIQUE
MERGE SORT DIVIDE AND CONQUER O(n log n)
TECHNIQUE
HEAP SORT TREE SORTING (selection O(n log n)
technique)
SELECTION SORT SELECTION O(n2)
142