UNIT 2
Stacks: Abstract Data Type, Primitive Stack operations: Push &
Pop, Array and Linked Implementation of Stack in C, Application of
stack: Prefix and Postfix Expressions, Evaluation of postfix
expression, Iteration and Recursion- Principles of recursion, Tail
recursion, Removal of recursion Problem solving using iteration and
recursion with examples such as binary search, Fibonacci numbers,
and Hanoi towers. Queues: Operations on Queue: Create, Add,
Delete, Full and Empty, Circular queues, Array and linked
implementation of queues in C, Dequeue and Priority Queue.
Searching: Concept of Searching, Sequential search, Index
Sequential Search, Binary Search. Concept of Hashing & Collision
resolution Techniques used in Hashing.
STACK
A Stack is a list of elements in which an element may be inserted or deleted
only at one end , called the top of the stack. This means, in particular, that
elements are removed from a stack in the reverse order of that in which they
were inserted into the stack.
Special terminology is used for two basic operations associated with stacks:
a. “PUSH” is the term used to insert an element into a stack.
b. “POP” is the term used to delete an element from a stack.
void push (int val,int n) //n is size of the stack
{
if (top == n )
printf("\n Overflow");
else
{
top = top +1;
stack[top] = val;
}
}
int pop ()
{
if(top == -1)
{
printf("Underflow");
return 0;
}
else
{
return stack[top - - ];
}
}
int peek()
{
if (top == -1)
{
printf("Underflow");
return 0;
}
else
{
return stack [top];
}
}
push();
#include <stdio.h> break;
int stack[100],i,j,choice=0,n,top=-1; }
void push(); case 2:
void pop(); {
void show(); pop();
void main () break;
{ }
case 3:
printf("Enter the number of elements in the stack "); {
scanf("%d",&n); show();
printf("*********Stack operations using array*********"); break;
}
printf("\n----------------------------------------------\n"); case 4:
while(choice != 4) {
{ printf("Exiting....");
printf("Chose one from the below options...\n"); break;
printf("\n1.Push\n2.Pop\n3.Show\n4.Exit"); }
printf("\n Enter your choice \n"); default:
scanf("%d",&choice); {
switch(choice) printf("Please Enter valid choice ");
{ }
case 1: }}}
{
void push () void pop ()
{ { void show()
int val; if(top == -1) {
if (top == n ) printf("Underflow"); for (i=top;i>=0;i--)
printf("\n Overflow"); else {
else top = top -1; printf("%d\n",stack[i]);
{ } }
printf("Enter the value?");
if(top == -1)
scanf("%d",&val);
{
top = top +1;
printf("Stack is empty");
stack[top] = val;
}
}
}
}
LINKED REPRESENTATION OF STACK
PUSH_LINKSTACK(INFO,LINK,TOP,AVAIL,ITEM)
This procedure pushes an item into a linked stack.
STEP 1 : If AVAIL= NULL, then write OVERFLOW and Exit
STEP 2 : [Remove first node from Avail List]
Set NEW:= AVAIL and AVAIL:= LINK[AVAIL].
STEP 3: Set INFO[NEW]:= ITEM ( Copies item in to a new node)
STEP 4: Set LINK[NEW] := TOP [ New node points to the original
top node of the stack]
STEP 5: Set TOP= NEW [reset TOP to point to the new node at the
top of the stack]
Step 6: EXIT
LINKED REPRESENTATION OF STACK
POP_LINKSTACK(INFO,LINK,TOP,AVAIL,ITEM)
This procedure deletes the top element of a linked stack and assigns
it to the variable ITEM.
STEP 1 : IF TOP= NULL then Write: UNDERFLOW and Exit
STEP 2 : Set ITEM:= INFO[TOP] [copies the top element of stack
into ITEM]
STEP 3: Set TEMP:= TOP and TOP:= LINK[TOP]
[Remember the old value of the TOP pointer in TEMP
and reset TOP to point to the next element in the stack]
STEP 4: FREE TEMP
STEP 5: EXIT
LEVEL of PRECEDENCE for binary operations
Highest : Exponentiation( )
Next Highest: Multiplication ( *) and Division ( /)
Lowest: Addition (+ ) and Subtraction(-)
TRANSFORMING INFIX EXPRESSION TO POSTFIX EXPRESSION
1. K + L - M*N + (O^P) * W/U/V * T + Q
2. a+b*c-(d/e+f*g*h)
TRANSFORMING INFIX EXPRESSION TO
PREFIX EXPRESSION
Iterate the given expression from left to right, one character at a time
Step 1: Reverse the infix expression. Note while reversing each ‘(‘
will become ‘)’ and each ‘)’ becomes ‘(‘.
Step 2: Convert the reversed infix expression to “nearly” postfix
expression. While converting to postfix expression, instead of
using pop operation to pop operators with greater than or equal
precedence, here we will only pop the operators from stack that
have greater precedence.
Step 3: Reverse the postfix expression.
1. K + L - M*N + (O^P) * W/U/V * T + Q
2. a+b*c-(d/e+f*g*h)
RECURSION
Sometimes a problem is too difficult or too complex to solve because
it is too big. If the problem can be broken down into smaller versions
of itself, we may be able to find a way to solve one of these smaller
versions and then be able to build up to a solution to the entire
problem. This is the idea behind recursion; recursive algorithms
break down a problem into smaller pieces which you either already
know the answer to, or can solve by applying the same algorithm to
each piece, and then combining the results.
P is called a recursive procedure if P is a procedure containing either a call
statement to itself or a call statement to second procedure that may
eventually result in a call statement back to the original procedure P. So that
a program will not continue to run indefinitely , a recursive procedure must
have the following two properties :
i. There must be certain criteria , called the base criteria , for which the
procedure does not call itself.
ii. Each time the procedure does call itself (directly or indirectly) , it must be
closer to the base criteria.
A recursive procedure with these two properties is said to be well defined.
Recursion and Iteration
• Both repeatedly execute the set of instructions.
• Recursion occurs when a statement in a function calls itself repeatedly.
• The iteration occurs when a loop repeatedly executes until the
controlling condition becomes false.
The basic difference between recursion and iteration is
that recursion is a process always applied to a function
and iteration is applied to the set of instructions which we want to be
executed repeatedly.
Recursion Iteration
• Recursion uses the selection structure. • Iteration uses the repetition structure.
• Infinite recursion occurs if the step in recursion doesn't
reduce the problem to a smaller problem. It also
• An infinite loop occurs when the condition in the loop
becomes infinite recursion if it doesn't convert on a
doesn't become False ever.
specific condition. This specific condition is known as
the base case.
• The system crashes when infinite recursion is • Iteration uses the CPU cycles again and again when an
encountered. infinite loop occurs.
• Recursion terminates when the base case is met. • Iteration terminates when the condition in the loop fails.
• Recursion is slower than iteration since it has the • Iteration is quick in comparison to recursion. It doesn't
overhead of maintaining and updating the stack. utilize the stack.
• Recursion uses more memory in comparison to iteration. • Iteration uses less memory in comparison to recursion.
• Recursion reduces the size of the code. • Iteration increases the size of the code.
Tail Recursion
The tail recursion is basically using the recursive function as the last
statement of the function. So when nothing is left to do after coming back
from the recursive call, that is called tail recursion.
#include <stdio.h>
void printN(int n){ int main() {
if(n < 0){
printN(10);
return;
} }
printf(“\n %d”,n);
printN(n - 1);
}
The tail recursion is better than non-tail recursion. As there is no task left
after the recursive call, it will be easier for the compiler to optimize the
code. When one function is called, its address is stored inside the stack. So
if it is tail recursion, then storing addresses into stack is not needed.
long fact(long n, long a)
{
if(n == 0)
return a;
return fact(n-1, a*n);
}
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.
Tower of Hanoi puzzle with n disks can be solved in
minimum 2n−1 steps.
Let's go through each of the steps:
Move the first disk from A to C.
Move the first disk from A to B.
Move the first disk from C to B.
Move the first disk from A to C.
Move the first disk from B to A.
Move the first disk from B to C.
Move the first disk from A to C.
The steps to follow are −
Step 1 − Move n-1 disks from source to aux
Step 2 − Move nth disk from source to dest
Step 3 − Move n-1 disks from aux to dest
ALGORITHM
TOWER(N,BEG,AUX,END)
This procedure gives a recursive solution to the tower of Hanoi problem
for N disks.
Step 1: If N=1,then:
a. Write BEG->END
b. Return.
[End of If Structure.]
Step 2: [Move N-1 disks from peg BEG to Peg AUX.]
Call TOWER(N-1,BEG,END,AUX)
Step 3: Write: BEG->END
Step 4: [Move N-1 disks from peg AUX to peg END.]
Call Tower (N-1,AUX,BEG,END).
Step 5: Return.
Binary Search is a search algorithm that is used to find the position of an element
(target value ) in a sorted array. The array should be sorted prior to applying a
binary search.
Binary search is also known by these names, logarithmic search, binary chop, half
interval search.
Working
The binary search algorithm works by comparing the element to be searched by
the middle element of the array and based on this comparison follows the required
procedure.
Case 1 − element = middle, the element is found return the index.
Case 2 − element > middle, search for the element in the sub-array starting from
middle+1 index to n.
Case 3 − element < middle, search for element in the sub-array starting from 0
index to middle -1.
ALGORITHM
Parameters inital_value , end_value
Step 1 : Find the middle element of array. using ,
middle = (initial_value + end_value )/ 2 ;
Step 2 : If middle = element, return ‘element found’ and index.
Step 3 : if middle > element, call the function with end_value = middle
-1.
Step 4 : if middle < element, call the function with start_value = middle
+1.
Step 5 : exit.
PROGRAM TO IMPLEMENT BINARY SEARCH USING ITERATIVE
CALL
#include <stdio.h> int main(void){
int iterativeBinarySearch(int array[], int start_index, int int array[] = {1, 4, 7, 9, 16, 56, 70};
end_index, int element){ int n = 7;
while (start_index <= end_index){ int element = 16;
int middle = (start_index + end_index)/2; int found_index = iterativeBinarySearch(array, 0, n-1,
if (array[middle] == element) element);
return middle; if(found_index == -1 ) {
if (array[middle] < element) printf("Element not found in the array ");
start_index = middle + 1; }
else else {
end_index = middle - 1; printf("Element found at index : %d",found_index);
} }
return -1; return 0;
} }
PROGRAM TO IMPLEMENT BINARY SEARCH USING RECURSIVE CALL
#include <stdio.h>
int recursiveBinarySearch(int array[], int start_index, int end_index, int element)
{
if (start_index <= end_index){
int middle = (start_index + end_index )/2;
if (array[middle] == element)
return middle;
if (array[middle] > element)
return recursiveBinarySearch(array, start_index, middle-1, element);
return recursiveBinarySearch(array, middle+1, end_index, element);
}
return -1;
} if(found_index == -1 ) {
printf("Element not found in the array ");
int main(void){ }
int array[] = {1, 4, 7, 9, 16, 56, 70}; else {
int n = 7; printf("Element found at index : %d",found_index);
int element = 9; }
int found_index = recursiveBinarySearch(array, 0, n-1, element); return 0;
}
Algorithm to insert an element in a QUEUE
Step1: If REAR = MAX -1
Write OVERFLOW
Exit.
[End of IF]
Step 2: If FRONT =-1 and REAR =-1
SET FRONT= REAR =0
Else
SET REAR=REAR+1
[End of IF]
Step 3: Set QUEUE[REAR] =NUM
Step 4 : Exit
void insert (int queue[], int max, int front, int rear, int item)
{
if (rear== max-1)
{
printf("overflow");
}
else
{
if(front == -1 && rear == -1)
{
front = 0;
rear = 0;
}
else
{
rear = rear + 1;
}
queue[rear]=item;
}
}
Algorithm to delete an element in a QUEUE
Step1: If FRONT = -1 OR FRONT >REAR
Write UNDERFLOW
Else
SET VAL = QUEUE[FRONT]
SET FRONT = FRONT +1
[End of IF]
Step 2 : Exit
int delete (int queue[], int max, int front, int rear)
{
int y;
if (front == -1 || front > rear)
{
printf("underflow");
}
else
{
y = queue[front];
if(front == rear)
{
front = rear = -1;
else
front = front + 1;
}
return y;
}
}
LINKED REPRESENTATION OF QUEUE
QINSERT(QUEUE,N,FRONT,REAR,ITEM)
This procedure insert an item into a linked queue.
STEP 1 : If AVAIL= NULL, then write OVERFLOW and Exit
STEP 2 : [Remove first node from Avail List]
Set NEW:= AVAIL and AVAIL:= LINK[AVAIL].
STEP 3: Set INFO[NEW]:= ITEM ( Copies item in to a new node)
STEP 4: IF FRONT= NULL
Set FRONT= REAR= NEW
Set LINK[FRONT]=LINK[REAR]=NULL
Else
SET LINK[REAR]= NEW
Set REAR=NEW
Set LINK[REAR]= NULL
[End of IF]
Step 5: EXIT
LINKED REPRESENTATION OF QUEUE
QDELETE(QUEUE,N,FRONT,REAR,ITEM)
This procedure delete an item from a linked queue and assign it to
variable ITEM.
STEP 1 : IF FRONT= NULL
then Write : UNDERFLOW and EXIT
STEP 2: Set ITEM := INFO[FRONT]
STEP 3: Set FRONT=LINK[FRONT]
STEP 4: FREE ITEM.
STEP 5: EXIT
Why Was the Concept of Circular Queue Introduced?
Implementation of a linear queue brings the drawback of memory wastage.
However, memory is a crucial resource that you should always protect by
analyzing all the implications while designing algorithms or solutions. In
the case of a linear queue, when the rear pointer reaches the MaxSize of a
queue, there might be a possibility that after a certain number of dequeue()
operations, it will create an empty space at the start of a queue.
Algorithm to insert an element in a CIRCULAR
QUEUE
Step1: If ((FRONT=0 and REAR = MAX -1) OR (FRONT=REAR+1))
Write OVERFLOW
Exit. Step 3: Set QUEUE[REAR] =NUM
[End of IF]
Step 2: If FRONT =-1 and REAR =-1 Step 4 : Exit
SET FRONT= REAR =0
Else IF REAR=MAX-1 and FRONT!=0
SET REAR=0
Else
SET REAR=REAR+1
[End of IF]
Algorithm to delete an element in a CIRCULAR
QUEUE
Step1: If FRONT = -1
Write UNDERFLOW Step 4 : Exit
EXIT
Step 2: Set VAL= QUEUE[FRONT]
Step 3: IF FRONT=REAR
Set FRONT=REAR=-1
Else
IF FRONT=MAX-1
SET FRONT=0
Else
SET FRONT = FRONT +1
[End of IF]
[End of IF]
DEQUES
It is a list in which the elements can be inserted or deleted at either end. It is
also known as head tail linked list because elements can be added to or
removed from either the front(Head) or the back (tail) end. However no
element can be added and deleted from the middle. In computer’s memory
deque is implemented using either a circular array or circular linked list.
There are two variants of a double ended queue. They include
• Input restricted deque: Insertions can be done only at one end and
deletion can be done from both ends.
• Output Restricted deque : Deletion can be done only at one end while
insertions can be done on both ends.
PRIORITY QUEUE
It is a data structure in which each element is assigned a priority. The
priority of the element will be used to determine the order in which the
elements will be processed. General Rules are:
1. An element with higher priority is processed before an element with a
lower priority
2. Two elements with the same priority are processed on a first come first
serve basis.
Implementation of a Priority Queue
• Linked Representation- info, priority and address
• Array Representation- Separate queue for each priority number is maintained. Each
of these queues will be implemented using circular arrays or circular queues.
Every individual queue will have its own FRONT and REAR. 2-dimensional array
is used for this purpose. Front[K] and REAR[K] contain the front and rear values of
row K, where K is the priority number.
Insertion: To insert a new element with priority K in
the priority queue, add the element at the rear end of
row k where k is the row number as well as the
priority number of that element.
Deletion: To delete an element , we find the first non-
empty queue and then process the front element of the
first non empty queue. In technical terms , find the
element with the smallest K, such that FRONT[K]!=
NULL.
Hashing
Hashing
Hashing
if there are four elements 3, 5, 7, 2. Then in order to search any of these, we can
take array of size 7 and can search in O(1) constant time
Hashing
Hashing
The above elements are mapped using hash function H(x) = H(x) mod 5
Suppose we want to search a topic hashing in a Data Structure Book. Then, instead of
using linear search or binary search technique, we can directly use the help of the
index page and can see its exact page number and search this in O(1) time.
Definition of Hashing
• The process of transforming an
element into a secret element
using a hash code is known as
hashing.
• The mathematical function used
for transforming an element into
a mapped one or to secret code is
known as a Hash Function.
Hashing Functions
Modulo Method (Division Modulo) (Division Reminder method)
This method computes hash code using the division method. The simple formula for
calculating hash code is given by
Hash Code(key) = key mod m
The number m is usually chosen to be a prime number to avoid collisions.
Input elements as 35, 44, 22, 19, 11, 20, 43, 6, 88, 27
Hash code(35) = 35 mod 7 = 0,
Hash code(44) = 44 mod 7 = 2
0 1 2 3 4 5 6 7 8 9
35 22 44 11 19 6 20
Hashing Functions
Consider a Hash Table of Size 100,
The Hash code for 123,223,323,423
123 mod 100 =3
223 mod 100 =3
323 mod 100 =3
423 mod 100 =3
We cannot store these keys at the same location in
the Hash Table
WHAT CAN BE DONE IN SUCH CASE??
Hashing Functions
Mid Square Method
Step 1: Square the value of the key. That is, find k2 .
Step 2: Extract the middle r digits of the result obtained in Step 1.
Key 104 Key 4012
Key2 10816 Key2 16096144
H(K) 10816 H(K) 16096144
Calculate the hash value for keys 1234 and 5642 using the mid
square method .The hash table has 100 locations.
Hashing Functions
Folding Method
Step 1: Divide the key value into a number of parts. That is divide k into
parts k1,k2,…kn, where each part has the same number of digits except the
last part which may have lesser digits than the other parts.
Step 2: Add the individual parts. That is obtain the sum of k1+k2+. ..+kn.
The hash value is produced by ignoring the last carry if any.
Example: Table size (N) be 1000, i.e. addresses will range from 0 – 999.
The largest address is of 3 digit.
If the key is 12345678, breaking it down into groups of 3 digits each.
123+ 456 + 78 = 657
Collision Resolution in Hashing
The situation when the location found for two keys are same, the situation
can be termed as collision.
H:Key1→ L
H:Key2→ L
As two data values cannot be kept in the exact location, collision is not
desirable situation.
Avoiding collisions completely is difficult, even with a good hash function.
Some method should be used to resolve this.
Collision Resolution in Hashing
There are two known methods of collision resolution in Hashing.
•
Open Addressing
•
Chaining
Collision Resolution in Hashing
Open Addressing
Every key considers the entire table as the storage space. Thus, if it does not find the
appropriate place for storage through the hash function, it tries to find the next free
available slot.
• There are 3 different Open addressing mechanisms named as
• Linear Probing
• Quadratic Probing
• Rehashing/Double hashing
Collision Resolution in Hashing
Linear Probing
If the key cannot be stored/searched at the given hash location, try to find the next
available free slot by traversing sequentially
If the table size is TS,H’(K)= K Mod TS, j is the probe number that varies from 0 to
TS-1
Note: Probes is a count to find the
H(K,j) = (H'(K) + j) modulus TS free location for each value to store
j=0, 1, 2, ... in the hash table.
Sequence of investigation:
• H'(K) modulus TS
• (H'(K) + 1 ) modulus TS
• (H'(K) + 2) modulus TS
• …
Consider a hash table of size 10 . Using linear
probing , insert the keys 72,27,36,24,63,81 and 92
into the table.
Challenges in Linear Probing :
1.Primary Clustering: One of the problems with linear probing is
Primary clustering, many consecutive elements form groups and it starts
taking time to find a free slot or to search for an element.
2.Secondary Clustering: Secondary clustering is less severe, two records
only have the same collision chain (Probe Sequence) if their initial
position is the same.
Collision Resolution in Hashing
Quadratic Probing
•Idea: when there is a collision, check the next available position in the table using
the quadratic formula:
•H(K,j) = (H'(K) + a*j + b*j2)modulus TS
j =0, 1, 2, ...
if a=1/2, b=1/2 if a=0, b=1
Sequence of investigation: Sequence of investigation:
• H'(K) • H'(K)
• (H'(K) + ½ + ½ ) modulus TS • (H'(K) + 1 ) modulus TS
• (H'(K)+ ½*2+ ½ *22)modulus TS • (H'(K)+ 1*22)modulus TS
• (H'(K)+ ½*3+ ½ *32) modulus TS and so • (H'(K)+ 1 *32) modulus TS and so on
on i.e. H(K), H(K)+1, H(K)+4, H(K)+9, …
i.e. H'(K), H'(K)+1, H'(K)+3, H'(K)+6,
Challenges in Quadratic Probing :
Secondary Clustering: Secondary clustering is less severe, two records
only have the same collision chain (Probe Sequence) if their initial
position is the same.
Consider a hash table of size 10 . Using quadratic
probing , insert the keys 72,27,36,24,63,81 and 101
into the table. Take c1=1 and c2=3
Collision Resolution in Hashing
Rehashing/Double Hashing
The first hash function is used to find the hash table location and the second hash function
to find the increment sequence
H(K,j) = (H(K) + j H’(K) ) modulus TS, j=0,1,..
Sequence of investigation: .
H(K)
(H(K) + H’(K)) modulus TS
(H(K) + 2*H’(K)) modulus TS and so on
(H(K) + 3*H’(K)) modulus TS and so on
Consider a hash table of size 10 . Using double
hashing , insert the keys 72,27,36,24,63,81and 92
and into the table. Take h1=(k mod 10) and h2 =(k
mod 8)
Collision Resolution in Hashing
Chaining
In Chaining, each location in a
hash table stores a pointer to a
linked list that contains all the
key values that were hashed to
that location. That is, location 1
in the hash table points to the
head of the linked list of all the
key values that hashed to 1.
However, if no key value
hashes to 1, then location 1 in
the hash table contains NULL.
The keys with the same hash
address go to the same linked
list.
Insert the keys 7,24,18,52,36,54 ,11 and 23 in a chained
hash table of 9 memory locations .Use h(K)= K mod m.