0% found this document useful (0 votes)
11 views

BCS304-Data Structures and Applications-Digital Notes-Module 1

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views

BCS304-Data Structures and Applications-Digital Notes-Module 1

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 71

DATA STRUCTURES AND APPLICATIONS

(BCS304)

DIGITAL NOTES

B.E.
(II YEAR – III SEM)
(2024-25)

Prepared by
Dr. Nagaraj Bhat
Professor
Department of CSE
SHRI MADHWA VADIRAJA INSTITUTE OF
TECHNOLOGY AND MANAGEMENT
BCS304 | DATA STRUCTURES AND APPLICATIONS

TABLE OF CONTENTS

1. Data Structure .......................................................................................................................................2

1.1 Importance of Data Structures ..................................................................................................................2

1.2 Classification of Data Structures ...............................................................................................................3

1.3 Data Structure Operations ........................................................................................................................6

1.4 Review of Arrays ........................................................................................................................................7

1.5 Memory Layout of a C Program ..............................................................................................................12

1.6 Overview of Pointers ...............................................................................................................................14

1.8 Dynamic Memory Allocation And Dynamic Arrays..................................................................................16

1.9 Overview of Structures and Unions .........................................................................................................20

1.10 Polynomials ...........................................................................................................................................27

1.11 Sparse Matrices .....................................................................................................................................38

1.12 Representation of Multidimensional Arrays .........................................................................................42

1.13 Strings ....................................................................................................................................................44

1.14 Stacks .....................................................................................................................................................47

2. Queues ................................................................................................................................................. 64

2.1 Types of Queues ......................................................................................................................................65

2.2 The Queue Abstract Data Type ...............................................................................................................65

2.3 Implementation of Queue .......................................................................................................................66

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 1


BCS304 | DATA STRUCTURES AND APPLICATIONS

1. Data Structure
A data structure is a way of organizing and storing data in a computer so that it can be accessed and
modified efficiently. It provides a means to manage large amounts of data for various computational
tasks, such as storing, retrieving, and manipulating data.

1.1 Importance of Data Structures


Efficient Data Management:
o Data structures allow for the organization of large volumes of data in a structured way,
enabling efficient data management, retrieval, and storage.

Optimized Performance:
o Properly chosen data structures improve the performance of algorithms by optimizing
operations such as searching, sorting, and updating data.

Memory Utilization:
o Data structures help in utilizing memory efficiently by storing data in a way that
minimizes space usage and avoids memory wastage.

Simplified Problem Solving:


o Complex problems can be broken down and managed more easily with the appropriate
data structure, making it simpler to implement and understand algorithms.

Enhanced Data Processing:


o Data structures enable fast processing of data, which is crucial in applications requiring
real-time data handling, such as databases, operating systems, and network
applications.

Improved Data Integrity and Security:


o By organizing data efficiently, data structures help maintain data integrity and security,
ensuring that data is accessed and modified only in intended ways.

Scalability:
o As data grows, well-designed data structures can scale efficiently, handling larger
datasets without significant performance degradation.

Support for Data Abstraction:


o Data structures provide a way to implement data abstraction, allowing developers to
focus on higher-level operations without worrying about the underlying implementation
details.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 2


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.2 Classification of Data Structures

Data structures can be broadly classified into two categories: Primitive Data Structures and Non-
Primitive Data Structures.

1.2.1 Primitive Data Structures


Primitive data structures are the simplest form of data structures, directly supported by the machine
instructions. They are the building blocks for data manipulation in programming languages.

1.2.1.1 Types of Primitive Data Structures

Integer:
o Description: Used to store numeric values without decimal points.
o Example: int age = 25;
o Usage: Useful for counting and indexing.

Float:
o Description: Used to store numbers with fractional parts.
o Example: float temperature = 36.5;
o Usage: Used in calculations requiring precision, such as scientific computations.

Character:
o Description: Stores individual characters.
o Example: char grade = 'A';
o Usage: Handling text and single-character inputs.

Boolean:
o Description: Stores true or false values.
o Example: bool isPassed = true;
o Usage: Common in conditional statements.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 3


BCS304 | DATA STRUCTURES AND APPLICATIONS

Pointer:
o Description: Stores memory addresses of other variables.
o Example:
int num = 10; int* ptr = #
o Usage: Dynamic memory allocation, passing by reference.

1.2.2 Non-Primitive Data Structures


Non-primitive data structures are derived from primitive data structures and are used to handle large
and complex data. They are categorized into Linear and Non-linear structures.

1.2.2.1 Linear Data Structures


Linear data structures arrange data in a sequential manner where elements are linked one after
another.

Arrays:
o Description: A collection of elements, all of the same type, stored in contiguous memory
locations.
o Example: int numbers[5] = {1, 2, 3, 4, 5};
o Usage: Useful for fixed-size collections of similar items.

Stacks:
o Description: Follows the Last In, First Out (LIFO) principle.
o Example:
#define MAX 10
int stack[MAX];
int top = -1;
o Usage: Undo mechanisms, backtracking.

Queues:
o Description: Follows the First In, First Out (FIFO) principle.
o Example:
#define MAX 10
int queue[MAX];
int front = -1, rear = -1;
o Usage: Scheduling, managing resources.

Linked Lists:
o Description: Elements (nodes) are stored in non-contiguous memory locations,
connected by pointers.
o Example:
struct Node {
int data;
struct Node* next;
};
o Usage: Dynamic collections, frequent insertions/deletions.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 4


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.2.2.2 Non-Linear Data Structures


Non-linear data structures arrange data hierarchically and are used for more complex relationships
among data.

Trees:
o Description: A hierarchical data structure with a root node and child nodes forming a
tree-like structure.
o Example:
struct Node {
int data;
struct Node* left;
struct Node* right;
};
o Usage: Databases, file systems.

Graphs:
o Description: A collection of nodes (vertices) connected by edges. Can be directed or
undirected.
o Example:
struct Graph {
int V;
int E;
int** adjMatrix;
};
o Usage: Networks, social connections.

Hash Tables:
o Description: Stores key-value pairs with fast access through hashing.
o Example:
int hashTable[10];
int hashFunction(int key) {
return key % 10;
}
o Usage: Efficient searching, indexing.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 5


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.3 Data Structure Operations


Data structure operations are the fundamental actions that can be performed on data within a data
structure. These operations allow for the management, modification, and retrieval of data stored in
various data structures.

1.3.1. Common Data Structure Operations

Traversing:
o Description: Accessing each element of the data structure exactly once, usually to
perform some action on each element.
o Example:
▪ Array Traversal: Iterating through an array to print all its elements.
▪ Linked List Traversal: Visiting each node in a linked list to calculate the sum of
all elements.
o Usage: Useful for displaying data, performing calculations, and processing each element
of the structure.

Searching:
o Description: Finding the location of a specific element within the data structure.
o Example:
▪ Linear Search: Searching for a number in an unsorted array.
▪ Binary Search: Searching for a number in a sorted array using a divide-and-
conquer approach.
o Usage: Essential for data retrieval, such as finding a record in a database or checking the
existence of a value.

Inserting:
o Description: Adding a new element to the data structure.
o Example:
▪ Array Insertion: Adding a new element at a specific position in an array (may
require shifting elements).
▪ Linked List Insertion: Inserting a new node at the beginning, end, or any specific
position in the list.
o Usage: Required when expanding the dataset, such as adding new entries to a database
or appending elements to a list.

Deleting:
o Description: Removing an element from the data structure.
o Example:
▪ Array Deletion: Removing an element from an array (may require shifting
elements).
▪ Linked List Deletion: Removing a specific node from a linked list.
o Usage: Important for data maintenance, like deleting obsolete records from a database
or removing an item from a collection.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 6


BCS304 | DATA STRUCTURES AND APPLICATIONS

Sorting:
o Description: Arranging the elements of a data structure in a specific order, typically
ascending or descending.
o Example:
▪ Bubble Sort: Sorting an array by repeatedly swapping adjacent elements that
are out of order.
▪ Quick Sort: A divide-and-conquer algorithm that sorts elements by partitioning
the array into sub-arrays.
o Usage: Critical for data organization, such as preparing data for binary search or
displaying sorted lists to users.

Merging:
o Description: Combining elements from two data structures into a single data structure.
o Example:
▪ Merging Sorted Arrays: Combining two sorted arrays into a single sorted array.
▪ Merging Linked Lists: Combining two sorted linked lists into one sorted list.
o Usage: Often used in applications that involve combining datasets, such as merging
customer records or combining results from different sources.

Updating:
o Description: Modifying the value of an existing element in the data structure.
o Example:
▪ Array Update: Changing the value of an element at a specific index.
▪ Linked List Update: Changing the data in a particular node.
o Usage: Used when the data within the structure changes, such as updating a user’s
profile information in a database.

1.4 Review of Arrays

An array is a data structure that stores a fixed-size sequence of elements of the same type in contiguous
memory locations. Arrays are used when we need to store multiple values of the same type in a single
variable, and they allow for efficient access to elements using an index.
Array as a Set of Pairs <index, value>

An array can be conceptually understood as a set of pairs <index, value>. Each element in an array is
associated with a unique index, which serves as a key to access the corresponding value. The index
represents the position of the element within the array, while the value is the actual data stored at that
position.

Let's consider an example where an array stores the marks of students in a class.
Example: Storing Student Marks in an Array
Suppose we have an array that holds the marks of 5 students in a subject:
int marks[5] = {85, 92, 76, 88, 95};

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 7


BCS304 | DATA STRUCTURES AND APPLICATIONS

This array can be represented as a set of pairs <index, value>, where:


