CPDS Unit 3
CPDS Unit 3
Introduction
Basic Terminology
➢ Data structures are the building blocks of any program or the software.
➢ Choosing the appropriate data structure for a program is the most difficult
task for a programmer.
Data: Data can be defined as an elementary value or the collection of values, for
example, student's name and its id are the data about the student.
Group Items: Data items which have subordinate data items are called Group
item, for example, name of a student can have first name and the last name.
Record: Record can be defined as the collection of various data items, for
example, if we talk about the student entity, then its name, address, course and
marks can be grouped together to form the record for the student.
File: A File is a collection of various records of one type of entity, for example, if
there are 60 employees in the class, then there will be 20 records in the related
file where each record contains the data about each employee.
Attribute and Entity: An entity represents the class of certain objects. it contains
various attributes. Each attribute represents the particular property of that
entity.
➢ A data structure is called linear if all of its elements are arranged in the
linear order.
➢ In linear data structures, the elements are stored in non-hierarchical order
Arrays:
• An array is a collection of similar type of data items and each data item is
called an element of the array.
• The data type of the element may be any valid data type like char, int,
float or double.
• The elements of array share the same variable name but each one carries
a different index number known as subscript.
• The array can be of one dimensional, two dimensional or
multidimensional.
The individual elements of the array age are:
Linked List:
• Linked list is a linear data structure which is used to maintain a list in the
memory.
• It can be seen as the collection of nodes stored at non-contiguous memory
locations.
• Each node of the list contains a pointer to its adjacent node.
Stack:
• Stack is a linear list in which insertion and deletions are allowed only at one
end, called top.
• Stack works on the principle of LIFO(last in first out)/FILO(First in last out)
• A stack is an abstract data type (ADT), can be implemented in most of the
programming languages.
• It is named as stack because it behaves like a real-world stack,
• Queue is a linear list in which elements can be inserted only at one end
called rear and deleted only at the other end called front.
• It is an abstract data structure, similar to stack.
• Queue is opened at both end therefore it follows First-In-First-Out (FIFO)
methodology for storing the data items.
➢ This data structure does not form a sequence i.e. each item or element is
connected with two or more other items in a non-linear arrangement.
➢ The data elements are not arranged in sequential structure.
Trees:
Graphs:
1) Traversing: Every data structure contains the set of data elements. Traversing
the data structure means visiting each element of the data structure in order to
perform some specific operation like searching or sorting.
If the size of data structure is n then we can only insert n-1 data elements into it.
3) Deletion:The process of removing an element from the data structure is called
Deletion. We can delete an element from the data structure at any random
location.
4) Searching: The process of finding the location of an element within the data
structure is called Searching. There are two algorithms to perform searching,
Linear Search and Binary Search. We will discuss each one of them later in this
tutorial.
5) Sorting: The process of arranging the data structure in a specific order is known
as Sorting. There are many algorithms that can be used to perform sorting, for
example, insertion sort, selection sort, bubble sort, etc.
6) Merging: When two lists List A and List B of size M and N respectively, of similar
type of elements, clubbed or joined to produce the third list, List C of size (M+N),
then this process is called merging
Stack
➢ A Stack is a linear data structure that follows the LIFO (Last-In-First-
Out) principle.
➢ Stack has one end, whereas the Queue has two ends (front and rear).
➢ It contains only one pointer top pointer pointing to the topmost element
of the stack.
➢ Whenever an element is added in the stack, it is added on the top of the
stack, and
➢ the element can be deleted only from top of the stack.
➢ In other words, a stack can be defined as a container in which insertion and
deletion can be done from the one end known as the top of the stack.
Working of Stack
PUSH operation
o Before deleting the element from the stack, we check whether the stack is
empty.
o If we try to delete the element from the empty stack, then
the underflow condition occurs.
o If the stack is not empty, we first access the element which is pointed by
the top
o Once the pop operation is performed, the top is decremented by 1,
i.e., top=top-1.
Representation of stacks
A stack can be represented in two ways
1. Array Representation
Example:
#include<stdio.h>
int stack[100],choice,n,top,x,i;
void push(void);
void pop(void);
void display(void);
int main()
{
//clrscr();
top=-1;
printf("\n Enter the size of STACK[MAX=100]:");
scanf("%d",&n);
printf("\n\t STACK OPERATIONS USING ARRAY");
printf("\n\t--------------------------------");
printf("\n\t 1.PUSH\n\t 2.POP\n\t 3.DISPLAY\n\t 4.EXIT");
do
{
printf("\n Enter the Choice:");
scanf("%d",&choice);
switch(choice)
{
case 1:
{
push();
break;
}
case 2:
{
pop();
break;
}
case 3:
{
display();
break;
}
case 4:
{
printf("\n\t EXIT POINT ");
break;
}
default:
{
printf ("\n\t Please Enter a Valid Choice(1/2/3/4)");
}
}
}
while(choice!=4);
return 0;
}
void push()
{
if(top>=n-1)
{
printf("\n\tSTACK is over flow");
}
else
{
printf(" Enter a value to be pushed:");
scanf("%d",&x);
top++;
stack[top]=x;
}
}
void pop()
{
if(top<=-1)
{
printf("\n\t Stack is under flow");
}
else
{
printf("\n\t The popped elements is %d",stack[top]);
top--;
}
}
void display()
{
if(top>=0)
{
printf("\n The elements in STACK \n");
for(i=top; i>=0; i--)
printf("\n%d",stack[i]);
printf("\n Press Next Choice");
}
else
{
printf("\n The STACK is empty");
}
}
Output:
Enter the size of STACK[MAX=100]:10
STACK OPERATIONS USING ARRAY
--------------------------------
1.PUSH
2.POP
3.DISPLAY
4.EXIT
Enter the Choice:1
Enter a value to be pushed:12
98
24
12
Press Next Choice
Enter the Choice:2
The popped elements is 98
Enter the Choice:3
24
12
Press Next Choice
Enter the Choice:4
EXIT POINT
Example:
//Linked List Representation of Stacks
#include <stdio.h>
#include <stdlib.h>
struct node
{
int info;
struct node *ptr;
}*top,*top1,*temp;
int topelement();
void push(int data);
void pop();
void empty();
void display();
void destroy();
void stack_count();
void create();
int count = 0;
void main()
{
int no, ch, e;
printf("\n 1 - Push");
printf("\n 2 - Pop");
printf("\n 3 - Top");
printf("\n 4 - Empty");
printf("\n 5 - Exit");
printf("\n 6 - Display");
printf("\n 7 - Stack Count");
printf("\n 8 - Destroy stack");
create();
while (1)
{
printf("\n Enter choice : ");
scanf("%d", &ch);
switch (ch){
case 1:
printf("Enter element : ");
scanf("%d", &no);
push(no);
break;
case 2:
pop();
break;
case 3:
if (top == NULL)
printf("stack is empty");
else
{
e = topelement();
printf("\n Top element : %d", e);
}
break;
case 4:
empty();
break;
case 5:
exit(0);
case 6:
display();
break;
case 7:
stack_count();
break;
case 8:
destroy();
break;
default :
printf(" wrong choice:Try again ");
break;
}
}
}
//empty stack
void create()
{
top = NULL;
}
void stack_count()
{
printf("\n no: of elements in stack : %d", count);
}
//push data
void push(int data)
{
if (top == NULL)
{
top =(struct node *)malloc(1*sizeof(struct node));
top->ptr = NULL;
top->info = data;
}
else
{
temp =(struct node *)malloc(1*sizeof(struct node));
temp->ptr = top;
temp->info = data;
top = temp;
}
count++;
}
void display()
{
top1 = top;
if (top1 == NULL){
printf("empty stack");
return;
}
while (top1 != NULL)
{
printf("%d ", top1->info);
top1 = top1->ptr;
}
}
void pop()
{
top1 = top;
if (top1 == NULL)
{
printf("\n error");
return;
}
else
top1 = top1->ptr;
printf("\n Popped value : %d", top->info);
free(top);
top = top1;
count--;
}
int topelement()
{
return(top->info);
}
//check stack empty or not
void empty()
{
if (top == NULL)
printf("\n empty stack");
else
printf("\n stack not empty with %d values", count);
}
void destroy()
{
top1 = top;
while (top1 != NULL)
{
top1 = top->ptr;
free(top);
top = top1;
top1 = top1->ptr;
}
free(top1);
top = NULL;
printf("\n all are destroyed");
count = 0;
}
Output:
1 - Push
2 - Pop
3 - Top
4 - Empty
5 - Exit
6 - Display
7 - Stack Count
8 - Destroy stack
Enter choice : 1
Enter element : 10
Enter choice : 1
Enter element : 20
Enter choice : 1
Enter element : 30
Enter choice : 3
Top element : 30
Enter choice : 6
30 20 10
Enter choice : 7
Stack Applications
In a stack, only limited operations are performed because it is restricted
data structure.
Following are the applications of stack:
1. Expression Evaluation
2. Expression Conversion
Expression Evaluation
➢ In the C programming language, an expression is evaluated based on the
operator precedence and associativity.
➢ When there are multiple operators in an expression, they are evaluated
according to their precedence and associativity.
➢ The operator with higher precedence is evaluated first and the operator
with the least precedence is evaluated last.
Parsing Expressions
Expression Conversion
➢ The way to write arithmetic expression is known as a notation.
➢ An arithmetic expression can be written in three different equivalent
notations, i.e., without changing the essence or output of an expression.
These notations are −
• Infix Notation
• Prefix (Polish) Notation
• Postfix (Reverse-Polish) Notation
These notations are named as how they use operator in expression.
Infix Notation
Prefix Notation
Postfix Notation
The following table briefly tries to show the difference in all three notations −
2 (a + b) ∗ c ∗+abc ab+c∗
3 a ∗ (b + c) ∗a+bc abc+∗
5 (a + b) ∗ (c + d) ∗+ab+cd ab+cd+∗
6 ((a + b) ∗ c) - d -∗+abcd ab+c∗d-
We can use B as a helper to finish this job. We are now ready to move on. Let’s
go through each of the steps:
1. Move the first disk from A to C
2. Move the first disk from A to B
3. Move the first disk from C to B
4. Move the first disk from A to C
5. Move the first disk from B to A
6. Move the first disk from B to C
7. Move the first disk from A to C
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 queue can be defined as an ordered list which enables insert
operations to be performed at one end called REAR and delete
operations to be performed at another end called FRONT.
For example, people waiting in line for a rail ticket form a queue.
Queue Representation
Operations on Queue
o Enqueue: The enqueue operation is used to insert the element at the rear
end of the queue. It returns void.
o Dequeue: The dequeue operation performs the deletion from the front-
end of the queue. It also returns the element which has been removed
from the front-end. It returns an integer value. The dequeue operation can
also be designed to void.
o Queue overflow (isfull): When the Queue is completely full, then it shows
the overflow condition.
o Queue underflow (isempty): When the Queue is empty, i.e., no elements
are in the Queue then it throws the underflow condition.
A Queue can be represented as a container opened from both the sides in which
the element can be enqueued from one side and dequeued from another side
Array representation of Queue
The above figure shows the queue of characters forming the English
word "HELLO".
However, the value of rear increases by one every time an insertion is performed
in the queue.
After inserting an element into the queue shown in the above figure, the queue
will look something like following. The value of rear will become 5 while the value
of front remains same.
After deleting an element, the value of front will increase from 0 to 1. however,
the queue will look something like following.
Example:
#include <stdio.h>
#include<stdlib.h>
#define MAX 5
void insert();
void delete();
void display();
int queue_array[MAX];
int rear = - 1;
int front = - 1;
int main()
{
int choice;
while (1)
{
printf("\n 1.Insert ");
printf("\n 2.Delete ");
printf("\n 3.Display ");
printf("\n 4.Quit ");
printf("\n Enter your choice : ");
scanf("%d", &choice);
switch(choice)
{
case 1:
insert();
break;
case 2:
delete();
break;
case 3:
display();
break;
case 4:
exit(1);
default:
printf("Wrong choice n");
}
}
}
void insert()
{
int item;
if(rear == MAX - 1)
printf("Queue Overflow n");
else
{
if(front== - 1)
front = 0;
printf("Inset the element in queue : ");
scanf("%d", &item);
rear = rear + 1;
queue_array[rear] = item;
}
}
void delete()
{
if(front == - 1 || front > rear)
{
printf("Queue Underflow n");
return;
}
else
{
printf("Element deleted from queue is : %dn", queue_array[front]);
front = front + 1;
}
}
void display()
{
int i;
if(front == - 1)
printf("Queue is empty n");
else
{
printf("Queue is : n");
for(i = front; i <= rear; i++)
printf("%d ", queue_array[i]);
printf("n");
}
}
Output:
1.Insert
2.Delete
3.Display
4.Quit
Enter your choice : 1
1.Insert
2.Delete
3.Display
4.Quit
Enter your choice : 1
1.Insert
2.Delete
3.Display
4.Quit
Enter your choice : 3
Queue is :
1000 2000
1.Insert
2.Delete
3.Display
4.Quit
Enter your choice : 1
1.Insert
2.Delete
3.Display
4.Quit
Enter your choice : 1
Queue is :
1000 2000 3000 4000
1.Insert
2.Delete
3.Display
4.Quit
Enter your choice : 2
Element deleted from queue is : 1000
1.Insert
2.Delete
3.Display
4.Quit
Enter your choice : 3
Queue is :
2000 3000 4000
1.Insert
2.Delete
3.Display
4.Quit
Enter your choice : 2
Element deleted from queue is : 2000
1.Insert
2.Delete
3.Display
4.Quit
Enter your choice : 3
Queue is :
3000 4000
1.Insert
2.Delete
3.Display
4.Quit
Enter your choice : 4
In a linked queue, each node of the queue consists of two parts i.e. data part and
the link part.
Each element of the queue points to its immediate next element in the memory.
In the linked queue, there are two pointers maintained in the memory i.e. front
pointer and rear pointer.
The front pointer contains the address of the starting element of the queue while
the rear pointer contains the address of the last element of the queue.
Insertion and deletions are performed at rear and front end respectively.
If front and rear both are NULL, it indicates that the queue is empty.
Example:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *front;
struct node *rear;
void insert();
void delete();
void display();
void main ()
{
int choice;
while(choice != 4)
{
printf("\n*************************Main
Menu*****************************\n");
printf("\n=========================================================
\n");
printf("\n1.insert an element\n2.Delete an element\n3.Display the
queue\n4.Exit\n");
printf("\nEnter your choice ?");
scanf("%d",& choice);
switch(choice)
{
case 1:
insert();
break;
case 2:
delete();
break;
case 3:
display();
break;
case 4:
exit(0);
break;
default:
printf("\nEnter valid choice??\n");
}
}
}
void insert()
{
struct node *ptr;
int item;
===========================================================
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
Enter value?
100
*************************Main Menu*****************************
================================================================
=
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
Enter value?
200
*************************Main Menu*****************************
================================================================
=
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
Enter value?
300
*************************Main Menu*****************************
================================================================
=
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
100
200
300
*************************Main Menu*****************************
================================================================
=
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
*************************Main Menu*****************************
================================================================
=
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
200
300
*************************Main Menu*****************************
================================================================
=
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
Types of Queues
There are four types of Queues:
1.Linear Queue
▪ In Linear Queue, an insertion takes place from one end while the deletion
occurs from another end.
▪ The end at which the insertion takes place is known as the rear end, and
the end at which the deletion takes place is known as front end.
▪ It strictly follows the FIFO rule.
The above figure shows that the elements are inserted from the rear end, and if
we insert more elements in a Queue, then the rear value gets incremented on
every insertion.
▪ In the above figure, we can observe that the front pointer points to the
next element, and the element which was previously pointed by the front
pointer was deleted.
▪ The major drawback of using a linear Queue is that insertion is done only
from the rear end.
▪ If the first three elements are deleted from the Queue, we cannot insert
more elements even though the space is available in a Linear Queue.
▪ In this case, the linear Queue shows the overflow condition as the rear is
pointing to the last element of the Queue.
2.Circular Queue
3. Priority Queue
A priority queue is another special type of Queue data structure in which each
element has some priority associated with it.
Based on the priority of the element, the elements are arranged in a priority
queue.
If the elements occur with the same priority, then they are served according to
the FIFO principle.
In priority Queue, the insertion takes place based on the arrival while the deletion
occurs based on the priority.
1, 3, 4, 8, 14, 22
All the values are arranged in ascending order. Now, we will observe how the
priority queue will look after performing the following operations:
o poll(): This function will remove the highest priority element from the
priority queue. In the above priority queue, the '1' element has the highest
priority, so it will be removed from the priority queue.
o add(2): This function will insert '2' element in a priority queue. As 2 is the
smallest element among all the numbers so it will obtain the highest
priority.
o poll(): It will remove '2' element from the priority queue as it has the
highest priority queue.
o add(5): It will insert 5 element after 4 as 5 is larger than 4 and lesser than
8, so it will obtain the third highest priority in a priority queue.
4. Deque
Deque is a linear data structure in which the insertion and deletion operations
are performed from both ends. We can say that deque is a generalized version of
the queue.
o Deque can be used both as stack and queue as it allows the insertion and
deletion operations on both ends.
In deque, the insertion and deletion operation can be performed from one side.
The stack follows the LIFO rule in which both the insertion and deletion can be
performed only from one end; therefore, we conclude that deque can be
considered as a stack.
In deque, the insertion can be performed on one end, and the deletion can be
done on another end.
The queue follows the FIFO rule in which the element is inserted on one end and
deleted from another end.
Therefore, we conclude that the deque can also be considered as the queue.
There are two types of Queues, Input-restricted queue, and output-restricted
queue.
1. malloc()
2. calloc()
3. realloc()
4. free()
Before learning above functions, let's understand the difference between static
memory allocation and dynamic memory allocation.
Now let's have a quick look at the methods used for dynamic memory allocation.
malloc() function in C
Example:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n,i,*ptr,sum=0;
printf("Enter number of elements: ");
scanf("%d",&n);
ptr=(int*)malloc(n*sizeof(int)); //memory allocated using malloc
if(ptr==NULL)
{
printf("Sorry! unable to allocate memory");
exit(0);
}
printf("Enter elements of array: ");
for(i=0;i<n;++i)
{
scanf("%d",ptr+i);
sum+=*(ptr+i);
}
printf("Sum=%d",sum);
free(ptr);
return 0;
}
Output:
Enter number of elements: 3
20
30
Sum=60
calloc() function in C
ptr=(cast-type*)calloc(number, byte-size)
Example:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n,i,*ptr,sum=0;
printf("Enter number of elements: ");
scanf("%d",&n);
ptr=(int*)calloc(n,sizeof(int)); //memory allocated using calloc
if(ptr==NULL)
{
printf("Sorry! unable to allocate memory");
exit(0);
}
printf("Enter elements of array: ");
for(i=0;i<n;++i)
{
scanf("%d",ptr+i);
sum+=*(ptr+i);
}
printf("Sum=%d",sum);
free(ptr);
return 0;
}
Output:
200
300
Sum=600
realloc() function in C
▪ If memory is not sufficient for malloc() or calloc(), you can reallocate the
memory by realloc() function.
▪ In short, it changes the memory size.
ptr=realloc(ptr, new-size)
Example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n = 4, i, *p, s = 0;
p = (int*) calloc(n, sizeof(int));
if(p == NULL)
{
printf("\nError! memory not allocated.");
exit(0);
}
printf("\nEnter elements of array : ");
for(i = 0; i < n; ++i)
{
scanf("%d", p + i);
s += *(p + i);
}
printf("\nSum : %d", s);
p = (int*) realloc(p, 6);
printf("\nEnter elements of array : ");
for(i = 0; i < n; ++i)
{
scanf("%d", p + i);
s += *(p + i);
}
printf("\nSum : %d", s);
return 0;
}
Output: Enter elements of array : 3 34 28 8
Sum : 73
Enter elements of array : 3 28 33 8 10 15
Sum : 145
free() function in C
free(ptr)
Example:
#include <stdio.h>
int main()
{
int* ptr = malloc(10 * sizeof(*ptr));
if (ptr != NULL)
{
*(ptr + 2) = 50;
printf("Value of the 2nd integer is %d",*(ptr + 2));
}
free(ptr);
}
Output:
Value of the 2nd integer is 50