C++ - Unit IV
C++ - Unit IV
C++ - Unit IV
Unit - IV
Stacks
Stack is a linear data structure which follows a particular order in which the operations are
performed. stack allows operations at one end only. For example, we can add or remove an element
from the top of the stack only. 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 diagram depicts a stack and its operations
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.
Stacks … Cont’d
peek()
Algorithm of peek() function Implementation
begin procedure peek int peek()
return stack[top] {
end procedure return stack[top];
}
isfull()
Algorithm of isfull() function Implementation
begin procedure isfull bool isfull()
if top equals to MAXSIZE {
return true if(top == MAXSIZE)
else return true;
return false else
endif return false;
end procedure }
Stacks … Cont’d
isempty()
Algorithm of isempty() function Implementation
begin procedure isempty bool isempty()
if top less than 1 {
return true if(top == -1)
else return true;
return false else
endif return false;
end procedure }
Note : Implementation of isempty() function is slightly different. We initialize top at -1, as the index in array
starts from 0. So we check if the top is below zero or -1 to determine if the stack is empty.
Stacks … Cont’d
Push Operation
The process of putting a new data element onto stack is known as a Push Operation. 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
2 (a + b) ∗ c ∗+abc ab+c∗
3 a ∗ (b + c) ∗a+bc abc+∗
5 (a + b) ∗ (c + d) ∗+ab+cd ab+cd+∗
Output:
abcd^e-fgh*+^*+i-
Stacks … Cont’d
Recursion:
The process in which a function calls itself directly or indirectly is called recursion and the
corresponding function is called as recursive function.
In the recursive program, the solution to the base case is provided and the solution of the
bigger problem is expressed in terms of smaller problems.
int fact(int n)
{
if (n < = 1) // base case
return 1;
else
return n*fact(n-1);
}
In the above example, base case for n < = 1 is defined and larger value of number can be solved
by converting to smaller one till base case is reached.
Stacks … Cont’d
Properties of Recursion:
A recursive function can go infinite like a loop. To avoid infinite running of recursive function,
there are two properties that a recursive function must have
• Base criteria − There must be at least one base criteria or condition, such that, when this condition
is met the function stops calling itself recursively.
• Progressive approach − The recursive calls should progress in such a way that each time a recursive
call is made it comes closer to the base criteria.
Implementation:
Many programming languages implement recursion by means of stacks. Generally,
whenever a function (caller) calls another function (callee) or itself as callee, the caller function
transfers execution control to the callee. This transfer process may also involve some data to be
passed from the caller to the callee.
This implies, the caller function has to suspend its execution temporarily and resume later
when the execution control returns from the callee function. Here, the caller function needs to
start exactly from the point of execution where it puts itself on hold. It also needs the exact
same data values it was working on. For this purpose, an activation record (or stack frame) is
created for the caller function.
Stacks … Cont’d
This activation record keeps the information about local variables, formal parameters, return
address and all information passed to the caller function.
When any function is called from main(), the memory is allocated to it on the stack. A recursive
function calls itself, the memory for a called function is allocated on top of memory allocated to
calling function and different copy of local variables is created for each function call. When the
base case is reached, the function returns its value to the function by whom it is called and
memory is de-allocated and the process continues.
Let us take the example how recursion works by taking a simple function.
Stacks … Cont’d
//C++ program to demonstrate working of recursion When printFun(3) is called from main(), memory is allocated to
printFun(3) and a local variable test is initialized to 3 and
#include <bits/stdc++.h> statement 1 to 4 are pushed on the stack as shown in below
using namespace std; diagram. It first prints ‘3’.
In statement 2, printFun(2) is called and memory is allocated to
void printFun(int test)
printFun(2) and a local variable test is initialized to 2 and
{
statement 1 to 4 are pushed in the stack.
if (test < 1)
return; Similarly, printFun(2) calls printFun(1) and printFun(1) calls
else printFun(0). printFun(0) goes to if statement and it return to
{ printFun(1).
cout << test << " "; //statement 1
Remaining statements of printFun(1) are executed and it
printFun(test - 1); // statement 2
returns to printFun(2) and so on. In the output, value from 3 to
cout << test << " "; // statement 3
1 are printed and then 1 to 3 are printed. The memory stack
return; // statement 4
has been shown in below diagram.
}
}
int main()
{
int test = 3; Output:
printFun(test); 3 2 1 1 2 3
}
Stacks … Cont’d
Maze Problem ( Rat in a Maze):
A Maze is given as N*N binary matrix of blocks where source block is the upper left most
block i.e., maze[0][0] and destination block is lower rightmost block i.e., maze[N-1][N-1].
A rat starts from source and has to reach the destination. The rat can move only in two
directions: forward and down.
In the maze matrix, 0 means the block is a dead end and 1 means the block can be used in the
path from source to destination. Note that this is a simple version of the typical Maze problem.
For example, a more complex version can be that the rat can move in 4 directions and a more
complex version can be with a limited number of moves.
Following is an example maze.
Gray blocks are dead ends (value = 0).
Following is binary matrix representation of the maze.
Maze Problem… Cont’d
Following is a maze with highlighted solution path and the solution Matrix.(output of program)
Approach:
Form a recursive function, which will follow a path and check if the path reaches the destination or not. If the path does not reach
the destination then backtrack and try other paths.
Algorithm:
• Create a solution matrix, initially filled with 0’s.
• Create a recursive function, which takes initial matrix, output matrix and position of rat (i, j).
• if the position is out of the matrix or the position is not valid then return.
• Mark the position output[i][j] as 1 and check if the current position is destination or not. If destination is reached print the
output matrix and return.
• Recursively call for position (i+1, j) and (i, j+1).
• Unmark position (i, j), i.e output[i][j] = 0.
Queue
Queue is an abstract data structure, somewhat similar to Stacks. Unlike stacks, a queue is open at
both its ends. One end is always used to insert data (enqueue) and the other is used to remove data
(dequeue). Queue follows First-In-First-Out methodology, i.e., the data item stored first will be accessed
first.
A real-world example of queue can be a single-lane one-way road, where the vehicle enters first,
exits first. More real-world examples can be seen as queues at the ticket windows and bus-stops.
Queue Representation
As we now understand that in queue, we access both ends for different reasons. The following diagram
given below tries to explain queue representation as data structure
As in stacks, a queue can also be implemented using Arrays, Linked-lists, Pointers and Structures. For the
sake of simplicity, we shall implement queues using one-dimensional array.
Queue… Cont’d
Basic Operations
Queue operations may involve initializing or defining the queue, utilizing it, and then completely erasing it
from the memory. Here we shall try to understand the basic operations associated with queues
• enqueue() − add (store) an item to the queue.
• dequeue() − remove (access) an item from the queue.
Few more functions are required to make the above-mentioned queue operation efficient. These are
• peek() − Gets the element at the front of the queue without removing it.
• isfull() − Checks if the queue is full.
• isempty() − Checks if the queue is empty.
In queue, we always dequeue (or access) data, pointed by front pointer and while enqueuing (or storing)
data in the queue we take help of rear pointer.
Let's first learn about supportive functions of a queue
peek()
This function helps to see the data at the front of the queue. The algorithm of peek() function is as follows
Queue… Cont’d
isfull()
As we are using single dimension array to implement queue, we just check for the rear pointer to reach at
MAXSIZE to determine that the queue is full. In case we maintain the queue in a circular linked-list, the
algorithm will differ. Algorithm of isfull() function
isempty()
Algorithm of isempty() function
Queue… Cont’d
Enqueue Operation
Queues maintain two data pointers, front and rear. Therefore, its operations are comparatively difficult to implement
than that of stacks.
The following steps should be taken to enqueue (insert) data into a queue
• Step 1 − Check if the queue is full.
• Step 2 − If the queue is full, produce overflow error and exit.
• Step 3 − If the queue is not full, increment rear pointer to point the next empty space.
• Step 4 − Add data element to the queue location, where the rear is pointing.
• Step 5 − return success.
Sometimes, we also check to see if a queue is initialized or not, to handle any unforeseen situations
Queue… Cont’d
Implementation of enqueue()
Queue… Cont’d
Dequeue Operation
Accessing data from the queue is a process of two tasks − access the data where front is pointing and
remove the data after access.
The following steps should be taken to perform dequeue operation.
• Step 1 − Check if the queue is empty.
• Step 2 − If the queue is empty, produce underflow error and exit.
• Step 3 − If the queue is not empty, access the data where front is pointing.
• Step 4 − Increment front pointer to point to the next available data element.
• Step 5 − Return success.
Queue… Cont’d
Implementation of enqueue()
Queue… Cont’d
Applications of Queue
Queue, as the name suggests is used whenever we need to manage any group of objects in an order in
which the first one coming in, also gets out first while the others wait for their turn, like in the following
scenarios:
1. Serving requests on a single shared resource, like a printer, CPU task scheduling etc.
2. In real life scenario, Call Center phone systems uses Queues to hold people calling them in an
order, until a service representative is free.
3. Handling of interrupts in real-time systems. The interrupts are handled in the same order as
they arrive i.e First come first served.
Queue… Cont’d
Circular Queue
Circular Queue is also a linear data structure, which follows the principle of FIFO(First In First Out), but
instead of ending the queue at the last position, it again starts from the first position after the last, hence
making the queue behave like a circular data structure.
why we need a circular queue
In a Linear queue, once the queue is completely full, it's not possible to insert more elements. Even if we
dequeue the queue to remove some of the elements, until the queue is reset, no new elements can be inserted.
When we dequeue any element to remove it from the queue, we are actually moving the front of the queue
forward, thereby reducing the overall size of the queue. And we cannot insert new elements, because the rear
pointer is still at the end of the queue.
The only way is to reset the linear queue, for a fresh start.
Circular Queue… Cont’d
Basic features of Circular Queue
1. In case of a circular queue, head pointer will always point to the front of the queue, and tail
pointer will always point to the end of the queue.
2. Initially, the head and the tail pointers will be pointing to the same location, this would mean that
the queue is empty.
3. New data is always added to the location pointed by the tail pointer, and once the data is added,
tail pointer is incremented to point to the next available location.
Circular Queue… Cont’d
Basic features of Circular Queue
4. In a circular queue, data is not actually removed from the queue. Only the head pointer is
incremented by one position when dequeue is executed. As the queue data is only the data between
head and tail, hence the data left outside is not a part of the queue anymore, hence removed.
5. The head and the tail pointer will get reinitialised to 0 every time they reach the end of the queue.
Circular Queue… Cont’d
Basic features of Circular Queue
6. Also, the head and the tail pointers can cross each other. In other words, head pointer can be greater
than the tail. Sounds odd? This will happen when we dequeue the queue a couple of times and the tail
pointer gets reinitialized upon reaching the end of the queue.
Another very important point is keeping the value of the tail and the head pointer within the maximum
queue size. In the diagrams above the queue has a size of 8, hence, the value of tail and head pointers will
always be between 0 and 7.
This can be controlled either by checking every time whether tail or head have reached the maxSize and
then setting the value 0 or, we have a better way, which is, for a value x if we divide it by 8, the remainder
will never be greater than 8, it will always be between 0 and 0, which is exactly what we want.
So the formula to increment the head and tail pointers to make them go round and round over and again
will be, head = (head+1) % maxSize or tail = (tail+1) % maxSize
Linked List
A linked list is a sequence of data structures, which are connected together via links.
Linked List is a sequence of links which contains items. Each link contains a connection to another link.
Linked list is the second most-used data structure after array. Following are the important terms to
understand the concept of Linked List.
• Link − Each link of a linked list can store a data called an element.
• Next − Each link of a linked list contains a link to the next link called Next.
• LinkedList − A Linked List contains the connection link to the first link called First.
As per the above illustration, following are the important points to be considered.
• Linked List contains a link element called first.
• Each link carries a data field(s) and a link field called next.
• Each link is linked with its next link using its next link.
• Last link carries a link as null to mark the end of the list.
Linked List …Cont’d
Insertion Operation
Adding a new node in linked list is a more than one step activity. We shall learn this with diagrams here.
First, create a node using the same structure and find the location where it has to be inserted.
Imagine that we are inserting a node B (NewNode), between A (LeftNode) and C (RightNode). Then point
B.next to C
It should look like this
Linked List …Cont’d
Now, the next node at the left should point to the new node.
This will put the new node in the middle of the two. The new list should look like this
Similar steps should be taken if the node is being inserted at the beginning of the list. While inserting it at
the end, the second last node of the list should point to the new node and the new node will point to NULL.
Linked List …Cont’d
Deletion Operation
Deletion is also a more than one step process. We shall learn with pictorial representation. First, locate the
target node to be removed, by using searching algorithms.
The left (previous) node of the target node now should point to the next node of the target node
This will remove the link that was pointing to the target node. Now, using the following code, we will
remove what the target node is pointing at.
Linked List …Cont’d
We need to use the deleted node. We can keep that in memory otherwise we can simply deallocate
memory and wipe off the target node completely.
Reverse Operation:
This operation is a thorough one. We need to make the last node to be pointed by the head node and
reverse the whole linked list.
First, we traverse to the end of the list. It should be pointing to NULL. Now, we shall make it point to its
previous node
Linked List …Cont’d
We have to make sure that the last node is not the last node. So we'll have some temp node, which
looks like the head node pointing to the last node. Now, we shall make all left side nodes point to their
previous nodes one by one.
Except the node (first node) pointed by the head node, all nodes should point to their predecessor, making
them their new successor. The first node will point to NULL.
We'll make the head node point to the new first node by using the temp node.
Representation of a Polynomial
A polynomial p(x) is the expression in variable x which is in the form (ax^n + bx^n-1 + …. + jx+ k),
where a, b, c …., k fall in the category of real numbers and 'n' is non negative integer, which is called
the degree of polynomial.
An essential characteristic of the polynomial is that each term in the polynomial expression consists of
two parts
1. Coefficient
2. Exponent
Example: 10x^2 + 26x, here 10 and 26 are coefficients and 2, 1 is its exponential value.
Representation of a Polynomial…Cont’d
Points to keep in Mind while working with Polynomials:
• The sign of each coefficient and exponent is stored within the coefficient and the exponent itself
• Additional terms having equal exponent is possible one
• The storage allocation for each term in the polynomial must be done in ascending and descending
order of their exponent
Adding two polynomials using Linked List
Given two polynomial numbers represented by a linked list. Write a function that add these lists means add
the coefficients who have same variable powers.
Representation of a Polynomial…Cont’d
Doubly Linked List
Doubly Linked List is a variation of Linked list in which navigation is possible in both ways,
either forward and backward easily as compared to Single Linked List. Following are the
important terms to understand the concept of doubly linked list.
• Link − Each link of a linked list can store a data called an element.
• Next − Each link of a linked list contains a link to the next link called Next.
• Prev − Each link of a linked list contains a link to the previous link called Prev.
• LinkedList − A Linked List contains the connection link to the first link called First and to the
last link called Last.
Doubly Linked List Representation
Doubly Linked List…Cont’d
As per the above illustration, following are the important points to be considered.
• Doubly Linked List contains a link element called first and last.
• Each link carries a data field(s) and two link fields called next and prev.
• Each link is linked with its next link using its next link.
• Each link is linked with its previous link using its previous link.
• The last link carries a link as null to mark the end of the list.
Basic Operations:
Following are the basic operations supported by a list.
• Insertion − Adds an element at the beginning of the list.
• Deletion − Deletes an element at the beginning of the list.
• Insert Last − Adds an element at the end of the list.
• Delete Last − Deletes an element from the end of the list.
• Insert After − Adds an element after an item of the list.
• Delete − Deletes an element from the list using the key.
• Display forward − Displays the complete list in a forward manner.
• Display backward − Displays the complete list in a backward manner.
Doubly Linked List…Cont’d
Insertion Operation
Following code demonstrates the insertion operation at the beginning of a doubly linked list.
Doubly Linked List…Cont’d
Deletion Operation
Following code demonstrates the deletion operation at the beginning of a doubly linked list.
Doubly Linked List…Cont’d
Insertion at the End of an Operation
Following code demonstrates the insertion operation at the last position of a doubly linked list.
Doubly Linked List…Cont’d