• index is the position of the student's marks in the array (starting from 0).
• value is the actual mark obtained by the student.
Here’s how the array can be visualized:
Index Value (Marks)
0 85
1 92
2 76
3 88
4 95
Explanation:
• Index 0: The value at index 0 is 85, representing the marks of the first student.
• Index 1: The value at index 1 is 92, representing the marks of the second student.
• Index 2: The value at index 2 is 76, representing the marks of the third student.
• Index 3: The value at index 3 is 88, representing the marks of the fourth student.
• Index 4: The value at index 4 is 95, representing the marks of the fifth student.
In this context, the array marks is a collection of these <index, value> pairs:
• <0, 85>
• <1, 92>
• <2, 76>
• <3, 88>
• <4, 95>
Each pair is a mapping from an index (which identifies the position of the student's marks) to the
corresponding value (the marks themselves). This structure allows for efficient access to the marks by
simply referring to the student's position in the array.

For instance, if you want to find the marks of the third student, you can access marks[2], which directly
gives you the value 76. This efficiency is one of the primary advantages of using arrays in programming.
This concept of an array as a set of <index, value> pairs makes it a fundamental data structure for
storing and accessing data sequentially, with direct access to any element via its index.

1.4.1 Abstract Data Type (ADT) of Array

1.4.1.1 What is an Abstract Data Type (ADT)?


An Abstract Data Type (ADT) is a theoretical concept that defines a data type purely in terms of its
behavior (i.e., the operations that can be performed on it) rather than its implementation. An ADT
specifies:
• The operations that can be performed on the data.
• The rules for those operations (what inputs are valid, what outputs can be expected).
• The abstract nature of the data (what kind of information is stored).
In simpler terms, an ADT is a model for a certain class of data structures that have similar behavior. For
example, an "array" ADT describes what an array can do (store elements, access elements by index, etc.)
but not how these operations are implemented in code.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 8


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.4.1.2 ADT for Array


1.4.1.2 ADT for Array (Based on Prescribed Textbook)
The Abstract Data Type (ADT) for Arrays defines the objects (or data elements) and the functions (or
operations) that can be performed on these objects. Arrays are objects consisting of a set of pairs
<index, value>, where each index corresponds to a value from the set of elements. The index is a finite
ordered set, which can have one or more dimensions (e.g., 1D, 2D, or multi-dimensional arrays).
Objects:
• A set of pairs <index, value>, where:
o index: A finite ordered set of one or more dimensions (e.g., {0, 1, ..., n-1} for a one-
dimensional array or {(i, j)} for a two-dimensional array).
o value: Each index is associated with a value from the set of items (the elements stored
in the array).
For example:
• 1D Array: Index set = {0, 1, 2, ..., n-1}
• 2D Array: Index set = {(0, 0), (0, 1), (1, 0), (1, 1)}
Functions (Operations) of Array ADT:
Let:
• A ∈ Array (symbolizing a given array)
• i ∈ index (symbolizing an index within the array)
• x ∈ item (symbolizing an element or value in the array)
• j, size ∈ integer (symbolizing dimensions or sizes of the array)

Return Function Operation Type Description


Type Name
Array Create(j, list) Creation Creates a new array of j dimensions, with
undefined items.
Item Retrieve(A, i) Access/Retrieval Retrieves the item stored at index i in array A.
Array Store(A, i, x) Modification/Storage Returns an array identical to A, except that the
value x is stored at index i.

1.4.2 Array Declaration and Initialization During Compilation


When an array is declared and initialized during compilation, the size of the array and its elements are
known and defined at compile time. This means that both the size of the array and the initial values of
its elements are specified in the code before the program is executed.
Example:
#include <stdio.h>

int main() {
int a[5] = {1, 2, 3, 4, 5}; // Array declaration and initialization during compilation
int sum = 0;

for(int i = 0; i < 5; i++) {

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 9


BCS304 | DATA STRUCTURES AND APPLICATIONS

sum += a[i]; // Adding each element of the array to sum


}

printf("Sum = %d", sum); // Output: Sum = 15

return 0;
}
• Explanation:
o In this example, the array a is declared with a size of 5 and initialized with the values {1,
2, 3, 4, 5} at compile time.
o The size of the array and the values it contains are fixed and known before the program
is executed.
o The program calculates the sum of all elements in the array and outputs it.

1.4.3 Array Declaration and Initialization During Runtime (Without Using Any Memory
Allocation Function)
When an array is declared and initialized during runtime, the size of the array is determined while the
program is running, based on user input or other runtime conditions. However, the array is still created
in the stack memory, not in the heap, and does not use dynamic memory allocation functions like
malloc() or calloc().
Example:
#include <stdio.h>
int main() {
int n, i, sum = 0;

// Getting the size of the array from the user at runtime


printf("Enter number of array elements: ");
scanf("%d", &n);

// Declaration of an array with size n


int a[n];
// Taking array elements input from the user
printf("Enter array elements:\n");
for(i = 0; i < n; i++) {
scanf("%d", &a[i]);
sum += a[i]; // Adding each element to sum
}
// Displaying the sum of array elements
printf("Sum = %d", sum);

return 0;
}

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 10


BCS304 | DATA STRUCTURES AND APPLICATIONS

• Explanation:
o Array Declaration During Runtime: In this program, the array a is declared after
determining its size n from the user's input at runtime.
o No Dynamic Memory Allocation: The array is created on the stack (not dynamically
allocated in the heap), meaning that memory is allocated automatically when the array
is declared.
o Runtime Initialization: The user inputs the elements of the array during the execution of
the program, which are then stored in the array a.
o The program calculates the sum of all elements entered by the user and prints the
result.

1.4.4 Multidimensional Arrays


Multidimensional arrays in C are arrays of arrays. They allow you to store data in a tabular or matrix
form, where data is organized into rows and columns (and potentially more dimensions). The most
common type of multidimensional array is the two-dimensional array, but arrays can have as many
dimensions as needed.
Key Concepts:
1. Two-Dimensional Arrays:
o A two-dimensional array can be thought of as a matrix with rows and columns.
o Syntax: data_type array_name[rows][columns];
o Example: int matrix[3][4]; // A 3x4 matrix (3 rows and 4 columns)
2. Three-Dimensional Arrays:
o A three-dimensional array can be visualized as a cube or a collection of matrices.
o Syntax: data_type array_name[x][y][z];
o Example: int cube[2][3][4]; // A 2x3x4 three-dimensional array
Example: Two-Dimensional Array
#include <stdio.h>
int main() {
int matrix[2][3]; // A 2x3 matrix (2 rows and 3 columns)
int i, j;
// Input elements into the matrix
printf("Enter 6 elements for a 2x3 matrix:\n");
for (i = 0; i < 2; i++) {
for (j = 0; j < 3; j++) {
scanf("%d", &matrix[i][j]);
} }
// Print the matrix
printf("The 2x3 matrix is:\n");
for (i = 0; i < 2; i++) {
for (j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]); }
printf("\n"); // Newline for the next row }
return 0; }

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 11


BCS304 | DATA STRUCTURES AND APPLICATIONS

Explanation:
• Array Declaration: int matrix[2][3]; declares a two-dimensional array with 2 rows and 3
columns.
• Input: Nested loops are used to input elements into the matrix. The outer loop iterates over the
rows, and the inner loop iterates over the columns.
• Output: The same nested loop structure is used to print the matrix, formatting it into rows and
columns.
Accessing Elements:
• Row-Major Order: In a two-dimensional array, elements are stored in memory in row-major
order, meaning the elements of each row are stored in contiguous memory locations.
• Access Syntax:
o To access an element in the ith row and jth column: array_name[i][j].
o Example: matrix[1][2] accesses the element in the second row and third column of the
matrix.

1.5 Memory Layout of a C Program


When a C program is executed, its memory is organized into several distinct sections, each serving a
different purpose. These sections include Stack Memory, Heap Memory, Data Memory Area, and Text
Area. Understanding the memory layout is crucial for efficient programming and debugging.

Memory Layout Overview

Text Area:
o Description: The Text Area, also known as the Code Segment, stores the actual code or
instructions of the program. This section is usually read-only to prevent accidental
modification of the instructions.
o Characteristics:
▪ Contains compiled machine code.
▪ Fixed size, determined at compile time.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 12


BCS304 | DATA STRUCTURES AND APPLICATIONS

▪ Often marked as read-only to avoid accidental overwriting.


o Example: The instructions of a function like printf() reside in this area.

Data Memory Area:


o Description: The Data Memory Area is divided into two sub-sections:
▪ Initialized Data Segment: Stores global and static variables that are initialized by
the programmer.
▪ Uninitialized Data Segment (BSS - Block Started by Symbol): Stores global and
static variables that are not initialized by the programmer.
o Characteristics:
▪ Initialized variables retain their initial values throughout the program execution.
▪ Uninitialized variables are automatically set to zero by the system.
o Example:
int global_var = 10; // Initialized data
static int count; // Uninitialized data (BSS)

Heap Memory:
o Description: Heap Memory is used for dynamic memory allocation. Memory in the heap
is allocated and deallocated by the programmer at runtime using functions like malloc(),
calloc(), realloc(), and free().
o Characteristics:
▪ Size can grow and shrink dynamically as needed during program execution.
▪ Not automatically managed by the system; requires manual deallocation.
▪ Useful for allocating memory when the size of data structures is not known in
advance.
o Example:
int* ptr = (int*)malloc(10 * sizeof(int)); // Allocates memory for an array of 10 integers
free(ptr); // Frees the allocated memory

Stack Memory:
o Description: Stack Memory is used for storing local variables, function parameters, and
return addresses. It operates in a Last-In-First-Out (LIFO) manner.
o Characteristics:
▪ Memory allocation and deallocation are managed automatically by the system.
▪ Each function call creates a new stack frame, which includes the function's local
variables and return address.
▪ Stack memory is limited in size, leading to a stack overflow if too much memory
is used (e.g., excessive recursion).
o Example:
void function() {
int local_var = 5; // Stored in the stack
}

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 13


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.6 Overview of Pointers


Pointers are a fundamental feature in C programming, providing a powerful way to manage memory
and create dynamic data structures. A pointer is a variable that stores the memory address of another
variable, rather than a direct value.

1.6.1 Key Concepts of Pointers

Pointer Declaration:
o Pointers are declared using the * operator before the pointer variable's name.
o Syntax: datatype *pointer_name;
o Example:
int *ptr; // Declares a pointer to an integer

Pointer Initialization:
o Pointers are typically initialized to the address of a variable using the address-of
operator &.
o Example:
int num = 10;
int *ptr = &num; // ptr now holds the address of num
2. Dereferencing Pointers:
o Dereferencing a pointer means accessing the value stored at the memory address the
pointer is pointing to, using the * operator.
o Example:
int value = *ptr; // Retrieves the value at the address stored in ptr (value will be 10)
3. Null Pointer:
o A pointer that is not assigned any address can be set to NULL, indicating that it points to
nothing.
o Example:
int *ptr = NULL; // ptr is initialized but points to nothing
4. Pointer Arithmetic:
o Pointers can be incremented or decremented to point to the next or previous memory
locations, especially in arrays.
o Example:
ptr++; // Moves the pointer to the next memory location of its type

1.6.2 Example: Using Pointers


Here's a simple example demonstrating the use of pointers:
#include <stdio.h>

int main() {
int num = 25; // Declare an integer variable
int *ptr = &num; // Declare a pointer and assign it the address of num

printf("Value of num: %d\n", num); // Output the value of num

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 14


BCS304 | DATA STRUCTURES AND APPLICATIONS

printf("Address of num: %p\n", &num); // Output the address of num


printf("Value of ptr: %p\n", ptr); // Output the address stored in ptr (which is &num)
printf("Value pointed by ptr: %d\n", *ptr);
// Output the value stored at the address ptr points to (which is num's value)
*ptr = 30; // Change the value of num through the pointer
printf("Updated value of num: %d\n", num); // Output the updated value of num

return 0;
}
Output:
Value of num: 25
Address of num: 0x7ffee3c5b74c
Value of ptr: 0x7ffee3c5b74c
Value pointed by ptr: 25
Updated value of num: 30

1.7 Arrays Using Pointers

In C, arrays and pointers are closely related. The name of an array acts like a pointer to the first element
of the array, which means you can use pointers to access and manipulate array elements. By using
pointers, you can perform operations on arrays more efficiently and flexibly.

1.7.1. Accessing Array Elements Using Pointers


When you declare an array, the array name itself acts as a pointer to the first element of the array. For
example, if arr is an array, then arr (or &arr[0]) gives the address of the first element, and *(arr + i) gives
the value of the element at index i.
Example: Adding All Elements of an Array Using Pointers
Let's consider a simple program that adds all the elements of an array using pointers.
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50}; // Declare and initialize an array
int *ptr; // Declare a pointer to an integer
int sum = 0;
int n = 5;
ptr = arr; // Initialize the pointer to point to the first element of the array
// Iterate through the array using the pointer
for(int i = 0; i < n; i++) {
sum += *(ptr + i); // Add the value pointed by ptr to sum }
printf("Sum of array elements = %d\n", sum); // Output the sum
return 0;
}
Output:
Sum of array elements = 150

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 15


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.8 Dynamic Memory Allocation And Dynamic Arrays


Dynamic memory allocation in C refers to the process of allocating memory during the runtime of a
program. Unlike static memory allocation, where the size of the data structures must be known at
compile time, dynamic memory allocation allows the program to request memory from the heap as
needed while the program is running. This provides flexibility in managing memory, especially when
dealing with data structures whose size may vary.
The standard library functions malloc(), calloc(), realloc(), and free() are used for dynamic memory
allocation in C. These functions operate on the heap, a region of memory used for dynamic allocation.
Memory allocated on the heap persists until it is explicitly deallocated using the free() function.

1.8.1 malloc(size) (Memory Allocation)


Description: The malloc() function allocates a specified size of bytes and returns a pointer of void type to
the first byte of the allocated memory block. The allocated memory is uninitialized, meaning it may
contain garbage values. An explicit type conversion (type casting) is necessary to convert the void
pointer to the appropriate data type.
Syntax: ptr = (data_type *)malloc(size);
Where:
• ptr: A pointer variable of type data_type.
• data_type: Any basic data type (e.g., int, float) or user-defined data type.
• size: The number of bytes required (typically calculated as number_of_elements *
sizeof(data_type)).
Example Program:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
int n, sum = 0;
printf("Enter the number of elements: ");
scanf("%d", &n);
// Allocate memory for n integers
arr = (int *)malloc(n * sizeof(int));
// Check if memory allocation was successful
if (arr == NULL) {
printf("Memory not allocated.\n");
return 1; } // Exit the program if memory allocation failed
printf("Enter the elements:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
sum += arr[i]; }
printf("Sum of elements using malloc = %d\n", sum);
// Free the allocated memory
free(arr);
return 0; }

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 16


BCS304 | DATA STRUCTURES AND APPLICATIONS

Explanation:
The program dynamically allocates memory for an array of n integers based on user input using malloc().
After inputting the elements and calculating their sum, the memory is freed using free().

1.8.2 calloc(n, size) (Contiguous Allocation)


Description:
The calloc() function allocates memory for an array of n elements, each of size bytes. It initializes all
allocated memory to zero and returns a pointer of void type to the first byte of the memory block. As
with malloc(), an explicit type conversion is required.
Syntax: ptr = (data_type *)calloc(n, size);
Where:
• ptr: A pointer variable of type data_type.
• data_type: Any basic data type or user-defined data type.
• n: The number of elements to allocate.
• size: The size of each element in bytes (usually sizeof(data_type)).
Example Program:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
int n, sum = 0;
printf("Enter the number of elements: ");
scanf("%d", &n);
// Allocate memory for n integers and initialize to 0
arr = (int *)calloc(n, sizeof(int));
// Check if memory allocation was successful
if (arr == NULL) {
printf("Memory not allocated.\n");
return 1; }
// Input the elements and calculate the sum
printf("Enter the elements:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
sum += arr[i]; }
// Print the sum
printf("Sum of elements using calloc = %d\n", sum);
// Free the allocated memory
free(arr);
return 0;
}
Explanation:
The program allocates memory for an array of n integers using calloc(), initializing the memory to zero.
The elements are input, summed, and the memory is freed afterward.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 17


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.8.3 realloc(ptr, new_size) (Reallocation)


