Unit 2 Notes DSA
Unit 2 Notes DSA
Arrays as ADT
The array is a basic abstract data type that holds an ordered collection of items accessible by an
integer index. These items can be anything from primitive types such as integers to more omplex
types like instances of classes. Since it's an ADT, it doesn't specify an implementation, but is
almost always implemented by an array (data structure) or dynamic array.
Arrays have one property: they store and retrieve items using an integer index. An item is stored
in a given index and can be retrieved at a later time by specifying the same index. The way these
indices work is specific to the implementation, but you can usually just think of them as the slot
number in the array that the value occupies.
Bubble Sort
Following are the steps involved in bubble sort(for sorting a given array in ascending order):
1. Starting with the first element(index = 0), compare the current element with the next
element of the array.
2. If the current element is greater than the next element of the array, swap them.
3. If the current element is less than the next element, move to the next element. Repeat
Step 1.
bubbleSort(arr[], n)
{
arr[]: array of n elements
flag=0
for(i = 0; i < n; i++)
{
for(j = 0; j < n-i-1; j++)
{
if( arr[j] > arr[j+1])
{
swap the elements (arr[j], arr[j+1])
flag=1
}
}
if(flag==0)
break
}
}
Binary Search
1. If the size of the list is 0, we stop the process and conclude that the target element is not
present in the array
2. Else, we compare the target and the middle element of the list
3. If the target is equal to the middle element of the list, we return the position of the middle
element as the answer
4. Else, if the target is greater than the middle element of the list, we search in the right
sublist that starts just after the middle element and discard the left subilst completely.
5. Else, the target must be present in the left sublist (or target is not present at all);
so, we search in the left sublist that ends just before mid and discard the right sublist.
Recursive Implementation
function recursive_binary_search(A, low, high, target)
if low > high then
return -1
mid := (low + high) / 2
if target = A[mid] then
return mid
else if target > A[mid] then
return recursive_binary_search(A, mid + 1, high, target)
else:
return recursive_binary_search(A, low, mid - 1, target)
Iterative Implementation
STACKS
A stack is a non-primitive linear data structure. It is an ordered list in which addition of new data
item and deletion of already existing data item is done from only one end, known as Top of Stack
(TOS). As all the deletion and insertion in a stack is done from top of the stack, the last added
element will be the first to be removed from the stack. Due to this reason, the stack is also called
Last-In-First-Out (LIFO) type of list. Consider some examples,
• A common model of a stack is plates in a marriage party. Fresh plates are “pushed” onto
the top and “popped” off the top.
• Some of you may eat biscuits. If you assume only one side of the cover is torn and biscuits
are taken off one by one. This is called popping and similarly, if you want to preserve some
biscuits for some time later, you will put them back into the pack through the same torn
end called pushing.
Whenever, a stack is created, the stack base remains fixed, as a new element is added to the stack
from the top, the top goes on increasing, conversely as the top most element of the stack is removed
the stack top is decrementing.
Applications
• Following are some of the applications in which stacks play an important role.
• Direct applications
– Balancing of symbols
– Infix-to-postfix conversion
– Evaluation of postfix expression
– Implementing function calls (including recursion)
– Page-visited history in a Web browser [Back Buttons]
– Undo sequence in a text editor
– Matching Tags in HTML and XML
SEQUENTIAL IMPLEMENTATION OF STACKS
Stack can be implemented in two ways :
(a) Static implementation
(b) Dynamic implementation
Static implementation
Static implementation uses arrays to create stack. Static implementation is a very simple
technique, but is not a flexible way of creation, as the size of stack has to be declared during
program design, after that the size cannot be varied. Moreover, static implementation is not too
efficient w.r.t. memory utilization. As the declaration of array (for implementing stack) is done
before the start of the operation (at program design time), now if there are too few elements to be
stored in the stack the statically allocated memory will be wasted, on the other hand if there are
more number of elements to be stored in the stack then we can’t be able to change the size of array
to increase its capacity, so that it can accommodate new elements.
Dynamic implementation
As in static implementation, we have used arrays to store the elements that get added to the tack.
However, implemented as an array it suffers from the basic limitation of array-that its size cannot
be increased or decreased one it is declared. As a result, one ends up reserving either too much
space or too less space for an array and in turn for a stack. This problem can be overcome if we
implement a stack using a linked list. In case of a linked list we shall push and pop nodes from one
end of a linked list. Linked list representation is commonly known as Dynamic implementation
and uses pointers to implement the stack type of data structure. The stack as linked list is
represented as a singly connected list. Each node in the linked list contains the data and a pointer
that gives location of the next node in the list. The node in the list is a structure as shown below:
struct node
{
<data type> data;
node *link;
};
where <data type> indicates that the data can be of any type like int, float, char etc, and link, is a
pointer to the next node in the list. The pointer to the beginning of the list serves the purpose of
the top of the stack. Fig. (1) shows the linked list representation of a stack
OPERATIONS ON STACK
The basic operations that can be performed on stack are as follows :
1. PUSH : The process of adding a new element to the top of the stack is called PUSH operation.
Pushing an element in the stack involve adding of element, as the new element will be inserted at
the top, so after every push operation, the top is incremented by one. In case the array is full and
no new element can be accommodated, it is called STACK-FULL condition. This condition is
called STACK OVERFLOW.
2. POP : The process of deleting an element from the top of the stack is called POP operation.
After every pop operation, the stack is decremented by one. If there is no element on the stack and
the pop is performed then this will result into STACK UNDERFLOW condition.
ALGORITHMS FOR PUSH & POP FOR STATIC IMPLEMENTATION USING
ARRAYS
(i) Algorithm for inserting an item into the stack (PUSH)
Let STACK[MAXSIZE] is an array for implementing the stack, MAXSIZE represents the max.
size of array STACK. NUM is the element to be pushed in stack & TOP is the index number
of the element at the top of stack.
Step 1 : [Check for stack overflow ? ]
If TOP = MAXSIZE – 1, then :
Write : ‘Stack Overflow’ and return.
[End of If Structure]
Step 2 : Read NUM to be pushed in stack.
Step 3 : Set TOP = TOP + 1 [Increases TOP by 1]
Step 4 : Set STACK[TOP] = NUM [Inserts new number NUM in new TOP Position]
Step 5 : Exit
A ( A
+ (+ A
( (+( A
B (+( AB
* (+(* AB
C (+(* ABC
) ABC*+
Evaluation of a Postfix Expression
The following algorithm is used to evaluate the value of a postfix expression.
1. Add a ) at the end of the post fix expression
2. Scan every character of the postfix expression and repeat Steps 3 and 4 until ) is
encountered
3. If an operand is encountered, out it on the STACK.
4. If an operator O is encountered, then
1. POP the two top elements of STACK as A(topmost element) and B(next-to-top
element).
2. Evaluate B O A.
3. Push the result of evaluation on the STACK.
5. SET RESULT equal to the topmost element of the STACK.
Example
Consider the following postfix notation
823*8+2/–
. The equivalent infix expression is
8 – ((2 * 3) + 8) / 2
The following table shows the procedure for evaluating the expression by simulating the above
algorithm.
8 8
2 8, 2
3 8, 2, 3
Symbol Scanned STACK
* 8, 6
8 8, 6, 8
+ 8, 14
2 8, 14, 2
/ 8, 7
– 1
The final number in the stack, 1, is the value of the postfix expression.
Tower of Hanoi
Tower of Hanoi, is a mathematical puzzle which consists of three towers (pegs) and more than
one rings is as depicted −
These rings are of different sizes and stacked upon in an ascending order, i.e. the smaller one sits
over the larger one. There are other variations of the puzzle where the number of disks increase,
but the tower count remains the same.
Rules
The mission is to move all the disks to some another tower without violating the sequence of
arrangement. A few rules to be followed for Tower of Hanoi are −
• 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.
Algorithm
To write an algorithm for Tower of Hanoi, first we need to learn how to solve this problem with
lesser amount of disks, say → 1 or 2. We mark three towers with
name, source, destination and aux (only to help moving the disks). If we have only one disk,
then it can easily be moved from source to destination peg.
If we have 2 disks −
So now, we are in a position to design an algorithm for Tower of Hanoi with more than two
disks. We divide the stack of disks in two parts. The largest disk (nth disk) is in one part and all
other (n-1) disks are in the second part. Our ultimate aim is to move disk n from source to
destination and then put all other (n1) disks onto it. We can imagine to apply the same in a
recursive way for all given set of disks.
START
Procedure Hanoi(disk, source, dest, aux)
IF disk == 1, THEN
move disk from source to dest
ELSE
Hanoi(disk - 1, source, aux, dest) // Step 1
move disk from source to dest // Step 2
Hanoi(disk - 1, aux, dest, source) // Step 3
END IF
END Procedure
STOP
Queue
Queue is a non-primitive linear data structure that permits insertion of an element at one end and
deletion of an element at the other end. The end at which the deletion of an element take place is
called front, and the end at which insertion of a new element can take place is called rear. The
deletion or insertion of elements can take place only at the front and rear end of the list respectively.
The first element that gets added into the queue is the first one to get removed from the list. Hence,
Queue is also referred to as First-In-First-Out (FIFO) list. The name ‘Queue’ comes from the
everyday use of the term. Consider a railway reservation booth, at which we have to get into the
reservation queue. New customers got into the queue from the rear end, whereas the customers
who get their seats reserved leave the queue from the front end. It means the customers are serviced
in the order in which they arrive the service center (i.e. first come first serve type of service). The
same characteristics apply to our Queue.
Sequential implementation of Linear queues
Queues can be implemented in two ways:
1.Static implementation (using arrays)
2. Dynamic implementation (using pointers)
Static implementation:
Static implementation of Queue is represented by arrays. If Queue is implemented using arrays,
we must be sure about the exact number of elements we want to store in the queue, because we
have to declare the size of the array at design time or before the processing starts. In this case, the
beginning of the array will become the front for the queue and the last location of the array will
act as rear for the queue.
The following relation gives the total number of elements present in the queue, when implemented
using array :
rear – front + 1
Also note that if front > rear, then there will be no element in the queue or queue is empty.
OPERATIONS ON A QUEUE
The basic operations that can be performed on queue are:
1. To Insert an element in a Queue
2. To Delete an element from a Queue.
3. To Traverse all elements of a Queue.
ALGORITHMS & FUNCTIONS FOR INSERTION AND DELETION IN A LINEAR
QUEUE (USING ARRAYS)
(1) Algorithm for Insertion in a Linear Queue
Let QUEUE[MAXSIZE] is an array for implementing the Linear Queue & NUM is the element to
be inserted in linear queue, FRONT represents the index number of the element at the beginning
of the queue and REAR represents the index number of the element at the end of the Queue.
Step 1 :If REAR = (MAXSIZE –1) : then
Write : “Queue Overflow” and return
[End of If structure]
Step 2 : Read NUM to be inserted in Linear Queue.
Step 3 : Set REAR := REAR + 1
Step 4 : Set QUEUE[REAR] := NUM
Step 5 : If FRONT = –1 : then
Set FRONT=0.
[End of If structure]
Step 6 : Exit
CIRCULAR QUEUES
The queue that we implemented using an array suffers from one limitation. In that implementation
there is a possibility that the queue is reported as full (since rear has reached the end of the array),
even though in actuality there might be empty slots at the beginning of the queue. To overcome
this limitation, we can implement the queue as a circular queue. Here as we go on adding elements
to the queue and reach the end of the array, the next element is stored in the first slot the array
(provided it is free). Suppose an array arr of n elements is used to implement a circular queue we
may reach arr[n-1]. We cannot add any more elements to the queue since we have reached at the
end of the array. Instead of reporting the queue as full, if some elements in the queue have been
deleted then there might be empty slots at the beginning of the queue. In such a case these slots
would be filled by new elements being added to the queue. In short just because we have reached
the end of the array, the queue would not be reported as full. The queue would be reported as full
only when all the slots in the array stand occupied.
Algorithm for Insertion in a Circular Queue
Let CQUEUE[MAXSIZE] is an array for implementing the Circular Queue, where MAXSIZE
represents the max. size of array. NUM is the element to be inserted in circular queue, FRONT
represents the index number of the element at the beginning of the queue and REAR represents
the index number of the element at the end of the Queue.
PRIORITY QUEUE
A priority queue is a collection of elements where the elements are stored according to their
priority levels. The order in which the elements get added or removed is decided by the priority of
the element.
Following rules are applied to maintain a priority queue :
(1) The element with a higher priority is processed before any element of lower priority.
(2) If there are elements with the same priority, then the element added first in the queue would
get processed.
Priority queues are used for implementing job scheduling by the operating system where jobs with
higher priorities are to be processed first. Another application of Priority queues is simulation
systems where priority corresponds to event times.
There are mainly two ways of maintaining a priority queue in memory. One uses a oneway list,
and the other uses multiple queues. The ease or difficultly in adding elements to or deleting them
from a priority queue clearly depends on the representation that one chooses.
Priority queues will operate in the usual way : the lower the priority number, the higher the priority.
Out of these two ways of representing a Priority Queue, the array representation of a priority queue
is more time-efficient than the one way list. This is because when adding an element to a one-way
list, one must perform a linear search on the list. On the other hand, the one-way list representation
of the priority queue may be more space-efficient than the array representation. This is because in
using the array representation overflow occurs when the number of elements in any single priority
level exceeds the capacity for that level, but in using the one-way list, overflow occurs only when
the total number of elements exceeds the total capacity. Another alternative is to use a linked list
for each priority level.
Though the insertion and deletion in a deque can be performed on both ends, it does not follow the
FIFO rule. The representation of a deque is given as follows -
Types of deque
There are two types of deque -
o Input restricted queue
o Output restricted queue
Input restricted Queue
In input restricted queue, insertion operation can be performed at only one end, while deletion can
be performed from both ends.
In output restricted queue, deletion operation can be performed at only one end, while insertion
can be performed from both ends.
APPLICATIONS OF QUEUES :
1. Round Robin technique for processor scheduling is implemented using queues.
2. All types of customer service (like railway ticket reservation ) center software’s are designed
using queues to store customers information. Printer server routines are designed using queues. A
number of users share a printer using printer server ( a dedicated computer to which a printer is
connected), the printer server then spools all the jobs from all the users, to the server’s hard disk
in a queue. From here jobs are printed one-by-one according to their number in the queue.