Unit 1 - Data Structures
Unit 1 - Data Structures
UNIT -1
Abstract Data Types
Data types such as int, float, double, long, etc. are considered to be in-built data types
and we can perform basic operations with them such as addition, subtraction, division,
multiplication, etc. Now there might be a situation when we need operations for our user-
defined data type which have to be defined. These operations can be defined only as and when
we require them. So, in order to simplify the process of solving problems, we can create data
structures along with their operations, and such data structures that are not in-built are known
as Abstract Data Type (ADT).
Abstract Data type (ADT) is a type (or class) for objects whose behaviour is defined by
a set of values and a set of operations. The definition of ADT only mentions what operations
are to be performed but not how these operations will be implemented. It does not specify how
data will be organized in memory and what algorithms will be used for implementing the
operations. It is called “abstract” because it gives an implementation-independent view.
The process of providing only the essentials and hiding the details is known as
abstraction.
The user of data type does not need to know how that data type is implemented, for
example, we have been using Primitive values like int, float, char data types only with the
knowledge that these data type can operate and be performed on without any idea of how they
are implemented.
So a user only needs to know what a data type can do, but not how it will be implemented.
Think of ADT as a black box which hides the inner structure and design of the data type. Now
we‟ll define three ADTs namely List ADT, Stack ADT, Queue ADT.
List ADT
The data is generally stored in key sequence in a list.
The data node contains the pointer to a data structure and a self-referential
pointer which points to the next node in the list.
The List ADT Functions is given below:
get() – Return an element from the list at any given position.
insert() – Insert an element at any position of the list.
remove() – Remove the first occurrence of any element from a non-empty list.
removeAt() – Remove the element at a specified location from a non-empty list.
replace() – Replace an element at any position by another element.
size() – Return the number of elements in the list.
isEmpty() – Return true if the list is empty, otherwise return false.
isFull() – Return true if the list is full, otherwise return false.
C.Dinesh AP/CSE-AIML, MRCE Page 1
CS302PC : Data Structures
Stack ADT
In Stack ADT Implementation instead of data being stored in each node, the pointer to
data is stored.
The program allocates memory for the data and address is passed to the stack ADT.
The head node and the data nodes are encapsulated in the ADT. The calling function
can only see the pointer to the stack.
The stack head structure also contains a pointer to top and count of number of entries
currently in stack.
Queue ADT
The queue abstract data type (ADT) follows the basic design of the stack abstract data
type.
Each node contains a void pointer to the data and the link pointer to the next element in
the queue. The program‟s responsibility is to allocate memory for storing the data.
Features of ADT:
Abstraction:
The user does not need to know the implementation of the data structure.
Better Conceptualization:
ADT gives us a better conceptualization of the real world.
Robust:
The program is robust and has the ability to catch errors.
From these definitions, we can clearly see that the definitions do not specify how these
ADTs will be represented and how the operations will be carried out. There can be different
ways to implement an ADT, for example, the List ADT can be implemented using arrays, or
singly linked list or doubly linked list. Similarly, stack ADT and Queue ADT can be
implemented using arrays or linked lists.
The data type is the form of a variable to which Data structure is a collection of different
a value can be assigned. It defines that the kinds of data. That entire data can be
particular variable will assign the values of the represented using an object and can be used
given data type only. throughout the program.
It can hold value but not data. Therefore, it is It can hold multiple types of data within a
dataless. single object.
There is no time complexity in the case of data In data structure objects, time complexity
types. plays an important role.
In the case of data types, the value of data is not While in the case of data structures, the data
stored because it only represents the type of and its value acquire the space in the
data that can be stored. computer‟s main memory.
Hash Tables
These types can be implemented as linear or non-linear data structures. The data
structures consist of key-value pairs.
S.
No. Linear Data Structure Non-linear Data Structure
Data elements can be traversed in a single run Data elements can‟t be traversed in a
4.
only. single run only.
6. Examples : array, stack, queue, linked list Examples : trees and graphs.
A Singly linked list is a collection of data called nodes, where each node is divided into two
parts to store data and address at some random addresses. The pointer next, points to the address
of the next node in a list.
Compared to the array data structure, the size of the linked list elements is not fixed. Due to
this, there is efficient memory utilization in a singly linked list.
Implementing a singly linked list to perform operations like insertion and deletion is easy.
Elements are accessed easily in a singly linked list.
Node is declared as follows
struct node
{
int data;
struct node *next;
};
Delete at Beginning:
Point head to the next node i.e. second node and make sure to free unused memory by
free(t); or delete t;
Delete at End:
Find the last second element and change next pointer to null. Make sure to free unused
memory by free(t) or delete t
t=head;
while(t!=NULL)
{
printf("%d-->",t->data);
t=t->next;
}
printf("NULL\n");
Stack of Balls
Stack Implementation using Array
Stack implementation is defined in terms of adding an element which is called Push and
deleting an element from the stack which is called Pop.
In an array, elements can be added or deleted at any position but while implementing
stack, we have to permit insertions and deletions at top of the stack only. To do this we can use a
variable called top which points to the last element in the stack.
Initially when the stack is empty, the value of top is initialized to -1.
For push operation, first the value of top is increased by -1 and then the new element is
pushed at the position of top.
For pop operation, first the element at the position of top is popped and then top is
decreased by 1.
Below are the points to aware about implementation of stack using array
Fixed Capacity: A stack can hold at max of n elements which is given during
initialization of the stack.
Overflow: Once stack reaches the max capacity, it is not possible to push any new
element.
Underflow: When no elements are left in the stack, it is not possible to pop the elements
from the stack.
Initialization
Initialize array a[] with size n which is used to store stack elements.
Initialize an index top with -1. It means no elements left in the stack.
push(int data)
if stack is full
print error message
else
top = top+1
a[top] = data
pop()
if stack is empty
print error message
else
print a[top]
top = top-1
display()
if stack is empty
print error message
else
print a[top] to a[0]
Push b1 :
Increment top by 1, it means top now
points at index 0
store ball b1 at top index which is our top
or last element
Push b2 :
Increment top by 1 => top = 1
Store ball b2 at top position => b2 is the top or
last element in the stack
Push b3 :
Increment top by 1 => top = 2
Store ball b3 at top position => b3 is last
element in the stack
Push b4 :
Increment top by 1 => top = 3
Store ball b4 at top position => b4 is last
element in the stack
Push b5 :
As stack has reached it max capacity,
adding new element will result in overflow
Pop :
top element b4 gets removed from the
stack
top index gets decremented by 1
if (top == n-1)
return 1
else
return 0
isEmpty ( ) Operation
This function validates if the stack is empty. If top is equal to -1, then we can consider the
queue as empty.
if ( top == -1)
return 1
else
return 0
Peek ( ) Operation
This function helps in extracting the data element where the top is pointing without
removing it from the stack.
if ( isEmpty() )
return STACK IS EMPTY
else
return a[top]
Node Structure:
struct Node
{
int data;
struct Node *next;
};
Struct Node *top = NULL;
PUSH Operation
Adding or inserting a new element to a stack is known as the Push() operation in the
stack. Elements can only be pushed at the top of the stack.
Steps to push an element into a Stack:
Create a new node (p) using dynamic memory allocation and assign value to the node.
struct Node *p = malloc(sizeof(struct Node));
p->data = value;
Check if stack is empty or not, i.e, (if top == NULL).
If it is empty, then set the next pointer of the node to NULL.
p->next = NULL;
If it is not empty, the newly created node should be linked to the current top element of
the stack, i.e.,
p->next = top;
Make sure that the top of the stack should always be pointing to the newly created node.
top = p;
POP Operation
Removing or deleting an element from a stack is known as the Pop() operation in the
stack. Elements are popped from the top of the stack. There should be at least one element in the
stack to perform the pop() operation.
Steps to pop an element from a Stack:
Check if stack is empty or not, i.e, (TOP == NULL).
If it is empty, then print Stack Underflow.
If it is not empty, then create a temporary node (t) and set it to top. And print data of
temporary node ie deleted element from the stack.
struct Node *t = top;
print t->data;
Now, make top point to the next node.
top = top->next;
Delete the temporary node.
free(t);
TOP
int pop( )
{
if (top == NULL)
printf("\nEMPTY STACK");
else
{
t = top;
printf(“%d”, top->data);
top = top->next;
free(t);
}
}
Applications of Stack:
Stack data structure is used in evaluation and conversion of arithmetic expressions.
Stack is used in Recursion.
It is used for parenthesis checking.
While reversing a string, stack is used as well.
Stack is used in memory management.
It is also used for processing of function calls.
The stack is used to convert expressions from infix to postfix.
The stack is used to perform undo as well as redo operations in word processors.
The stack is used in virtual machines like JVM.
The stack is used in the media players. Useful to play the next and previous song.
The stack is used in recursion operation.
Exponentiation (^) > Multiplication ( * ) or Division ( / ) > Addition (+) or Subtraction (-)
Brackets have the highest priority and their presence can override the precedence order.
Algorithm
Step 1 : Scan the Infix Expression from left to right.
Step 2 : If the scanned character is an operand, append it with final Postfix string.
Step 3 : Else,
Step 3.1 : If the precedence order of the scanned(incoming) operator is greater
than the precedence order of the operator in the stack (or the stack is empty or the
stack contains a „(„ or „[„ or „{„), push it on stack.
Step 3.2 : Else, Pop all the operators from the stack which are greater than or
equal to in precedence than that of the scanned operator. After doing that “Push”
the scanned operator to the stack. (If you encounter parenthesis while popping
then stop there and push the scanned operator in the stack.)
Step 4 : If the scanned character is an „(„ or „[„ or „{„, push it to the stack.
Step 5 : If the scanned character is an „)‟or „]‟ or „}‟, pop the stack and output it until a „(„
or „[„ or „{„ respectively is encountered, and discard both the parenthesis.
Step 6 : Repeat steps 2 to 5 until infix expression is scanned.
Step 7 : Print the output
Step 8 : Pop and output from the stack until it is not empty.
Step 1 : Initially Stack is Empty and the very first literal of Infix Expression is '3' which is
operand hence push it on output stack.
Stack : Output : 3
Step 2 : Next literal of expression is + which is operand, hence needed to be pushed on stack but
intially stack is empty hence literal will directly pushed on to stack.
Stack : + Output : 3
Stack : + Output : 3 4
Step 4 : Next literal is * which is an operator, as stack is not empty, priority should be checked
of in-stack operator(top of stack) and of incoming operator i.e * as priority of in-stack operator is
less than incoming operator, * will be pushed on to stack.
Stack : + * Output : 3 4
Step 5 : Next literal is 5 which is an operand, hence should be pushed on to output stack.
Stack : + * Output : 3 4 5
Step 6 : Next literal is / which is an operator, as stack is not empty, priority should be checked of
in-stack operator(top of stack) i.e * and of incoming operator i.e /, as priority of / and * are equal
hence * will be poped out of stack and will be stored on output stack and operator / will be stored
on stack.
Stack : + / Output : 3 4 5 *
Step 7 : Next literal is 2 which is an operand, hence should be pushed on output stack.
Stack : + / Output : 3 4 5 * 2
Step 8 : As now all literals are traversed, despite stack is not empty, hence pop all literals from
stack and pushed it on to output stack.
Postfix Expression: 3 4 5 * 2 / +
Once the expression is converted to postfix notation, step 2 can be performed:
Example
Given infix expression is: 3+4*5/2 and equivalent postfix by the step1 is 3 4 5 * 2 / +
The string has been completely traversed, the stack contains only one element which is
the result of the given expression ie. 3+4*5/2 = 13.
2.Postfix Evaluation
Input String : 2 3 * 2 1 - / 5 3 * +
S.No. Input Operand 1 Operand 2 Result Stack
1 2 2
2 3 23
3 * 2 3 2*3=6 6
4 2 62
5 1 621
6 - 2 1 2–1=1 61
7 / 6 1 6/1=6 6
8 5 65
9 3 653
10 * 5 3 5 * 3 = 15 6 15
11 + 6 15 6 + 15 = 21 21
Result : 21
Types of Queues:
(1) Simple Queue:
Simple queue also known as a linear queue is the most basic version of a queue.
Here, insertion of an element i.e. the Enqueue operation takes place at the rear end and
removal of an element i.e. the Dequeue operation takes place at the front end.
a) Input restricted Queue:
In this type of Queue, the input can be taken from one side only(rear) and
deletion of elements can be done from both sides(front and rear). This kind of
Queue does not follow FIFO(first in first out).
b) Output restricted Queue:
In this type of Queue, the input can be taken from both sides(rear and
front) and the deletion of the element can be done from only one side(front).
(2) Circular Queue:
In a circular queue, the elements of the queue act as a circular ring. The working
of a circular queue is similar to the linear queue except for the fact that the last element
is connected to the first element. Its advantage is that the memory is utilized in a better
way. This is because if there is an empty space i.e. if no element is present at a certain
position in the queue, then an element can be easily added at that position.
(3) Priority Queue:
This queue is a special type of queue. Its specialty is that it arranges the
elements in a queue based on some priority.
a) Descending Priority Queue
The priority can be something where the element with the highest value has the
priority so it creates a queue with decreasing order of values.
(4) Dequeue:
Dequeue is also known as Double Ended Queue. As the name suggests double
ended, it means that an element can be inserted or removed from both the ends of the
queue unlike the other queues in which it can be done only from one end. Because of
this property it may not obey the First In First Out property.
if(rear == MAX - 1)
printf("Queue Overflow \n");
else
{
if(front== - 1)
front = 0;
printf("Enter the value to be inserted into queue : ");
scanf("%d", &value);
rear = rear + 1;
a[rear] = value;
}
int i;
if(front > rear || rear == -1)
printf("Queue is empty \n");
else
{
for(i = front; i <= rear; i++)
printf("%d \t", a[i]);
}
isFull ( ) Operation
This function checks if the queue is full or not. If the queue is full, then the insertion of
elements is not possible in a queue. This condition is known as overflow error. You need to
perform the following steps while carrying this operation:
if (rear == n-1)
return 1
else
return 0
isEmpty ( ) Operation
This function validates if the queue is empty. If both the front and rear nodes are pointing
to null memory space (-1), then you can consider the queue as empty.
if (front == -1)
return 1
else
return 0
Peek ( ) Operation
This function helps in extracting the data element where the front is pointing without
removing it from the queue.
if ( isEmpty())
print QUEUE IS EMPTY
else
return a[front]
Example
In above example, the last inserted node is 50 and it is pointed by 'rear' and the first inserted
node is 10 and it is pointed by 'front'. The order of elements inserted is 10, 15, 22 and 50.
Operations
To implement queue using linked list, we need to set the following things before implementing
actual operations.
Step 1 - Include all the header files which are used in the program. And declare all
the user defined functions.
Step 2 - Define a 'Node' structure with two members data and next.
Step 3 - Define two Node pointers 'front' and 'rear' and set both to NULL.
Step 4 - Implement the main method by displaying Menu of list of operations and make
suitable function calls in the main method to perform user selected operation.
if(front == NULL)
printf("\n Queue is Underflow!!!\n");
else
{
struct Node *temp = front;
front = front -> next;
printf("\n Deleted element: %d\n", temp->data);
free(temp);
}
if(front == NULL)
printf("\n Queue is Empty!!!\n");
else
{
struct Node *temp = front;
while(temp->next != NULL)
{
printf("%d--->",temp->data);
temp = temp -> next;
}
printf("%d--->NULL\n",temp->data);
}
Applications of Queue:
Queue is used for handling website traffic.
It helps to maintain the playlist in media players.
Queue is used in operating systems for handling interrupts.
It helps in serving requests on a single shared resource, like a printer, CPU task
scheduling, etc.
It is used in asynchronous transfer of data for e.g. pipes, file IO, sockets.
Queues are used for job scheduling in operating system.
In social media to upload multiple phots or videos queue is used.
To send an e-mail queue data structure is used.
To handle website traffic at a time queue are used.
In windows operating system, to switch multiple application.