Description:
The realloc() function reallocates the memory block pointed to by ptr to a new size, new_size. It returns
a pointer of void type to the reallocated memory block, which may be at the same location or a new
location depending on memory availability. If the new size is larger, the additional memory is
uninitialized. Type casting is required to convert the returned void pointer.
Syntax: ptr = (data_type *)realloc(ptr, new_size);
Where:
o ptr: A pointer to the previously allocated memory block.
o data_type: Any basic data type or user-defined data type.
o new_size: The new size of the memory block in bytes.
Example Program:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
int n, new_n, sum = 0;
printf("Enter the initial number of elements: ");
scanf("%d", &n);
// Allocate memory for n integers
arr = (int *)malloc(n * sizeof(int));
// Check if memory allocation was successful
if (arr == NULL) {
printf("Memory not allocated.\n");
return 1;
}
// Input the elements
printf("Enter the elements:\n");
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}

// Ask the user for the new size of the array


printf("Enter the new number of elements: ");
scanf("%d", &new_n);

// Reallocate memory to the new size


arr = (int *)realloc(arr, new_n * sizeof(int));

// Check if memory reallocation was successful


if (arr == NULL) {
printf("Memory not reallocated.\n");

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 18


BCS304 | DATA STRUCTURES AND APPLICATIONS

return 1;
}

// Input additional elements if new_n > n


if (new_n > n) {
printf("Enter additional elements:\n");
for (int i = n; i < new_n; i++) {
scanf("%d", &arr[i]);
}
}

// Calculate the sum of all elements


for (int i = 0; i < new_n; i++) {
sum += arr[i];
}

// Print the sum


printf("Sum of elements after realloc = %d\n", sum);

// Free the allocated memory


free(arr);

return 0;
}
Explanation:
The program initially allocates memory for n integers using malloc(). It then reallocates the memory
block to hold new_n integers using realloc(). After inputting any additional elements and calculating the
sum, the memory is freed.

1.8.4 free(ptr) (Deallocation)


Description:
The free() function deallocates the memory block pointed to by ptr, making the memory available for
future allocations. This function does not return a value and does not require type casting.

Syntax:
free(ptr);
Where:
o ptr: A pointer to a previously allocated memory block that needs to be deallocated.

Explanation:
The free() function is used in each of the above examples to deallocate the dynamically allocated
memory, preventing memory leaks. It is essential to free any dynamically allocated memory after it is no
longer needed.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 19


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.9 Overview of Structures and Unions


In C programming, structures and unions are user-defined data types that allow the grouping of
different data types under a single name. They are particularly useful when a program needs to manage
related data items of different types in a logical and organized manner.

1.9.1 Structures
Structure (often abbreviated as struct) is a user-defined data type in C that allows the combination of
data items of different types under a single name. Each data item in a structure is called a member or
field.
Key Characteristics:
• Structures can contain variables of various data types.
• Each member in a structure has its own storage location, meaning all members can hold their
values independently.
• Structures are useful for representing complex data entities, like records or objects.
Basic Syntax:
struct StructureName {
data_type1 member1;
data_type2 member2;
...
};
Example: Basic Structure
#include <stdio.h>

struct Student {
int rollNumber;
char name[50];
float marks;
};

int main() {
struct Student student1;

// Assigning values to members


student1.rollNumber = 101;
strcpy(student1.name, "Alice");
student1.marks = 89.5;
// Accessing and printing structure members
printf("Roll Number: %d\n", student1.rollNumber);
printf("Name: %s\n", student1.name);
printf("Marks: %.2f\n", student1.marks);

return 0;
}

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 20


BCS304 | DATA STRUCTURES AND APPLICATIONS

Explanation:
• Structure Definition: The struct Student defines a structure named Student with three
members: rollNumber (an integer), name (a character array), and marks (a float).
• Structure Variable: The student1 is a variable of type struct Student.
• Accessing Members: Members of the structure are accessed using the dot operator (.) with the
structure variable.

1.9.1.1 Nested Structures


A nested structure is a structure that contains another structure as one of its members. This is useful for
creating complex data models.
Example:
#include <stdio.h>
struct Address {
char city[50];
char state[50];
};
struct Student {
int rollNumber;
char name[50];
float marks;
struct Address addr; // Nested structure
};
int main() {
struct Student student1;
// Assigning values to members
student1.rollNumber = 101;
strcpy(student1.name, "Bob");
student1.marks = 92.5;
strcpy(student1.addr.city, "New York");
strcpy(student1.addr.state, "NY");
// Accessing and printing structure members
printf("Roll Number: %d\n", student1.rollNumber);
printf("Name: %s\n", student1.name);
printf("Marks: %.2f\n", student1.marks);
printf("City: %s\n", student1.addr.city);
printf("State: %s\n", student1.addr.state);
return 0;
}
Explanation:
• The struct Address is nested within struct Student as a member. This allows storing and
accessing related information like a student’s address as part of the Student structure.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 21


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.9.1.2 Structures Using typedef


Using typedef with structures allows you to create an alias for the structure type, making the code
easier to read and write.
Example:
#include <stdio.h>

typedef struct {
int rollNumber;
char name[50];
float marks;
} Student; // Alias 'Student' for the structure

int main() {
Student student1;

// Assigning values to members


student1.rollNumber = 102;
strcpy(student1.name, "Charlie");
student1.marks = 85.0;

// Accessing and printing structure members


printf("Roll Number: %d\n", student1.rollNumber);
printf("Name: %s\n", student1.name);
printf("Marks: %.2f\n", student1.marks);

return 0;
}
Explanation:
• The typedef keyword is used to create an alias Student for the structure type. This allows the
use of Student instead of struct Student when declaring variables.

1.9.1.3 Structures in Functions


Structures can be passed to and returned from functions. They can be passed by value, where a copy of
the structure is passed, or by reference, using pointers.
Passing Structure to a Function (by Value):
#include <stdio.h>

struct Student {
int rollNumber;
char name[50];
float marks;
};

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 22


BCS304 | DATA STRUCTURES AND APPLICATIONS

void printStudent(struct Student s) {


printf("Roll Number: %d\n", s.rollNumber);
printf("Name: %s\n", s.name);
printf("Marks: %.2f\n", s.marks);
}

int main() {
struct Student student1 = {103, "David", 78.5};

// Passing structure to a function


printStudent(student1);

return 0;
}
Explanation:
• The printStudent() function takes a Student structure as an argument and prints its members.
The structure is passed by value, meaning a copy of student1 is passed to the function.

1.9.1.4 Structure Pointers in Functions


Passing a structure by reference (using pointers) can be more efficient, especially for large structures, as
it avoids copying the entire structure.
Example:
#include <stdio.h>

struct Student {
int rollNumber;
char name[50];
float marks;
};

void printStudent(struct Student *s) {


printf("Roll Number: %d\n", s->rollNumber);
printf("Name: %s\n", s->name);
printf("Marks: %.2f\n", s->marks);
}

int main() {
struct Student student1 = {104, "Eve", 91.0};

// Passing structure pointer to a function


printStudent(&student1);

return 0;

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 23


BCS304 | DATA STRUCTURES AND APPLICATIONS

Explanation:
• The printStudent() function now takes a pointer to a Student structure as an argument. The
arrow operator (->) is used to access the members of the structure through the pointer. The
structure is passed by reference, so any changes made within the function would affect the
original structure.

Accessing Structure Members: Dot (.) and Arrow (->) Operators


1. Dot Operator (.):
o The dot operator is used to access members of a structure variable directly.
o Example: student1.rollNumber accesses the rollNumber member of student1.
2. Arrow Operator (->):
o The arrow operator is used to access members of a structure when dealing with
pointers to structures.
o Example: s->rollNumber accesses the rollNumber member through the pointer s.

1.9.1.5 Self-Referential Structure

A self-referential structure is a structure in which one or more members are pointers that
reference the same structure type. This allows the creation of dynamic data structures such as
linked lists, trees, and graphs, where elements are connected to other elements of the same
type.

Characteristics of Self-Referential Structures:

• Pointer to Same Structure Type: A self-referential structure contains a pointer that points to
another structure of the same type.
• Used in Dynamic Data Structures: Self-referential structures are the foundation for many
dynamic data structures, such as linked lists, binary trees, and graphs.
• Memory Allocation: While dynamic memory allocation (malloc() and free()) is commonly
used, self-referential structures can also be created with static memory allocation, as shown in
the textbook example.

Structure Definition:

A basic definition of a self-referential structure in C is as follows:

typedef struct Node {


int data; // Data field
struct Node *link; // Pointer to the next node (self-referential)
}node;

• data: This field stores the data of the node (in this case, an integer).
• link: This pointer of type struct Node points to another node of the same type, making the
structure self-referential.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 24


BCS304 | DATA STRUCTURES AND APPLICATIONS

Example Program: Self-Referential Structure (Without Dynamic Memory)

This program creates a simple linked list of three items without using dynamic memory
allocation.

#include <stdio.h>

// Define a self-referential structure


typedef struct list {
char data; // Data field to store a character
struct list *link; // Pointer to the next node (self-referential)
}List;

int main() {
// Create three static nodes
List item1, item2, item3;

// Initialize data for the nodes


item1.data = 'a'; // First node holds 'a'
item2.data = 'b'; // Second node holds 'b'
item3.data = 'c'; // Third node holds 'c'

// Link the nodes together


item1.link = &item2; // First node points to second
item2.link = &item3; // Second node points to third
item3.link = NULL; // Third node is the last, points to NULL

// Traverse and print the linked list


List *current = &item1;
while (current != NULL) {
printf("%c -> ", current->data);
current = current->link;
}
printf("NULL\n");

return 0;
}

Explanation:

• Structure Definition: The list structure has two members:


o data: Holds the character data.
o link: Points to another list structure, allowing us to link the nodes together.
• Static Node Creation: Instead of using dynamic memory (malloc()), we declare three static
variables (item1, item2, and item3).
• Linking Nodes: We link the nodes by setting the link pointer of each node to the next node,
with the last node’s link set to NULL to indicate the end of the list.
• Traversal: The program uses a loop to traverse the linked list, printing the data field of each
node.

Output:

a -> b -> c -> NULL

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 25


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.9.2 Unions
Union is similar to a structure in that it is also a user-defined data type that can contain different data
types. However, unlike structures, all members of a union share the same memory location. This means
that at any given time, a union can only store a value for one of its members.

Key Characteristics:
• Unions can store different data types, but only one member can hold a value at a time because
all members share the same memory space.
• The size of a union is determined by the size of its largest member.
• Unions are useful when you want to work with different data types in the same memory
location, which can help save memory.
Syntax:
union UnionName {
data_type1 member1;
data_type2 member2;
...
};
Example:
#include <stdio.h>

union Data {
int intValue;
float floatValue;
char charValue;
};

int main() {
union Data data;

// Assigning and accessing integer value


data.intValue = 10;
printf("Integer: %d\n", data.intValue);

// Assigning and accessing float value (overwrites int value)


data.floatValue = 22.5;
printf("Float: %.2f\n", data.floatValue);

// Assigning and accessing char value (overwrites float value)


data.charValue = 'A';
printf("Character: %c\n", data.charValue);

return 0;
}

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 26


BCS304 | DATA STRUCTURES AND APPLICATIONS

Explanation:
• Union Definition: The union Data defines a union named Data with three members: intValue (an
integer), floatValue (a float), and charValue (a character).
• Union Variable: The data is a variable of type union Data.
• Memory Sharing: Since all members share the same memory location, writing to one member
will overwrite the previous value. For example, after setting floatValue, the value in intValue will
no longer be valid.

Differences between Structures and Unions


Feature Structure Union
Memory Allocates separate memory for each All members share the same memory
Allocation member. location.
Size The total size is the sum of the

1.10 Polynomials
Introduction

Viewed from a mathematical perspective, a polynomial is a sum of terms, where each term has
the form axe, where:

• x is the variable,
• a is the coefficient,
• e is the exponent.

For example, a polynomial such as a(x)=15x4+24x2+12x+4 consists of terms that are combined
based on their exponents. Polynomials are widely used in algebra, mathematical computations,
and scientific modeling.

1.10.1 Abstract Data Type (ADT) for Polynomials

The Polynomial ADT defines a set of operations that can be performed on polynomials, such as
creating, accessing, or modifying terms, and performing arithmetic operations like addition and
multiplication.

structure Polynomial is
objects: p(x) = a1xe1 + • • • + anxen; a set of ordered pairs of < ei, ai > where ai in Coefficients and ei
in Exponents, ei are integers >= 0
functions:

for all poly,poly1, poly2 ∈ Polynomial, coefe ∈ Coefficients, expon ∈ Exponents

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 27


BCS304 | DATA STRUCTURES AND APPLICATIONS

Operation
Return Type Function Name Description
Type
Returns a zero polynomial
Polynomial Zero() Creation
p(x)=0
Returns TRUE if the
Boolean IsZero(poly) Check polynomial is zero, otherwise
FALSE.
Returns the coefficient of the
Coefficient Coef(poly, exp) Retrieval term with exponent exp in
poly.
Returns the largest exponent
Exponent Lead_Exp(poly) Information
in the polynomial.
Inserts a new with the term
Polynomial Attach(poly, coef, exp) Modification
<coef, expon> in poly.
Removes the term with
Polynomial Remove(poly, exp) Deletion
exponent exp from poly.
Multiplies the polynomial by
Polynomial SingleMult(poly, coef, exp) Multiplication a. xe where a is the coefficient
and e is the exponent.
Polynomial Add(poly1, poly2)
Adds two polynomials and
Addition
returns the result.
Multiplies two polynomials
Polynomial Mult(poly1, poly2) Multiplication
and returns the result.

Given Polynomials:

1. a(x)=4x3+3x2+5x+6

2. b(x)=5x4+4x2+2x+1

1. Zero()
Operation: This function creates and returns a zero polynomial p(x)=0.

Example:

Polynomial p = Zero();

Output: The polynomial p(x)=0.

2. IsZero(poly)
Operation: This function checks if the polynomial is a zero polynomial.

Example:

Boolean result = IsZero(a);

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 28


BCS304 | DATA STRUCTURES AND APPLICATIONS

Explanation:

• a(x)= 4x3+3x2+5x+6, so IsZero(a) will return FALSE because a(x) is not zero.

• If you call IsZero(p) (where p(x)=0), it will return TRUE.

3. Coef(poly, exp)
Operation: This function retrieves the coefficient of the term with a given exponent in a polynomial.

Example:

float coef = Coef(a, 2); // Coefficient of x² in a(x)

Explanation:
For 4x3+3x2+5x+6, calling Coef(a, 2) will return 3 (the coefficient of x²).

4. Lead_Exp(poly)
Operation: This function returns the largest exponent (leading term) in the polynomial.

Example:

int leadExp = Lead_Exp(b);

Explanation:
For b(x)=5x4+4x2+2x+1, the largest exponent is 4 because 5x⁴ is the leading term.

5. Attach(poly, coef, exp)


Operation: This function inserts a new term coef X x exp into the polynomial.

Example:

Polynomial a_new = Attach(a, 2, 5); // Adding the term 2x⁵ to a(x)

Explanation:

• Adding the term 2x⁵ to a(x)=4x3+3x2+5x+6 will give:

anew(x)=2x5+4x3+3x2+5x+6

6. Remove(poly, exp)
Operation: This function removes the term with a given exponent from the polynomial.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 29


BCS304 | DATA STRUCTURES AND APPLICATIONS

Example:

Polynomial b_new = Remove(b, 2); // Remove x² term from b(x)

Explanation:
For b(x)=5x4+4x2+2x+1, removing the x² term results in:

bnew(x)=5x4+2x+1

7. SingleMult(poly, coef, exp)


Operation: This function multiplies the polynomial by a single term a×xe where a is the coefficient, and e
is the exponent.

Example:

Polynomial result = SingleMult(a, 3, 2); // Multiply a(x) by 3x²

Explanation:
Multiplying a(x)=4x3+3x2+5x+6 by 3x² results in:

result(x) = 12x⁵ + 9x⁴ + 15x³ + 18x²

8. Add(poly1, poly2)
Operation: This function adds two polynomials.

Example:

Polynomial result = Add(a, b); // Add a(x) and b(x)

Explanation:
Adding a(x) = 4x³ + 3x² + 5x + 6 and b(x) = 5x⁴ + 4x² + 2x + 1 gives:

a(x)+b(x)= 5x⁴ + 4x³ + 7x² + 7x + 7

9. Mult(poly1, poly2)
Operation: This function multiplies two polynomials.

Example:

Polynomial result = Mult(a, b); // Multiply a(x) and b(x)

Explanation:
Multiplying a(x) = 4x³ + 3x² + 5x + 6 and b(x) = 5x⁴ + 4x² + 2x + 1 results in:

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 30


BCS304 | DATA STRUCTURES AND APPLICATIONS

a(x)×b(x)= 20x⁷ + 15x⁶ + 38x⁵ + 48x⁴ + 35x³ + 38x² + 17x + 6

1.10.2 Polynomial Representation

Polynomials can be represented in two primary ways:

1. Array Representation: The index represents the exponent, and the value at each index is the
corresponding coefficient.
2. Array of Structures: Each term is stored in a structure containing the coefficient and exponent,
saving memory in sparse polynomials.

1.10.2.1 Array Representation

In array representation, the polynomial is stored in an array where the index is the degree
(exponent) and the value is the coefficient.

Example: Polynomial a(x)= a(x)=15x4+24x2+12x+4

#define MAX_DEGREE 101


typedef struct {
int degree; // Highest degree of the polynomial
float coeff[MAX_DEGREE]; // Array to store coefficients
} Polynomial;

Polynomial a;
a.degree = 4; // Highest degree is 4
a.coeff[4] = 15; // Coefficient for x^4
a.coeff[3] = 0; // Coefficient for x^3 (missing term)
a.coeff[2] = 24; // Coefficient for x^2
a.coeff[1] = 12; // Coefficient for x^1
a.coeff[0] = 4; // Coefficient for x^0 (constant)

In memory, it will look like:

degree coeff [4] coeff [3] coeff [2] coeff [1] coeff [0]
4 15 0 24 12 4

1.10.2.2 Polynomial Representation Using an Array of Structures

For sparse polynomials, an array of structures is used, where each structure contains both the
coefficient and exponent, which makes this more memory-efficient by skipping zero terms.

Structure Definition:
#define MAX_TERMS 7
typedef struct {
float coeff; // Coefficient of the term
int expon; // Exponent (degree) of the term
} PolynomialTerm;

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 31


BCS304 | DATA STRUCTURES AND APPLICATIONS

PolynomialTerm terms[MAX_TERMS]; // Array of structures


int avail = 0; // Keeps track of the next available position

Example: Multiple Polynomials

Consider two polynomials:

• a(x)=15x4+24x2+12x+4
• b(x)=13x3+7x+3

The memory stores only non-zero coefficients and their corresponding degrees, ignoring zero
terms.

Memory Representation
starta finisha startb finishb avail
terms[0] terms[1] terms[2] terms[3] terms[4] terms[5] terms[6]
coeff 15 24 12 4 13 7 3
expon 4 2 1 0 3 1 0

1.10.3 Polynomial Operations


Polynomial Addition

1.10.3.1 : Initial version of padd function


This program adds two polynomials a(x) and b(x) by comparing their leading exponents and attaching
the terms to a result polynomial d(x). This is a simplified version of the polynomial addition function.

Code Structure:

/* a + b, where a, b, and d are polynomials */


d = Zero(); // Initialize the result polynomial d as a zero polynomial
while (!IsZero(a) && !IsZero(b)) {
switch (COMPARE(Lead_Exp(a), Lead_Exp(b))) {
case -1: // If the leading exponent of b is greater than a
d = Attach(d, Coef(b, Lead_Exp(b)), Lead_Exp(b));
b = Remove(b, Lead_Exp(b)); // Remove the leading term from b
break;

case 0: // If the leading exponents of a and b are equal


sum = Coef(a, Lead_Exp(a)) + Coef(b, Lead_Exp(b));
if (sum) {
d = Attach(d, sum, Lead_Exp(a)); // Attach the sum of the coefficients to d
}
a = Remove(a, Lead_Exp(a)); // Remove the leading term from a
b = Remove(b, Lead_Exp(b)); // Remove the leading term from b

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 32


BCS304 | DATA STRUCTURES AND APPLICATIONS

break;

case 1: // If the leading exponent of a is greater than b


d = Attach(d, Coef(a, Lead_Exp(a)), Lead_Exp(a));
a = Remove(a, Lead_Exp(a)); // Remove the leading term from a
break;
}
}
Insert any remaining terms of a or b into d

Explanation:

1. Initialization:

o The result polynomial d(x) is initialized as a zero polynomial using d = Zero(). This means
that d(x)= 0.

2. While Loop:

o The loop continues until one of the input polynomials a(x)or b(x) becomes a zero
polynomial (!IsZero(a) and !IsZero(b)).

o Inside the loop, the leading terms of a(x) and b(x) are compared using the
COMPARE(Lead_Exp(a), Lead_Exp(b)) function. Based on the result of this comparison,
different actions are taken:

3. Switch Cases:

o Case -1: If the leading exponent of b(x) is greater than that of a(x), the leading term
from b(x) is added to d(x), and then it is removed from b(x).

o Case 0: If the leading exponents of a(x) and b(x) are equal, their coefficients are added
together. If the sum of the coefficients is non-zero, the result is attached to d(x). The
leading terms are then removed from both a(x) and b(x).

o Case 1: If the leading exponent of a(x) is greater than that of b(x), the leading term from
a(x) is added to d(x), and then it is removed from a(x).

4. Handling Remaining Terms:

o After the loop exits, any remaining terms in either a(x) or b(x) are attached to the result
polynomial d(x).

Key Functions:

• Lead_Exp(a): Returns the leading exponent (highest degree) of polynomial a(x).

• Coef(a, exp): Returns the coefficient of the term in polynomial a(x) with exponent exp.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 33


BCS304 | DATA STRUCTURES AND APPLICATIONS

• Attach(d, coef, exp): Adds a new term with coefficient coef and exponent exp to the polynomial
d(x).

• Remove(a, exp): Removes the term in polynomial a(x) with exponent exp.

• IsZero(a): Checks if the polynomial a(x) is the zero polynomial.

Example:

Consider the polynomials:

• a(x)=4x3+3x2+5x+6

• b(x)=5x4+4x2+2x+1

The function will:

1. Compare the leading exponents of a(x) and b(x):

o 5x4 from b(x) is added to d(x).

2. Compare the next leading exponents:

o 4x3 from a(x) is added to d(x).

3. Continue comparing and adding terms:

o 7x2 (sum of 3x2 from a(x) and 4x2 from b(x)) is added to d(x).

o 7x (sum of 5x from a(x) and 2x from b(x)) is added to d(x).

o The constant 7 (sum of constants 6 from a(x) and 1 from b(x)) is added to d(x).

The final result is:

d(x)= 5x4 +4x3 +7x2+7x+7

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 34


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.10.3.2 : Function to add two polynomials

This program enhances the initial version of the padd function (Program 2.4), refining how two
polynomials are added. In this version, two polynomials A(x)and B(x) are represented as arrays of terms,
and the function computes their sum D(x). It manages each term of both polynomials and adds them in
decreasing order of exponents.

Code padd Function

void padd(Polynomial *terms, int starta, int finisha, int startb, int finishb, int *startd, int *finishd) {
float coefficient;
*startd = avail; // Start of result polynomial D(x)

while (starta <= finisha && startb <= finishb) {


switch (COMPARE(terms[starta].expon, terms[startb].expon)) {
case -1: // Exponent of B(x) is larger
attach(terms[startd] ,terms[startb].coef, terms[startb].expon);
startb++;
startd++;
break;

case 0: // Exponents are equal


coefficient = terms[starta].coef + terms[startb].coef;
if (coefficient)
attach(terms[startd] ,coefficient, terms[starta].expon);
starta++;
startb++;
startd++;
break;

case 1: // Exponent of A(x) is larger


attach(terms[startd] ,terms[starta].coef, terms[starta].expon);
starta++;
startd++;
break;
}
}

// Add remaining terms of A(x)


for (; starta <= finisha; starta++) {
attach(terms[startd] ,terms[starta].coef, terms[starta].expon);
startd++;
}

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 35


BCS304 | DATA STRUCTURES AND APPLICATIONS

// Add remaining terms of B(x)


for (; startb <= finishb; startb++) {
attach(terms[startd] ,terms[startb].coef, terms[startb].expon);
startd++;
}

*finishd = avail - 1; // End of result polynomial D(x)


}
Explanation of Key Components:

1. Initialization:

o The result polynomial D(x) begins at the current available position in the global array
terms (*startd = avail).

2. While Loop (Main Addition):

o The while loop continues as long as there are terms left in both A(x) and B(x).

o The function compares the exponents of the current terms in A(x) and B(x) using the
COMPARE() function, which returns:

▪ -1 if the exponent of B(x) is greater,

▪ 0 if the exponents are equal, or

▪ 1 if the exponent of A(x) is greater.

3. Switch Cases:

o Case -1: If the exponent of B(x) is greater, the term from B(x) is added to D(x), and the
index for B(x) (startb) is incremented.

o Case 0: If the exponents are equal, the coefficients of both terms are added. If the sum
of the coefficients is non-zero, the new term is added to D(x), and both indices (starta,
startb) are incremented.

o Case 1: If the exponent of A(x) is greater, the term from A(x) is added to D(x), and the
index for A(x) (starta) is incremented.

4. Handling Remaining Terms:

o After the while loop finishes, any remaining terms from either polynomial are added to
D(x). If A(x) still has terms, they are appended to D(x); the same process is followed for
B(x).

5. Finalization:

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 36


BCS304 | DATA STRUCTURES AND APPLICATIONS

o The result polynomial D(x) ends at the next available position in the global array terms
(*finishd = avail - 1).

Helper Functions:

• COMPARE(exp1, exp2): Compares two exponents and returns:

o -1 if exp1 < exp2,

o 0 if exp1 == exp2,

o 1 if exp1 > exp2.

• attach(coefficient, exponent): Adds a new term to the polynomial D(x) at the next available
position in the array.

Example:

Consider two polynomials:

• A(x)=4x3+3x2+5x+6

• B(x)=5x4+4x2+2x+1

Using the above program, the result D(x) would be:

D(x)= 5x4 +4x3 +7x2+7x+7

In this process:

• The leading terms 5x4 from B(x) and 4x3 from A(x) are added to D(x).

• The x2 terms from both polynomials are added together to get 7x2

• The x terms are added to get 7x.

• The constants 6 from A(x) and 1 from B(x) sum to 7.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 37


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.11 Sparse Matrices


A sparse matrix is a matrix with a significant number of zero elements. Instead of storing all elements in
the matrix, we store only the non-zero elements to save space and improve computational efficiency.

1.11.1 Sparse Matrix Abstract Data Type (ADT)


Structure:
A Sparse-Matrix is defined as:

• Objects: A set of triples, <row,column,value>, where row and column are integers and form a
unique combination, and value comes from the set item.

• Functions:
For all a,b ∈ Sparse-Matrix, x ∈ item, and i,j,max-row,max-col ∈ index, we define operations that
can be performed on sparse matrices as follows:

Return Type Function Name Operation Type Description


Returns a sparse matrix that can hold up to
Create(max_row,
Sparse_Matrix Creation max_row * max_col elements. The matrix is
max_col)
initialized with all elements set to zero.
Returns the matrix produced by interchanging
Sparse_Matrix Transpose(a,b) Modification the rows and columns of every non-zero
element in the matrix a.
If matrices a and b have the same dimensions,
returns a new matrix d where d(i,j) = a(i,j) +
Sparse_Matrix Add(a, b) Addition
b(i,j) for all non-zero elements. If dimensions
differ, returns an error.
Multiplies two matrices a and b. For matrix
multiplication to be valid, the number of
Sparse_Matrix Multiply(a, b) Multiplication
columns in a must equal the number of rows
in b.

1.11.2. Sparse Matrix Representation


Instead of storing the entire matrix, a sparse matrix is stored as an array of triples, where each triple
represents a non-zero element. A typical structure for storing a sparse matrix can be defined as follows:

#define MAX_TERMS 101


typedef struct {
int row;
int col;
int value;
} term;

term a[MAX_TERMS]; // Array to store non-zero elements

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 38


BCS304 | DATA STRUCTURES AND APPLICATIONS

The first entry a[0] stores:

• a[0].row: Number of rows in the matrix.

• a[0].col: Number of columns in the matrix.

• a[0].value: Total number of non-zero elements.

Subsequent entries store non-zero elements as triples [row,column,value].

Example of Sparse Matrix Storage

Consider the following sparse matrix:

15 0 0 22 0 -15
0 11 3 0 0 0
0 0 0 -6 0 0
0 0 0 0 0 0
91 0 0 0 0 0
0 0 28 0 0 0

This matrix can be stored as an array of triples:

a Row Column Value


[0] 6 6 8
[1] 0 0 15
[2] 0 3 22
[3] 0 5 -15
[4] 1 1 11
[5] 1 2 3
[6] 2 3 -6
[7] 4 0 91
[8] 5 2 28

1.11.3. Transposing a Sparse Matrix


To transpose a sparse matrix, we interchange the rows and columns of each non-zero element. The
following function transposes a sparse matrix.

Sparse_Matrix transpose(term a[], term b[]) {


int n = a[0].value; // Total number of non-zero elements in matrix a

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 39


BCS304 | DATA STRUCTURES AND APPLICATIONS

b[0].row = a[0].col; // Set number of rows for b to the number of columns in a


b[0].col = a[0].row; // Set number of columns for b to the number of rows in a
b[0].value = n; // Set the number of non-zero elements for b to be the same as a

int currentb = 1; // Index for the next element in the transposed matrix b

// Loop through each column in matrix a


for (int i = 0; i < a[0].col; i++) {
// Find elements in matrix a with column index i
for (int j = 1; j <= n; j++) {
if (a[j].col == i) {
// Assign the transposed element to matrix b
b[currentb].row = a[j].col; // Set row of b to column of a
b[currentb].col = a[j].row; // Set column of b to row of a
b[currentb].value = a[j].value; // Copy the value
currentb++; // Move to the next element in b
}
}
}
}

Explanation:

1. Input Parameters:

o a[]: This is the original sparse matrix stored as an array of triples [row,column,value]

o b[]: This is the transposed sparse matrix, which will store the result of the transpose
operation.

2. Initial Setup:

o The first step is to copy metadata from matrix a to b. Specifically:

▪ Number of rows in b is set to the number of columns in a.

▪ Number of columns in b is set to the number of rows in a.

▪ The number of non-zero elements remains the same in both matrices.

3. Loop Through Columns:

o The outer loop iterates through each column index (i) of the original matrix a. The goal is
to transpose by swapping row and column indices.

4. Find Elements in Each Column:

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 40


BCS304 | DATA STRUCTURES AND APPLICATIONS

o The inner loop (j) iterates over all the non-zero elements in matrix a. Whenever it finds
an element where the column index matches i, it transposes the element by:


Setting the row of matrix b to the column of matrix a.
▪ Setting the column of matrix b to the row of matrix a.
▪ Copying the value from matrix a to matrix b.
5. Updating the Transposed Matrix:

o The variable currentb keeps track of the position in the transposed matrix b[] where the
next transposed element should be stored.

Example:

Consider the following sparse matrix a:

a b
15 0 0 22 0 -15 15 0 0 0 91 0
0 11 3 0 0 0 0 11 0 0 0 0
0 0 0 -6 0 0 0 3 0 0 0 28
0 0 0 0 0 0 22 0 -6 0 0 0
91 0 0 0 0 0 0 0 0 0 0 0
0 0 28 0 0 0 -15 0 0 0 0 0

This matrix has 8 non-zero elements, and they are represented in the array a[] and transposed matrix
represented in matrix b[].

a Row Column Value b Row Column Value


[0] 6 6 8 [0] 6 6 8
[1] 0 0 15 [1] 0 0 15
[2] 0 3 22 [2] 0 4 91
[3] 0 5 -15 [3] 1 1 11
[4] 1 1 11 [4] 2 1 3
[5] 1 2 3 [5] 2 5 28
[6] 2 3 -6 [6] 3 0 22
[7] 4 0 91 [7] 3 2 -6
[8] 5 2 28 [8] 5 0 -15
Operations on Sparse Matrices

• Addition: Combines the non-zero elements of two sparse matrices by summing elements with
the same row and column indices.

• Multiplication: Sparse matrix multiplication requires taking the dot product of rows from one
matrix and columns from the other.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 41


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.12 Representation of Multidimensional Arrays

A multidimensional array is an extension of the one-dimensional and two-dimensional array


concepts to higher dimensions. These arrays are useful when data has multiple levels or
attributes that can be represented along different axes, such as matrices, tensors, or tables with
more than two indices.

1.12.1 Definition:

A multidimensional array is an array with more than one dimension, such as a 2D array (matrix)
or a 3D array (tensor). In C, they are often declared like this:

int array[10][10]; // Two-dimensional array with 10 rows and 10 columns

For a 3D array:

int array[10][10][10]; // Three-dimensional array

If an array is declared as a[upper0][upper1][upper2]...[uppern-1], it contains upper0 * upper1


* ... * uppern-1 elements.

1.12.2 Address Calculation:

To access elements in a multidimensional array stored in memory, a formula calculates the


memory location of an element based on its indices.

The two primary ways to store multidimensional arrays in memory are:

1. Row-major Order: This stores array elements row by row, which is common in C.
2. Column-major Order: This stores elements column by column, typical in languages like Fortran.

Row-major Order:

Row-major order stores the elements of the array sequentially by rows. This means that the entire
first row is stored, followed by the entire second row, and so on.

For a two-dimensional array A[upper0][upper1], the formula to calculate the address of element
A[i][j] is:

Address of A[i][j]=Base Address of A+(i×upper1+j)×Element Size

Where:

• i is the row index


• j is the column index
• upper1 is the number of columns in each row
• Element Size is the size of each array element in memory (for example, 4 bytes for an int).

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 42


BCS304 | DATA STRUCTURES AND APPLICATIONS

For a 3D array A[upper0][upper1][upper2], the memory address for element


A[i][j][k]A[i][j][k]A[i][j][k] can be computed as:

Address of A[i][j][k]=Base Address of A+((i×upper1×upper2)+(j×upper2)+k)×Element Size

Example:
For a 2D array A[3][4]A[3][4]A[3][4]:

int A[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};

The memory layout of this array in row-major order would be:

1,2,3,4,5,6,7,8,9,10,11,12

To calculate the memory address of A[2][3], where i=2i = 2i=2 and j=3j = 3j=3:

Address of A[2][3]=Base Address of A+(2×4+3)×Element Size

1.12.4 General Address Formula for n-Dimensional Arrays:


For an n-dimensional array A[upper0][upper1]...[uppern−1], the address of an element A[i0][i1]...[in−1]
can be generalized as:

This formula ensures that the correct offset is calculated for each element based on its position in
the multidimensional array.

Example (2D Array):

Consider a 2D array A[3][4], and you want to calculate the address of the element A[2][3].

• Base Address: Let's assume the base address of AAA is 1000.


• Array dimensions: upper0=3 (rows) and upper1=4 (columns).
• Indexes: i0=2 (row), i1=3 (column).
• Element Size: Let's assume each element is 4 bytes.

Applying the Formula:

Address of A[2][3]=Base Address of A+(i0×upper1+i1)×Element Size

=1000+(2×4+3)×4

=1000+(8+3)×4

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 43


BCS304 | DATA STRUCTURES AND APPLICATIONS

=1000+11×4

=1000+44=1044

Thus, the address of A[2][3] is 1044.

1.12.5 Advantages of Multidimensional Arrays:

• Efficient Storage: Data can be stored in a contiguous block of memory, which helps in faster
access and retrieval.
• Data Organization: It provides a structured way to organize data with multiple dimensions, such
as matrices or higher-dimensional tables.

Disadvantages:

• Memory Usage: Multidimensional arrays can consume large amounts of memory if the
dimensions are large, especially when declared statically.
• Complex Address Calculation: As the number of dimensions increases, the complexity of
calculating memory addresses increases.

This method is fundamental in handling multidimensional data structures such as matrices,


tensors, and other data that needs structured storage across several axes.

1.13 Strings

A String is an abstract data type (ADT) that represents a sequence of characters. Strings are one
of the most common data structures used in programming, especially for handling text.

1.13.1. String Abstract Data Type (ADT)

A string ADT is defined by:

• Objects: A finite set of zero or more characters.


• Functions: For all s,t ∈ Strings and i,j,m ∈ N (non-negative integers), the following
operations are defined:

Operations on Strings

The essential operations that can be defined for a string ADT are as follows:

Return Type Function Name Operation Type Description


String Null(m) Creation Creates a string that can hold up to mmm
characters but is initially empty (NULL).
Integer Compare(s, t) Comparison Compares two strings s and t. Returns 0 if they
are equal, -1 if s precedes t, and 1 if s follows t.
Boolean IsNull(s) Check Returns TRUE if the string s is NULL (empty).
Integer Length(s) Information Returns the length of the string s, i.e., the

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 44


BCS304 | DATA STRUCTURES AND APPLICATIONS

number of characters in it.


String Concat(s, t) Concatenation Concatenates two strings s and t, returning a
new string where t is appended to s.
String Substr(s, z, l) Substring Returns a substring of s starting from position z
Extraction and of length l.

1.13.2 Representation of Strings in C

In the C programming language, strings are typically represented as character arrays that end
with a null character (\0), which indicates the end of the string.

char s[] = "dog";


char t[] = "house";

In the above example, s holds the string "dog" and t holds the string "house". These arrays
include the null character (\0) at the end to mark the string's termination.

Example:

To concatenate the strings "dog" and "house" into the string "doghouse", we can use the
strcat function from the C standard library:

#include <stdio.h>
#include <string.h>

int main() {
char s[100] = "dog";
char t[] = "house";
strcat(s, t); // Concatenate t to s
printf("%s\n", s); // Outputs "doghouse"
return 0;
}

Here, the function strcat(s, t) appends the string t to s.

1.13.3 String Operations in C

Some of the most common string functions in C are:

Function Description
strcat(char *dest, const char *src) Concatenates src to the end of dest.
strcmp(const char *str1, const char *str2) Compares two strings lexicographically.
strcpy(char *dest, const char *src) Copies the string src to dest.
strlen(const char *str) Returns the length of the string str.
Returns a pointer to the first occurrence
strchr(const char *str, int c)
of the character c in str.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 45


BCS304 | DATA STRUCTURES AND APPLICATIONS

strstr(const char *haystack, const char Returns a pointer to the first occurrence
*needle) of the substring needle in haystack.

Example of Inserting a Substring

Inserting one string into another is a common string operation. Suppose we have two strings, s1
and s2, and we want to insert s2 into s1 at position i.

#include <stdio.h>
#include <string.h>

void insert(char *s1, char *s2, int pos) {


char temp[100];
strncpy(temp, s1, pos); // Copy first part of s1
temp[pos] = '\0';
strcat(temp, s2); // Append s2
strcat(temp, s1 + pos); // Append the remaining part of s1
strcpy(s1, temp); // Copy back to s1
}

int main() {
char s1[100] = "Hello World!";
char s2[] = "Beautiful ";
insert(s1, s2, 6); // Insert s2 into s1 at position 6
printf("%s\n", s1); // Outputs "Hello Beautiful World!"
return 0;
}

String Pattern Matching

String pattern matching is used to find a specific substring (pattern) within a larger string. The
simplest method is to use the strstr function, which returns a pointer to the first occurrence of
the pattern in the string.

Example of Pattern Matching:


#include <stdio.h>
#include <string.h>

int main() {
char str[] = "The quick brown fox";
char pat[] = "brown";
char *result = strstr(str, pat);
if (result) {
printf("Pattern found at position: %ld\n", result - str);
} else {
printf("Pattern not found.\n");
}
return 0;
}

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 46


BCS304 | DATA STRUCTURES AND APPLICATIONS

Here, strstr returns the pointer to the first occurrence of pat in str, and we calculate its
position by subtracting the base pointer of str.

1.14 Stacks

A stack is a fundamental data structure that operates under the Last In, First Out (LIFO)
principle. This means that the last element added to the stack is the first one to be removed. It’s
akin to stacking plates on top of each other: the last plate you put on the pile is the first one you
take off when you need one.

Key Characteristics of a Stack:

• LIFO Principle: The last item added (pushed) to the stack is the first item to be removed
(popped).
• Operations:
o Push: Add an element to the top of the stack.
o Pop: Remove and return the element at the top of the stack.
o Peek or Top: View the element at the top of the stack without removing it.
o IsEmpty: Check if the stack is empty.
o IsFull (for fixed-size stacks): Check if the stack has reached its maximum capacity.

Stacks are often used for managing data in recursive algorithms, expression evaluation, and
backtracking problems.

1.14.1 Stack Abstract Data Type (ADT):


• Objects: A stack is an ordered list where insertions and deletions occur at one end, called
the top.
• Functions: For all stack s ∈ Stacks, item e ∈ elements, max-stack-size ∈positive integers.

ADT Functions for Stacks


Return Function Operation
Description
Type Name Type
Stack CreateStack(n) Creation Creates an empty stack with a maximum size of n.
Boolean IsFull(S) Check Returns TRUE if the stack S is full.
Boolean IsEmpty(S) Check Returns TRUE if the stack S is empty.
Void Push(S, item) Insertion Adds an element item to the top of the stack S.
Removes and returns the element at the top of the
Element Pop(S) Deletion
stack S.
Returns the element at the top of the stack S without
Element Peek(S) Access
removing it.

1. CreateStack(n) - Creation

This function creates a stack of size n and initializes the top to -1.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 47


BCS304 | DATA STRUCTURES AND APPLICATIONS

#include <stdio.h>
#include <stdlib.h>

int *stack = NULL; // Pointer to dynamically allocated stack


int top = -1;

// Creates a stack that can hold up to 'n' elements dynamically


void CreateStack(int size) {
stack = (int*)malloc(size * sizeof(int)); // Allocate memory dynamically
for the stack
if (stack == NULL) {
printf("Memory allocation failed!\n");
exit(1);
}
top = -1; // Initialize the top index to -1 (indicating an empty
stack)
printf("Stack created with size: %d\n", size);
}

int main() {
int size;
printf("Enter the size of the stack: ");
scanf("%d", &size);

CreateStack(size); // Create a stack with the user-defined size

// Don't forget to free the allocated memory when done


free(stack);

return 0;
}

2. IsFull(S) - Check

This function checks if the stack is full by comparing the top index with the maximum size.

// Returns TRUE if the stack is full


int IsFull() {
return top == MAX - 1; // Stack is full when 'top' equals MAX - 1
}

int main() {
if (IsFull()) {
printf("Stack is full\n");
} else {
printf("Stack is not full\n");
}
return 0;

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 48


BCS304 | DATA STRUCTURES AND APPLICATIONS

3. IsEmpty(S) - Check

This function checks if the stack is empty by checking if the top index is -1.

// Returns TRUE if the stack is empty


int IsEmpty() {
return top == -1; // Stack is empty when 'top' equals -1
}

int main() {
if (IsEmpty()) {
printf("Stack is empty\n");
} else {
printf("Stack is not empty\n");
}
return 0;
}

4. Push(S, item) - Insertion

This function pushes an item onto the stack. It first checks if the stack is full, then increments the
top and adds the item.

// Pushes an item to the stack


void Push(int item) {
if (IsFull()) {
printf("Stack Overflow\n");
} else {
stack[++top] = item;
printf("Pushed %d to stack\n", item);
}
}

int main() {
Push(10); // Push 10 onto the stack
Push(20); // Push 20 onto the stack
return 0;
}

5. Pop(S) - Deletion

This function pops the top element from the stack. It checks if the stack is empty before popping.

// Pops an item from the stack


int Pop() {
if (IsEmpty()) {
printf("Stack Underflow\n");
return -1; // Return -1 to indicate an empty stack
} else {

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 49


BCS304 | DATA STRUCTURES AND APPLICATIONS

return stack[top--]; // Return the top element and decrement


the top index
}
}

int main() {
Push(10);
Push(20);
printf("Popped: %d\n", Pop()); // Pops 20
printf("Popped: %d\n", Pop()); // Pops 10
return 0;
}

6. Peek(S) - Access

This function returns the top element of the stack without removing it. It checks if the stack is
empty.

// Returns the top element without removing it


int Peek() {
if (IsEmpty()) {
printf("Stack is empty\n");
return -1; // Return -1 to indicate an empty stack
} else {
return stack[top]; // Return the top element
}
}

int main() {
Push(10);
Push(20);
printf("Top element: %d\n", Peek()); // Returns 20 without
removing it
return 0;
}

1.14.2 Representation of Stacks

Static Stack (Array Representation):

Stacks can be implemented using a one-dimensional array. The variable top keeps track of the
index of the top element in the stack. Initially, the top is set to -1 to indicate that the stack is
empty.

Operations on Static Stack:

1. Push Operation:
o Before adding an element, the IsFull function checks if there is space in the stack.
o If the stack is not full, increment the top and insert the new element at stack[++top].
2. Pop Operation:
o The IsEmpty function checks if the stack is empty before removing an element.
o If not empty, return the top element and decrement the top.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 50


BCS304 | DATA STRUCTURES AND APPLICATIONS

Here is a simple program that demonstrates push, pop, and display operations on a stack
implemented using an array in C.

Stack Program: Push, Pop, and Display


#include <stdio.h>
#define MAX 5 // Maximum size of the stack

int stack[MAX]; // Stack array


int top = -1; // Stack top index

// Function to push an element onto the stack


void Push(int item) {
if (top == MAX - 1) {
printf("Stack Overflow! Cannot push %d\n", item);
} else {
stack[++top] = item;//Increment top and add the item to the stack
printf("Pushed %d onto the stack.\n", item);
}
}

// Function to pop an element from the stack


int Pop() {
if (top == -1) {
printf("Stack Underflow! Stack is empty.\n");
return -1; // Return -1 to indicate the stack is empty
} else {
printf("Popped %d from the stack.\n", stack[top]);
return stack[top--];// Return the top element and decrement top
}
}

// Function to display all elements in the stack


void Display() {
if (top == -1) {
printf("Stack is empty!\n");
} else {
printf("Stack elements: ");
for (int i = 0; i <= top; i++) {
printf("%d ", stack[i]);
}
printf("\n");
}
}

int main() {
// Demonstrate push operations
Push(10);
Push(20);
Push(30);
Display(); // Display current stack elements

// Demonstrate pop operation


Pop(); // Pop the top element
Display(); // Display current stack elements

// Push another element


Push(40);

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 51


BCS304 | DATA STRUCTURES AND APPLICATIONS

Display(); // Display current stack elements

return 0;
}

Explanation:

1. Push Function: Adds an item to the stack if the stack is not full. If the stack is full, it prints an
overflow error.
2. Pop Function: Removes and returns the top element from the stack if it's not empty. If the stack
is empty, it prints an underflow error.
3. Display Function: Displays all the elements in the stack from bottom to top.

Sample Output:
Pushed 10 onto the stack.
Pushed 20 onto the stack.
Pushed 30 onto the stack.
Stack elements: 10 20 30
Popped 30 from the stack.
Stack elements: 10 20
Pushed 40 onto the stack.
Stack elements: 10 20 40

Here is the same program using a structure to represent the stack, including the push, pop, and
display operations.

Stack Program Using Structure: Push, Pop, and Display


#include <stdio.h>
#define MAX 5 // Maximum size of the stack

// Define a structure for the stack

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 52


BCS304 | DATA STRUCTURES AND APPLICATIONS

struct Stack {
int items[MAX]; // Array to hold stack elements
int top; // Index of the top element
} S; // Global instance of the Stack

// Function to push an element onto the stack


void Push(int item) {
if (S.top == MAX - 1) {
printf("Stack Overflow! Cannot push %d\n", item);
} else {
S.items[++S.top] = item;
printf("Pushed %d onto the stack.\n", item);
}
}

// Function to pop an element from the stack


int Pop() {
if (S.top == -1) {
printf("Stack Underflow! Stack is empty.\n");
return -1; // Return -1 to indicate the stack is empty
} else {
int item = S.items[S.top]; // Fetch the top item
printf("Popped %d from the stack.\n", item);
S.top--; // Decrement top
return item;
}
}

// Function to display all elements in the stack


void Display() {
if (S.top == -1) {
printf("Stack is empty!\n");
} else {
printf("Stack elements: ");
for (int i = S.top; i >=0; i--) {
printf("%d ", S.items[i]);
}
printf("\n");
}
}

int main() {
S.top = -1; // Initialize the stack top as empty

// Demonstrate push operations


Push(10);
Push(20);
Push(30);
Display(); // Display current stack elements
// Demonstrate pop operation
Pop(); // Pop the top element
Display(); // Display current stack elements

// Push another element


Push(40);
Display(); // Display current stack elements
return 0;
}

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 53


BCS304 | DATA STRUCTURES AND APPLICATIONS

Explanation:

1. Stack Structure:
o The stack is represented as a structure Stack containing an array items to hold the
elements and an integer top to track the top index.
2. InitStack Function:
o Initializes the stack by setting the top to -1 to indicate that the stack is empty.
3. Push Function:
o Adds an element to the top of the stack if it is not full. Otherwise, it prints an overflow
message.
4. Pop Function:
o Removes and returns the top element from the stack if it is not empty. Otherwise, it
prints an underflow message.
5. Display Function:
o Displays all elements of the stack from the bottom to the top.

Sample Output:
Stack elements: 10 20 30
Popped 30 from the stack.
Stack elements: 10 20
Pushed 40 onto the stack.
Stack elements: 10 20 40

1.14.3 Stack Using Dynamic Array

In this implementation, the stack is dynamically allocated using malloc and resized using
realloc to accommodate new elements as they are pushed onto the stack. The stack size begins
with 1 and expands by 1 element each time a new item is pushed.

Key Concepts:

1. Dynamic Memory Allocation:


o The stack is not allocated a fixed size at the start. Instead, it begins with size 1 and grows
dynamically as more elements are added.
2. malloc:
o Used to allocate memory for the stack when the first element is pushed.
3. realloc:
o Used to resize the stack each time an element is pushed. The stack size is incremented
by 1 for each push operation.
4. free:
o The realloc function adjusts the memory block to the new size but doesn't free the
unused memory automatically. In practice, free should be called when the stack is no
longer in use.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 54


BCS304 | DATA STRUCTURES AND APPLICATIONS

Stack Operations Using Dynamic Array

Here is a simple program demonstrating push and pop operations using dynamic memory
allocation:

#include <stdio.h>
#include <stdlib.h>
int *stack = NULL; // Dynamic array for the stack
int top = -1; // Top of the stack (index)
int size = 0; // Current size of the stack
// Function to push an element onto the stack
void Push(int item) {
if (size == 0) {
// Initial allocation for the stack (size 1)
stack = (int*)malloc(sizeof(int));
size = 1;
} else {
// Resize the stack by 1 using realloc
size++;
stack = (int*)realloc(stack, size * sizeof(int));
}

// Increment the top and add the item to the stack


stack[++top] = item;
printf("Pushed %d onto the stack. Current size: %d\n", item, size);
}

// Function to pop an element from the stack


int Pop() {
if (top == -1) {
printf("Stack Underflow! Stack is empty.\n");
return -1; // Return -1 to indicate the stack is empty
} else {
int item = stack[top--]; // Remove the top element
size--; // Decrease the stack size
// Resize the stack using realloc if needed
stack = (int*)realloc(stack, size * sizeof(int));
printf("Popped %d from the stack. Current size: %d\n", item, size);
return item;
}
}
int main() {
// Demonstrate push operations
Push(10);
Push(20);
Push(30);

// Demonstrate pop operations


Pop(); // Pop the top element
Pop(); // Pop the top element

// Push another element


Push(40);
// Free the dynamically allocated memory for the stack
free(stack);
return 0;
}

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 55


BCS304 | DATA STRUCTURES AND APPLICATIONS

Explanation:

1. Push Function:
o Initially, the stack size is set to 0, and when the first element is pushed, malloc is used
to allocate memory for 1 integer.
o For subsequent pushes, realloc is used to increase the size of the stack by 1 and
adjust the memory block size.
o The top index is incremented, and the new item is added to the stack.
2. Pop Function:
o Before popping, the function checks if the stack is empty by checking if top is -1.
o If the stack is not empty, the top element is removed, the size is reduced, and realloc
is called to shrink the memory block.
3. Memory Management:
o After all operations, free(stack) is called to release the memory allocated to the
stack dynamically. This prevents memory leaks.

Output Example:
Pushed 10 onto the stack. Current size: 1
Pushed 20 onto the stack. Current size: 2
Pushed 30 onto the stack. Current size: 3
Popped 30 from the stack. Current size: 2
Popped 20 from the stack. Current size: 1
Pushed 40 onto the stack. Current size: 2

1.15 Applications of Stack


1.15.1 Used in Function Calls
• Stacks are used to manage function calls in programming. Each function call creates a stack
frame that stores the function’s local variables, parameters, and return address. When the
function finishes execution, the frame is popped from the stack, and control returns to the
calling function.

1.15.2 Used in Conversion of Expressions


• Stacks are used to convert infix expressions (like A+BA + BA+B) into postfix (Reverse Polish
Notation) or prefix expressions. This simplifies the process of expression evaluation, especially in
calculators and compilers.

1.15.3 Evaluation of Expressions


• Arithmetic expressions in postfix or prefix format can be evaluated using stacks. In postfix form,
operators follow the operands, making the stack-based evaluation straightforward by pushing
operands and applying operators when encountered.

1.15.4 Used in Recursion


• Recursive function calls use the system stack to store return addresses and local variables. Every
recursive call pushes a new frame onto the stack, and when the base case is reached, frames are
popped off as the recursion unwinds.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 56


BCS304 | DATA STRUCTURES AND APPLICATIONS

1.15.5 Three Types of Arithmetic Expressions

1. Infix: Operators are placed between operands (e.g., A+B). Requires parentheses to specify
precedence.
2. Postfix: Operators come after operands (e.g., AB+). No need for parentheses, and evaluated left
to right.
3. Prefix: Operators come before operands (e.g., +AB). Evaluated right to left without parentheses.

1.15.6 Steps to Evaluate Arithmetic Expressions

Step 1: Convert Infix Expression to Postfix

• Use an algorithm to convert infix (e.g., A+B) to postfix (e.g., AB+).

Step 2: Evaluate Postfix Expression

• Once in postfix form, the expression can be evaluated using a stack. Operands are pushed onto
the stack, and when an operator is encountered, it is applied to the top elements of the stack.

1.15.6.1 Conversion of Infix to Postfix Expression (Algorithm)


STEP 1: Push # onto the stack.
STEP 2: Scan the expression from left to right.
STEP 3: If a '(' is encountered, push it onto the stack.
STEP 4: If an operand is encountered, add it to the postfix expression P.
STEP 5: If an operator is encountered:
a) Check if the current operator has lower or equal precedence than the operator on top of
the stack.
b) If so, pop operators from the stack and add them to P, then push the current operator.
STEP 6: If a ')' is encountered, pop from the stack until the matching '(' is found and add
everything to P.
STEP 7: After scanning, pop all remaining operators from the stack and add them to P.

1.15.7 Infix to postfix conversion

Example 1: Conversion of (a * b) + c

The simplified method to convert the infix expression (a∗b)+c directly to postfix without
explicitly using a stack involves recognizing basic patterns of operator precedence and
associativity. Here's how you can convert it:

(a * b) + c becomes ab*c+ directly by following these rules:

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 57


BCS304 | DATA STRUCTURES AND APPLICATIONS

Simplified Steps:

1. Identify the innermost parenthesis or the highest precedence operator.


2. Convert this expression to postfix by placing the operator after its operands.
3. Replace the converted part in the original expression.
4. Repeat until the entire expression is converted.

For (a∗b)+c:

• Convert a∗b to ab∗.


• Then apply + to the result and c, resulting in ab∗c+.

Infix to Postfix Conversion Steps using STACK:


( a*b)+ c
0 1 2 34 5 6
• top: Indicates the current index of the top element in the stack.
• pos: Shows the position in the postfix expression where the next character will be placed.
Initially top=0 and pos=0
Step Symbol Postfix Stack Action Variable
initial - - # Push # top=0, pos=0
0 ( - #, ( Push ( to stack top=1, pos=0
1 a a #, ( Add a to postfix top=1, pos=1
2 * a #, (, * Push * to stack top=2, pos=1
3 b ab #, (, * Add b to postfix top=2, pos=2
4 ) ab* # Pop *, apply to ab top=0, pos=3
5 + ab* #, + Push + to stack top=1, pos=3
6 c ab*c #+ Add c to postfix top=1, pos=4
7 End ab*c+ # Pop +, apply to ab*c top=0, pos=5

End- Place the remaining operators i.e ‘+’ into the Postfix. So, Postfix expression will be ab*c+

Example 2: Conversion of a + b * c - d / e
Step Symbol Postfix Stack Action Variable
initial - - # Push # to stack top=0, pos=0
0 a a # Add a to postfix top=0, pos=1
1 + a #+ Push + to stack top=1, pos=1
2 b ab #+ Add b to postfix top=1, pos=2
3 * ab #+* Push * to stack top=2, pos=2
4 c abc #+* Add c to postfix top=2, pos=3
5 - abc*+ #- Pop *, Pop +, Push - top=1, pos=5

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 58


BCS304 | DATA STRUCTURES AND APPLICATIONS

Step Symbol Postfix Stack Action Variable


6 d abc*+d #- Add d to postfix top=1, pos=6
7 / abc*+d #-/ Push / to stack top=2, pos=6
8 e abc*+de # -/ Add e to postfix top=2, pos=7
9 End abc*+de/- # Pop /, Pop -, apply to postfix top=0, pos=9

End- Place the remaining operators i.e ‘-’ into the Postfix. So, Postfix expression will be abc*+de/-

Example 3: Conversion of x * y + (a - b)
Step Symbol Postfix Stack Action Variable
init - - # Push # to stack top=0, pos=0
0 x x # Add x to postfix top=0, pos=1
1 * x #* Push * to stack top=1, pos=1
2 y xy #* Add y to postfix top=1, pos=2
3 + xy* #+ Pop *, Push + to stack top=1, pos=3
4 ( xy* #+( Push ( to stack top=2, pos=3
5 a xy*a #+( Add a to postfix top=2, pos=4
6 - xy*a #+(- Push - to stack top=3, pos=4
7 b xy*ab #+(- Add b to postfix top=3, pos=5
8 ) x y * a b- #+ Pop -, apply to postfix top=1, pos=6
9 End x y * a b- + # Pop +, apply to postfix top=0, pos=7
Final result: xy*ab-+

Example 4: Conversion of (p + q) * r - s
Step Symbol Postfix Stack Action Variable
init - - # Push # to stack top=0, pos=0
0 ( - #( Push ( to stack top=1, pos=0
1 p p #( Add p to postfix top=1, pos=1
2 + p #(+ Push + to stack top=2, pos=1
3 q pq #(+ Add q to postfix top=2, pos=2
4 ) pq+ # Pop +, apply to postfix top=0, pos=3
5 * pq+ #* Push * to stack top=1, pos=3
6 r pq+r #* Add r to postfix top=1, pos=4
7 - pq+r* #- Pop *, Push - to stack top=1, pos=5
8 s pq+r*s #- Add s to postfix top=1, pos=6

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 59


BCS304 | DATA STRUCTURES AND APPLICATIONS

Step Symbol Postfix Stack Action Variable


9 End pq+r*s- # Pop -, apply to postfix top=0, pos=7
Final result: pq+r*s-

Example 5: Conversion of h + i * (j - k) / l
Step Symbol Postfix Stack Action Variable
init - - # Push # to stack top=0, pos=0
0 h h # Add h to postfix top=0, pos=1
1 + h #+ Push + to stack top=1, pos=1
2 i hi #+ Add i to postfix top=1, pos=2
3 * hi #+* Push * to stack top=2, pos=2
4 ( hi #+*( Push ( to stack top=3, pos=2
5 j hij #+*( Add j to postfix top=3, pos=3
6 - hij #+*(- Push - to stack top=4, pos=3
7 k hijk #+*(- Add k to postfix top=4, pos=4
8 ) hijk- #+* Pop -, apply to postfix top=2, pos=5
9 / hijk- #+/ Pop *, Push / to stack top=2, pos=5
10 l hijk-l #+/ Add l to postfix top=2, pos=6
11 End hijk-l/+ # Pop /, *, +, apply to postfix top=0, pos=7
Final result: hijkl-/*+

1.15.8 Evaluation of Postfix Expression


The process of evaluating a postfix expression is much simpler than evaluating an infix expression. This is
because there are no parentheses to account for, and the order of operations is already determined in
postfix notation. The evaluation proceeds by scanning the postfix expression from left to right. Each
operand is pushed onto a stack until an operator is encountered. When an operator is found, the
necessary number of operands are popped from the stack, the operation is performed, and the result is
pushed back onto the stack.

1.5.8.1 Algorithm for Evaluation of Postfix Expression


Step 1: Initialize an empty stack to hold operands during evaluation. Scan the postfix expression from
left to right.
Step 2: If the symbol is an operand, push it onto the stack.
Step 3: If the symbol is an operator, perform the following steps:
a) Pop the required number of operands from the stack (for binary operators, pop two
operands).
b) Assign the first operand popped to opnd2 and the second operand popped to opnd1.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 60


BCS304 | DATA STRUCTURES AND APPLICATIONS

c) Perform the operation using the current operator: res = opnd1 (operator) opnd2.
d) Push the result of the operation (res) back onto the stack.
Step 4: Continue scanning the postfix expression until all symbols are processed.
Step 5: The final result of the postfix expression will be the only value remaining on the stack. Pop this
value to obtain the result.

Example 1: 7 8+6 5+*


Step Symbol Operand1 (opnd1) Operand2 (opnd2) Stack Operation Description
0 7 - - 7 Push '7' to the stack.
1 8 - - 7, 8 Push '8' to the stack.
2 + 7 8 15 Pop '7' and '8', add them, push '15'.
3 6 - - 15, 6 Push '6' to the stack.
4 5 - - 15, 6, 5 Push '5' to the stack.
5 + 6 5 15, 11 Pop '6' and '5', add them, push '11'.
6 * 15 11 165 Pop '15' and '11', multiply, push '165'.

Final result: 165

Example 2: 5 6 2 + * 12 4 / -
Step Symbol Operand1 (opnd1) Operand2 (opnd2) Stack Operation Description
0 5 - - 5 Push '5' to the stack.
1 6 - - 5, 6 Push '6' to the stack.
2 2 - - 5, 6, 2 Push '2' to the stack.
3 + 6 2 5, 8 Pop '6' and '2', add them, push '8'.
4 * 5 8 40 Pop '5' and '8', multiply, push '40'.
5 12 - - 40, 12 Push '12' to the stack.
6 4 - - 40, 12, 4 Push '4' to the stack.
7 / 12 4 40, 3 Pop '12' and '4', divide, push '3'.
8 - 40 3 37 Pop '40' and '3', subtract, push '37'.
Final result: 37

Example 3: 9 8 - 7 +
Step Symbol Operand1 (opnd1) Operand2 (opnd2) Stack Operation Description
0 9 - - 9 Push '9' to the stack.
1 8 - - 9, 8 Push '8' to the stack.
2 - 9 8 1 Pop '9' and '8', subtract, push '1'.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 61


BCS304 | DATA STRUCTURES AND APPLICATIONS

Step Symbol Operand1 (opnd1) Operand2 (opnd2) Stack Operation Description


3 7 - - 1, 7 Push '7' to the stack.
4 + 1 7 8 Pop '1' and '7', add, push '8'.
Final result: 8

Example 4: 3 4 2 * 1 5 - 2 3 ^ / +
Step Symbol Operand1 (opnd1) Operand2 (opnd2) Stack Operation Description
0 3 - - 3 Push '3' to the stack.
1 4 - - 3, 4 Push '4' to the stack.
2 2 - - 3, 4, 2 Push '2' to the stack.
3 * 4 2 3, 8 Pop '4' and '2', multiply, push '8'.
4 1 - - 3, 8, 1 Push '1' to the stack.
5 5 - - 3, 8, 1, 5 Push '5' to the stack.
6 - 1 5 3, 8, -4 Pop '1' and '5', subtract, push '-4'.
7 2 - - 3, 8, -4, 2 Push '2' to the stack.
8 3 - - 3, 8, -4, 2, 3 Push '3' to the stack.
9 ^ 2 3 3, 8, -4, 8 Pop '2' and '3', exponentiate, push '8'.
10 / -4 8 3, 8, -0.5 Pop '-4' and '8', divide, push '-0.5'.
11 + 3 8 3, 7.5 Pop '3' and '8', add, push '7.5'.
Final result: 7.5

Example 5: Postfix Expression 9 3 1 - 3 * + 10 2 / +


Step Symbol Operand1 (opnd1) Operand2 (opnd2) Stack Operation Description
0 9 - - 9 Push '9' to the stack.
1 3 - - 9, 3 Push '3' to the stack.
2 1 - - 9, 3, 1 Push '1' to the stack.
3 - 3 1 9, 2 Pop '3' and '1', subtract (2), push '2'.
4 3 - - 9, 2, 3 Push '3' to the stack.
5 * 2 3 9, 6 Pop '2' and '3', multiply (6), push '6'.
6 + 9 6 15 Pop '9' and '6', add (15), push '15'.
7 10 - - 15, 10 Push '10' to the stack.
8 2 - - 15, 10, 2 Push '2' to the stack.
9 / 10 2 15, 5 Pop '10' and '2', divide (5), push '5'.
10 + 15 5 20 Pop '15' and '5', add (20), push '20'.
Final result: 20

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 62


BCS304 | DATA STRUCTURES AND APPLICATIONS

Example 6: Postfix Expression 7 4 5 + * 2 3 ^ /


Step Symbol Operand1 opnd1) Operand2(opnd2) Stack Operation Description
0 7 - - 7 Push '7' to the stack.
1 4 - - 7, 4 Push '4' to the stack.
2 5 - - 7, 4, 5 Push '5' to the stack.
3 + 4 5 7, 9 Pop '4' and '5', add (9), push '9'.
4 * 7 9 63 Pop '7' and '9', multiply (63), push '63'.
5 2 - - 63, 2 Push '2' to the stack.
6 3 - - 63, 2, 3 Push '3' to the stack.
7 ^ 2 3 63, 8 Pop '2' and '3', exponentiate (8), push '8'.
8 / 63 8 7.875 Pop '63' and '8', divide (7.875), push '7.875'.
Final result: 7.875

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 63


BCS304 | DATA STRUCTURES AND APPLICATIONS

2. Queues
What is a Queue?
A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle. This means that the
element that is inserted first is the one that is removed first. A queue is an ordered list of elements
where insertions happen at one end, called the rear, and deletions happen from the other end, called
the front.
Key Operations:
• Enqueue: Insert an element at the rear of the queue.
• Dequeue: Remove an element from the front of the queue.
Queues are commonly used in situations where data needs to be processed in the order it arrives, such
as in print spooling or task scheduling systems.
Front and Rear
• Front: The front of the queue refers to the position where elements are removed (dequeue
operation). It indicates the first element of the queue.
• Rear: The rear of the queue refers to the position where new elements are added (enqueue
operation). It indicates the last element added to the queue.
Real-time Examples of Queue:
1. Ticket counter line: People are served in the order they arrive, the first person in line is the first
to be served.
2. Call center management: The first customer to call is the first customer to get assistance.
3. CPU Scheduling: Processes are queued up in a ready queue and are executed based on their
arrival.
Applications of Queues:
1. Operating systems: Queues are used for managing tasks in job scheduling, printer spooling, and
interrupt handling.
2. Network applications: Queues manage the buffer in networking for packet processing.
3. Simulations: Queues are used to simulate real-world waiting lines, such as people at a counter,
cars at a toll booth, etc.
4. Breadth-First Search (BFS) algorithm: Queues are used in this graph traversal algorithm to track
nodes at the current level before moving to the next.
Advantages of Queues:
1. Order Preservation: Queues maintain the order of elements as they are added, making it ideal
for scenarios that require processing in arrival order.
2. Simple to implement: Easy to implement using arrays or linked lists.
3. Widely applicable: Useful in various domains such as operating systems, network traffic
management, and real-time simulations.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 64


BCS304 | DATA STRUCTURES AND APPLICATIONS

2.1 Types of Queues


Queues can have several variations depending on how data is handled. The main types of queues are:
1. Simple Queue (or Linear Queue):
o This is the most basic type of queue that follows the FIFO principle.
o Insertions happen at the rear, and deletions happen from the front.
o Disadvantage: Once an element is dequeued, that space cannot be reused, potentially
causing inefficiency.
2. Circular Queue:
o A more efficient version of the linear queue where the last position connects back to the
first position to form a circle.
o In a circular queue, both front and rear pointers wrap around when they reach the end
of the array. This allows reuse of empty spaces and prevents overflow in cases where
elements have been dequeued.
o Used in buffering processes like streaming data or round-robin scheduling.
3. Priority Queue:
o Unlike a normal queue where the order of arrival is maintained, elements in a priority
queue are dequeued based on their priority.
o Each element is assigned a priority, and the highest-priority element is served first,
regardless of when it was added.
o Priority queues are widely used in algorithms like Dijkstra's and A*.
4. Deque (Double-ended Queue):
o A deque (pronounced "deck") allows insertion and deletion from both the front and rear
ends.
o It supports both FIFO and LIFO (Last-In-First-Out) operations, making it more versatile
than a standard queue.
o Deques are used in scenarios like sliding window problems, undo operations in text
editors, and caching algorithms.

2.2 The Queue Abstract Data Type


Structure Queue is:

• Objects: A finite ordered list with zero or more elements.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 65


BCS304 | DATA STRUCTURES AND APPLICATIONS

• Functions: For all queue ∈ Queue, item ∈ element, max-queue-size ∈ positive integer.

Queue Abstract Data Type

Return Type Function Description


Creates an empty queue whose maximum size is max-
Queue CreateQueue(max-queue-size)
queue-size.
Returns TRUE if the number of elements in the queue is
Boolean IsFull(queue, max-queue-size)
equal to max-queue-size, otherwise FALSE.
Inserts item at the rear of the queue if it's not full, and
Queue AddQueue(queue, item)
returns the updated queue.
Boolean IsEmpty(queue) Returns TRUE if the queue is empty, otherwise FALSE.
Removes and returns the element at the front of the
Element DeleteQueue(queue)
queue if it's not empty.

2.3 Implementation of Queue


Below are the algorithms and functions for the queue operations: Insert, Delete, and Display using a
sequential (array-based) implementation. As requested, front, rear, and queue are declared globally,
and parameters are not passed to these functions.

2.3.1 Insert Algorithm (insertrear())


Algorithm:
1. Check if the queue is full:
o If rear == MAX - 1, print "Queue is full" and return.
2. Else, if the queue is not full:
o If the queue is empty (i.e., front == -1), set front = 0.
o Increment the rear by 1.
o Insert the new element at queue[rear].

insert():
#include <stdio.h>
#define MAX 5
int queue[MAX];
int front = -1, rear = -1;

void insertrear(int item) {


if (rear == MAX - 1) {
printf("Queue is full\n");

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 66


BCS304 | DATA STRUCTURES AND APPLICATIONS

return;
}
if (front == -1) { // First insertion
front = 0;
}
rear++;
queue[rear] = item;
printf("Inserted %d into the queue\n", item);
}

2.3.2 Delete Algorithm (deletefront())


1. Check if the queue is empty:
• If front == -1 or front > rear:
o Print "Queue is empty".
o Set front = -1 and rear = -1 (reset queue).
o Return from the function.
2.Delete the element from the front:
• Print the element queue[front] as it is being deleted.
• Increment the front pointer (front = front + 1).
3. End the function.

Delete() Function:
// Function to delete an element from the front of the queue
void deletefront() {
if (front == -1 || front > rear) {
printf("Queue is empty\n");
if (front > rear) { // Reset when the queue becomes empty
front = rear = -1;
return;
}
printf("Deleted %d from the queue\n", queue[front++]);
}
}

2.3.3 Display Queue Elements Algorithm (display())


Algorithm:
1. Check if the queue is empty:
o If front == -1, print "Queue is empty".
2. Else:
o Loop through the queue from front to rear and print each element.

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 67


BCS304 | DATA STRUCTURES AND APPLICATIONS

display:
void display() {
if (front == -1) {
printf("Queue is empty\n");
return;
}
printf("Queue elements are: ");
for (int i = front; i <= rear; i++) {
printf("%d ", queue[i]);
}
printf("\n");
}

2.3.4 Queue Implementation Using Switch Cases

#include <stdio.h>
#define MAX 5
int queue[MAX];
int front = -1, rear = -1;

// Function to insert an element at the rear of the queue


void insertrear(int item) {
if (rear == MAX - 1) {
printf("Queue is full\n");
return;
}
if (front == -1) { // First insertion
front = 0;
}
queue[++rear] = item;
printf("Inserted %d into the queue\n", item);
}

// Function to delete an element from the front of the queue


void deletefront() {
if (front == -1 || front > rear) {
printf("Queue is empty\n");
if (front > rear) { // Reset when the queue becomes empty
front = rear = -1;
return;
}
printf("Deleted %d from the queue\n", queue[front++]);

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 68


BCS304 | DATA STRUCTURES AND APPLICATIONS

}
}

// Function to display the elements in the queue


void display() {
if (front == -1) {
printf("Queue is empty\n");
return;
}
printf("Queue elements are: ");
for (int i = front; i <= rear; i++) {
printf("%d ", queue[i]);
}
printf("\n");
}

// Main function to implement the queue using switch cases


int main() {
int choice, item;

while (1) {
printf("\nQueue Operations: \n");
printf("1. Insert\n");
printf("2. Delete\n");
printf("3. Display\n");
printf("4. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);

switch (choice) {
case 1:
printf("Enter the element to insert: ");
scanf("%d", &item); // Prompt and read input directly under case 1
inserrear(item);
break;
case 2:
deletefront();
break;
case 3:
display();
break;
case 4:

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 69


BCS304 | DATA STRUCTURES AND APPLICATIONS

printf("Exiting...\n");
return 0;
default:
printf("Invalid choice! Please try again.\n");
}
}
return 0;
}

Sample Output:
Queue Operations:
1. Insert
2. Delete
3. Display
4. Exit
Enter your choice: 1
Enter the element to insert: 15
Inserted 15 into the queue

Queue Operations:
1. Insert
2. Delete
3. Display
4. Exit
Enter your choice: 3
Queue elements are: 15

Queue Operations:
1. Insert
2. Delete
3. Display
4. Exit
Enter your choice: 2
Deleted 15 from the queue

Queue Operations:
1. Insert
2. Delete
3. Display
4. Exit
Enter your choice: 4
Exiting...

Digital Notes Prepared by Dr. Nagaraj Bhat, SMVITM 70

You might also like