Dsamodule Notes
Dsamodule Notes
Prepared by
Ms.Yashaswini H R
Assistant Professor
Data Structures and its Applications(B24CS302
Applications(B24CS302)
Module 1:Introduction
Data Structures Definition
Data structures are frameworks for organizing, managing, and storing data efficiently in computer systems, with
applications in databases, operating systems, artificial intelligence, compiler design, web development, networking,
and computer graphics. They enable faster retrieval and manipulation of information, allowing for the optimization
of algorithms and improving overall system performance across various fields.
Introduction to Data Structures
What is a Data Structure?
A data structure is a way of organizing and storing data so that it can be used efficiently.
dataa for solving computational problems.
It provides a systematic way to access, modify, and manage dat
Why Data Structures?
Efficient data storage and retrieval
Better organization of large amounts of data
Helps in optimizing algorithms
Forms the backbone of software development and system design.
design
Types of Data Structures
Primitive data structures are the basic building blocks of data manipulation.
These include:
Page 1 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
Arrays
A two-dimensional
dimensional array is a collection of similar data elements where each element is referenced by two
elements
subscripts.
Linked lists
A linked list is a collection of data elements whose order is not given by their physical location in
memory. It consists of nodes that contain data and link to the next node. The structure
stru allows easiness in
insertion and deletion operations. The last nodes are linked to NULL and signify the end of the list.
Page 2 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
Stack
Stack, LIFO(Last In First Out) system, is a linear data structure in which insertion(PUSH) and
deletion(POP) are restricted
ed to one endpoint called TOP.
Queue
A queue is a FIFO(First In First Out) system, in which insertion(ENQUEUE) can take place only at an end
called REAR and deletion(DEQUEUE) can take place only at another end called FRONT.
Page 3 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
Trees
Some data contains a hierarchical relationship between various elements. These data are represented in
the form of a Rooted tree graph or simply Tree. Here node A is called the root of the tree.
Graphs
Sometimes
times data contain relationships that are not hierarchical in nature. This type of relationship can be
expressed in the form of a graph data structure.
Page 4 of 74
Data Structures and its Applications(B24CS302)
Page 6 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
5. Operations on Arrays
Traversal → Visiting all elements
#include <stdio.h>
int main( ) {
int arr[100]; // Declare an array with a maximum capacity
int size; // Current number of elements in the array
int element; // The element to be inserted
int position; // The position where the element will be inserted
int i;
printf("Enter %d elements:\n",
n", size);
for (i = 0; i < size; i++) {
scanf("%d", &arr[i]);
}
Page 7 of 74
Data Structures and its Applications(B24CS302)
printf("Enter the position (1 to %d) where the element should be inserted: ", size + 1);
scanf("%d", &position);
// Shift elements to the right to make space for the new element
for (i = size; i >= position - 1; i--) {
arr[i + 1] = arr[i];
}
Initialization: An array arr with a fixed maximum size (e.g., 100) is declared. Variables for the current size,
the element to insert, and the position for insertion are also declared.
Input: The program prompts the user to enter the initial number of elements and then the elements
themselves. It also asks for the element to be inserted and the position where it should be placed.
Position Validation: It checks if the entered position is valid (within the bounds of the array, including the
next available spot).
Shifting Elements: A for loop iterates from the current size down to the position - 1. In each
iteration, arr[i] is moved to arr[i + 1], effectively shifting elements to the right to create an empty spot at
the position - 1 index.
Size Update: The size of the array is incremented to reflect the newly added element.
Page 8 of 74
Data Structures and its Applications(B24CS302)
#include <stdio.h>
int main( ) {
int arr[100]; // Declare an array with a maximum size of 100
int size, position, i;
printf("\n");
}
return 0;
}
Explanation:
Include Header:
The stdio.h header is included for standard input/output functions like printf and scanf.
Declare Variables:
arr[100]: An integer array to store the elements. Its maximum size is set to 100.
size: Stores the actual number of elements in the array.
position: Stores the 1-indexed position of the element to be deleted.
i: Used as a loop counter.
Input Array Elements:
The program prompts the user to enter the size of the array and then the elements themselves.
Input Position to Delete:
The user is asked to enter the 1-indexed position of the element they wish to delete.
Position Validation:
It checks if the entered position is valid (within the bounds of the array). If not, an error message is displayed.
Deletion Logic (Shifting Elements):
If the position is valid, a for loop iterates from position - 1 (the actual 0-indexed index of the
element to delete) up to size - 1.
In each iteration, arr[i] is assigned the value of arr[i + 1]. This effectively shifts all elements to the
right of the deleted element one position to the left, overwriting the element at the
specified position.
Decrement Size:
After shifting, the size of the array is decremented because one element has been "removed."
Print Modified Array:
Finally, the program prints the array with the deleted element removed.
We can update the value of array elements at the given index i in a similar way to accessing an element
by using the array square brackets [ ] and assignment operator (=).
array_name[i]=new_value;
Example:
int main( ) {
intarr[5] = {2, 4, 8, 12, 16};
Page 10 of 74
Data Structures and its Applications(B24CS302)
Page 11 of 74
Data Structures and its Applications(B24CS302)
Binary Search
• Binary Search is used for searching an element in a sorted array.
Page 12 of 74
Data Structures and its Applications(B24CS302)
// Loop will run till left > right. It means that there
// are no elements to consider in the given subarray
while (left <= right) {
int main() {
int arr[] = {2, 5, 8, 12, 16, 23, 38, 56, 72, 91};
int size = sizeof(arr) / sizeof(arr[0]);
// Element to be searched
Page 13 of 74
Data Structures and its Applications(B24CS302)
Page 15 of 74
Data Structures and its Applications(B24CS302)
Output:
Before sorting array elements are:
15 16 11 13 14
After sorting array elements are:
11 13 14 15 16
Selection Sort Algorithm :
In selection sort, the smallest value among the unsorted elements of the array is selected in every pass and inserted
into its appropriate position into the array. It is also the simplest algorithm. It is an in-place comparison sorting
algorithm.
In this algorithm, the array is divided into two parts; the first is the sorted part, and the other is the unsorted part.
Initially, the sorted part of the array is empty, and the unsorted part is the given array. The sorted part is placed at
the left, while the unsorted part is placed at the right.
Selection sort is generally used when:
o A small array is to be sorted
o Swapping cost does not matter
o It is compulsory to check all elements
Algorithm
// Function to do selection sort on the array 'a' of size 'n'
function selectionSort(a, s)
// Outer loop: for iterating through the array
// The last element is not included
for j = 0 to s - 1
// Assuming that the current element is the minimum
// storing its index.
minIdx = j
// Inner loop: for finding the minimum element in the unsorted portion
for k = j + 1 to s - 1
// If a smaller element is found
if a[k] < a[minIdx]
// Updating the index of the element, which is the minimum
minIdx = k
// Swapping the minimum element found with the current element
if minIdx != j
swap(a[j], a[minIdx])
// The array is now sorted. return it
return a
Page 16 of 74
Data Structures and its Applications(B24CS302)
Page 17 of 74
Data Structures and its Applications(B24CS302)
Advantages
Access of elements (O(1))
Easy to implement and use
Disadvantages
Example:
int arr[5] = {10, 20, 30, 40, 50};
Diagram:
Index: 0 1 2 3 4
↓ ↓ ↓ ↓ ↓
Value: 10 20 30 40 50
Here:
Array name: arr
arr[0] = 10
arr[1] = 20
arr[4] = 50
Example :
int arr[5] = {10, 20, 30, 40, 50};
printf("%d", arr[2]); // Output: 30
1. Static Arrays
Static Arrays are fixed in size.
Size of static arrays should be determined at compile-time (before run-time).
No need to delete static arrays, they are deleted automatically after going out of scope.
Page 18 of 74
Data Structures and its Applications(B24CS302)
Dynamic Arrays
Dynamic Arrays are allocated on heap.
Size of dynamic arrays can be determined either at compilation or at run-time (flexible).
You can construct very large dynamic arrays on heap, unlike static arrays.
You need to manually delete dynamic arrays after you no longer need them.
// Program to take 5 values from the user and store them in an array
// Print the elements stored in the array
#include <stdio.h>
int main( ) {
int values[5];
printf("Enter 5 integers: ");
// taking input and storing it in an array
for(int i = 0; i < 5; ++i) {
scanf("%d", &values[i]);
}
#include <stdio.h>
int main( ) {
int arr[5] = {5, 10, 15, 20, 25};
int sum = 0;
int main( ) {
int data[5] = {45, 72, 29, 90, 61};
int max = data[0];
Arrays and Pointers are closely related to each other such that we can use pointers to perform all the
possible operations of the array. The array name is a constant pointer to the first element of the array and
the array decays to the pointers when passed to the function.
Example :
#include <stdio.h>
int main() {
In C, arrays are passed to functions using pointers, as the array name decays to a pointer to the first
element. So, we also need to pass the size of the array to the function.
Example:
#include <stdio.h>
// Functions that take array as argument
void printArray(int arr[ ], int n) {
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
}
int main() {
int arr[] = {2, 4, 8, 12, 16};
int n = sizeof(arr) / sizeof(arr[0]);
// Passing array
printArray(arr, n);
return 0;
}
Page 21 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
2. Two-Dimensional
Dimensional Array (2D Array)
Declaration:
The general syntax for declaring a two-dimensional
two array is:
data_type array_name[rows][columns];
data_type: Specifies the type of elements the array will store (e.g., int, float, char).
array_name: The name given to the array.
[rows]: Defines the number of rows in the array.
[columns]: Defines the number of columns in the array.
Example:
Page 22 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
Example 1 :
Sum of two matrices
// C program
am to find the sum of two matrices of order 2*2
#include <stdio.h>
int main( )
{
float a[2][2], b[2][2], result[2][2];
Page 23 of 74
Data Structures and its Applications(B24CS302)
{
printf("%.1f\t", result[i][j]);
if (j == 1)
printf("\n");
}
return 0;
}
Example 2 :
Demonstrating the use of Two Dimensional Array(Transpose of a matrix) :
#include <stdio.h>
int main( ) {
int rows, cols;
Page 24 of 74
Data Structures and its Applications(B24CS302)
return 0;
}
Jagged Array
A jagged array in C is an array of arrays where each inner array (or "row") can have a different length. This
contrasts with a traditional 2D array in C, which is always rectangular, meaning all rows have the same number of
columns.
Implementation in C:
Jagged arrays in C are typically implemented using pointers. You create an array of pointers, and each pointer in
that array points to a dynamically allocated 1D array representing a "row."
Example:
#include <stdio.h>
#include <stdlib.h>
int main( ) {
// Declare an array of pointers to integers (for 3 rows)
int **jaggedArray;
int numRows = 3;
return 0;
}
Explanation:
Page 25 of 74
Data Structures and its Applications(B24CS302)
**`int ** jaggedArray;`**: This declares jaggedArray as a pointer to a pointer to an integer. It will hold the
address of the first element of an array of int* (pointers to integers).
malloc(numRows * sizeof(int *));:
This allocates memory for an array of numRows number of int* pointers. Each of these pointers will eventually
point to a row of the jagged array.
malloc(rowLengths[i] * sizeof(int));:
Inside the loop, for each row i, this allocates memory for rowLengths[i] number of integers. This creates a 1D array
of the specified length for that particular row.
jaggedArray[i][j]:
This syntax allows you to access individual elements of the jagged array, similar to a regular 2D array, even though
the underlying memory structure is different.
Memory Management:
It is crucial to free the dynamically allocated memory for each row and then for the array of pointers to prevent
memory leaks.
Pointers in C
A pointer is a variable that stores the memory address of another variable. Instead of holding a direct
value, it holds the address where the value is stored in memory. It is the backbone of low-level memory
manipulation in C. Accessing the pointer directly will just give us the address that is stored in the pointer.
For example,
#include <stdio.h>
int main( ) {
// Normal Variable
int var = 10;
return 0;
}
Dangling Pointers in C
The most common bugs related to pointers and memory management is dangling/wild pointers.
Sometimes the programmer fails to initialize the pointer with a valid address, then this type of
initialized pointer is known as a dangling pointer in C.
Dangling pointer occurs at the time of the object destruction when the object is deleted or de-allocated
from memory without modifying the value of the pointer.
In this case, the pointer is pointing to the memory, which is de-allocated. The dangling pointer can point
to the memory, which contains either the program code or the code of the operating system.
If we assign the value to this pointer, then it overwrites the value of the program code or operating
system instructions; in such cases, the program will show the undesirable result or may even crash.
Page 26 of 74
Data Structures and its Applications(B24CS302)
If the memory is re-allocated to some other process, then we dereference the dangling pointer will
cause the segmentation faults.
In the above figure, we can observe that the Pointer 3 is a dangling pointer. Pointer 1 and Pointer 2 are
the pointers that point to the allocated objects, i.e., Object 1 and Object 2, respectively. Pointer 3 is a
dangling pointer as it points to the de-allocated object.
Let's understand the dangling pointer through some C programs.
Using free() function to de-allocate the memory.
1. #include <stdio.h>
2. int main( )
3. {
4. int *ptr=(int *)malloc(sizeof(int));
5. int a=560;
6. ptr=&a;
7. free(ptr);
8. return 0;
9. }
In the above code, we have created two variables, i.e., *ptr and a where 'ptr' is a pointer and 'a' is a
integer variable. The *ptr is a pointer variable which is created with the help of malloc() function. As we
know that malloc() function returns void, so we use int * to convert void pointer into int pointer.
The statement int *ptr=(int *)malloc(sizeof(int)); will allocate the memory with 4 bytes shown in the
below image:
The statement free(ptr) de-allocates the memory as shown in the below image with a cross sign, and 'ptr'
pointer becomes dangling as it is pointing to the de-allocated memory.
Page 27 of 74
Data Structures and its Applications(B24CS302)
If we assign the NULL value to the 'ptr', then 'ptr' will not point to the deleted memory. Therefore, we can
say that ptr is not a dangling pointer, as shown in the below image:
Page 28 of 74
Data Structures and its Applications(B24CS302)
printf("%d", *p);
return 0;
}
In the above code, we did the following steps:
o First, we create the main( ) function in which we have declared 'p' pointer that contains the return
value of the fun( ).
o When the fun( ) is called, then the control moves to the context of the int *fun(), the fun() returns
the address of the 'y' variable.
o When control comes back to the context of the main() function, it means the variable 'y' is no
longer available. Therefore, we can say that the 'p' pointer is a dangling pointer as it points to the
de-allocated memory.
Output
Page 29 of 74
Data Structures and its Applications(B24CS302)
Output
The above diagram shows the stack memory. First, the fun( ) function is called, then the control moves to
the context of the int *fun(). As 'y' is a static variable, so it stores in the global memory; Its scope is
available throughout the program. When the address value is returned, then the control comes back to
the context of the main(). The pointer 'p' contains the address of 'y', i.e., 100. When we print the value of
'*p', then it prints the value of 'y', i.e., 10. Therefore, we can say that the pointer 'p' is not a dangling
pointer as it contains the address of the variable which is stored in the global memory.
Avoiding Dangling Pointer Errors
The dangling pointer errors can be avoided by initializing the pointer to the NULL value. If we assign
the NULL value to the pointer, then the pointer will not point to the de-allocated memory.
Assigning NULL value to the pointer means that the pointer is not pointing to any memory location.
Example 3:
#include <stdio.h>
int main()
{
int abc[5][4] ={
{0,1,2,3},
{4,5,6,7},
{8,9,10,11},
{12,13,14,15},
{16,17,18,19}
};
for (int i=0; i<=4; i++)
{
printf("%d ",abc[i]);
Page 30 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
}
return 0;
}
3. Multi-Dimensional
Dimensional Array (3D or more)
Stores data in 3 or more dimensions.
dimensions
Accessed using multiple indices.
indices
Example: 3D array can be seen as a “stack of matrices.”
Three-dimensional array:
A 3-D Multidimensionalal array contains three dimensions, so it can be considered an array of two
two-
dimensional arrays.
Example:
int cube[2][2][2] =
{
{{1,2}, {3,4}},
{{5,6}, {7,8}}
};
Diagram (3D Array Concept):
Layer 0: Layer 1:
[1 2] [5 6]
[3 4] [7 8]
Array in C is static in nature, so its size should be known at compile time and we can't change the size of
the array after its declaration. Due to this, we may encounter situations where our array doesn't have
enough space left for required elements or we allotted more than the required memory leading to
memory wastage. To solve this problem, dynamic arrays come into the picture.
A Dynamic Array is allocated memory at runtime and its size can be changed later in the program.
We can create a dynamic array in C by using the following methods:
1. Using malloc() Function
2. Using calloc() Function
3. Resizing Array Using realloc() Function
4. Using Free( ) Function
5. Using Variable Length Arrays(VLAs)
6. Using Flexible
xible Array Member.
Page 31 of 74
Data Structures and its Applications(B24CS302)
The “malloc” or “memory allocation” method in C is used to dynamically allocate a single large block of
memory with the specified size. It returns a pointer of type void which can be cast into a pointer of any
form. It is defined inside <stdlib.h> header file.
Syntax:
ptr = (cast-type*) malloc(byte-size);
We can use this function to create a dynamic array of any type by simply allocating a memory block of
some size and then typecasting the returned void pointer to the pointer of the required type.
Example:
ptr = (int*) malloc(100 * sizeof(int));
In the above example, we have created a dynamic array of type int and size 100 elements.
Note: It is to be noted that if malloc fails to allocate the required memory, it returns the NULL pointer. So,
it is a good practice to check for NULL pointer to see if the memory is successfully allocated or not.
Example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
// Memory allocated
printf("Memory successfully allocated using "
"malloc.\n");
ptr[j] = j + 1;
}
return 0;
}
Output:
Enter size of elements:5
Memory successfully allocated using malloc.
The elements of the array are: 1, 2, 3, 4, 5,
The “calloc” or “contiguous allocation” method in C is used to dynamically allocate the specified number of
blocks of memory of the specified type and initialized each block with a default value of 0.
The process of creating a dynamic array using calloc() is similar to the malloc() method. The difference is
that calloc() takes arguments instead of one as compared to malloc(). Here, we provide the size of each
element and the number of elements required in the dynamic array. Also, each element in the array is
initialized to zero.
Syntax:
ptr = (cast-type*)calloc(n, element-size);
Example:
ptr = (int*) calloc(5, sizeof(float));
In the above example, we have created a dynamic array of type float having five elements.
Let's take another example to create a dynamic array using the calloc() method.
Example:
// C program to create dynamic array using calloc() function
#include <stdio.h>
#include <stdlib.h>
int main()
{
// address of the block created hold by this pointer
int* ptr;
int size;
Page 33 of 74
Data Structures and its Applications(B24CS302)
// Memory allocated
printf("Memory successfully allocated using "
"malloc.\n");
return 0;
}
Output:
Enter size of elements:6
Memory successfully allocated using malloc.
The elements of the array are: 1, 2, 3, 4, 5, 6,
3. Dynamically Resizing Array Using realloc() Function
The “realloc” or “re-allocation” method in C is used to dynamically change the memory allocation of a
previously allocated memory.
Using this function we can create a new array or change the size of an already existing array.
Syntax:
ptr = realloc(ptr, newSize);
Example :
// C program to resize dynamic array using realloc()function
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size = 5;
if (ptr == NULL) {
printf("Memory not allocated.\n");
exit(0);
}
else {
printf("Memory successfully allocated using "
"calloc.\n");
}
// inserting elements
for (int j = 0; j < size; ++j) {
ptr[j] = j + 1;
}
printf("\n");
size = 10;
int *temp = ptr;
// using realloc
ptr = realloc(ptr, size * sizeof(int));
if (!ptr) {
printf("Memory Re-allocation failed.");
ptr = temp;
}
else {
printf("Memory successfully re-allocated using "
"realloc.\n");
}
Output
Memory successfully allocated using calloc.
The elements of the array are: 1, 2, 3, 4, 5,
Memory successfully re-allocated using realloc.
The new elements of the array are: 1, 2, 3, 4, 5, 15, 16, 17, 18, 19,
4. Free( ) Function :
The free() function in C is used to deallocate dynamically allocated memory. It is a crucial part of memory
management in C, preventing memory leaks and ensuring efficient resource utilization.
Purpose:
To release memory previously allocated by functions like malloc(), calloc(), or realloc() back to the
system.
To prevent memory leaks, which occur when dynamically allocated memory is no longer needed but
remains occupied, consuming system resources.
Syntax:
void free(void *ptr);
ptr: A pointer to the block of memory that was previously allocated by malloc(), calloc(), or
realloc( ).
How it works:
When free() is called with a valid pointer to a dynamically allocated memory block, the memory is
returned to the heap, making it available for future allocations.
The free() function does not erase the data that was stored in the memory block; it simply marks the
memory as available for reuse.
If ptr is NULL, free() does nothing and simply returns.
Page 36 of 74
Data Structures and its Applications(B24CS302)
int main( ) {
struct myStructure s1;
return 0;
}
// Print values
printf("My number: %d\n", s1.myNum);
printf("My letter: %c\n", s1.myLetter);
return 0;
}
Now, instead of writing struct Student_struct_name student1;, you can simply write Student student1; to declare a
variable of this structure type.
struct Person_struct {
char name[50];
int age;
};
typedef struct Person_struct Person; // Person is now an alias for struct Person_struct
Now, you can declare variables using either struct Person_struct p1; or Person p1;.
Self-referential Structures:-
A self-referential structure is a struct data type in C, where one or more of its elements are pointer to variables of
its own type. Self-referential user-defined types are of immense use in C programming. They are extensively used
to build complex and dynamic data structures such as linked lists and trees.
In C programming, an array is allocated the required memory at compile-time and the array size cannot be
modified during the runtime. Self-referential structures let you emulate the arrays by handling the size
dynamically.
File management systems in Operating Systems are built upon dynamically constructed tree structures, which are
manipulated by self-referential structures. Self-referential structures are also employed in many complex
algorithms.
Defining a Self-referential Structure
A general syntax of defining a self-referential structure is as follows −
strut typename{
type var1;
type var2;
...
...
struct typename *var3;
}
Page 38 of 74
Data Structures and its Applications(B24CS302)
Let us understand how a self-referential structure is used, with the help of the following example. We define a struct
type called mystruct. It has an integer element "a" and "b" is the pointer to mystruct type itself.
We declare three variables of mystruct type −
struct mystruct x = {10, NULL}, y = {20, NULL}, z = {30, NULL};
Next, we declare three "mystruct" pointers and assign the references x, y and z to them.
struct mystruct * p1, *p2, *p3;
p1 = &x;
p2 = &y;
p3 = &z;
The variables "x", "y" and "z" are unrelated as they will be located at random locations, unlike the array where all its
elements are in adjacent locations.
We use the malloc() function to dynamically allocate memory whose address is stored in pointer
variables. We then establish links between the three nodes as shown below −
#include <stdio.h>
#include <stdlib.h>
struct mystruct
{
int a;
struct mystruct *b;
};
int main()
Page 39 of 74
Data Structures and its Applications(B24CS302)
p1 -> b = p2;
p2 -> b = p3;
return 0;
}
Output
Run the code and check its output −
Add of x: 10032160 a: 10 add of next: 10032192
add of y: 10032192 a: 20 add of next: 10032224
add of z: 10032224 a: 30 add of next: 0
#include <stdio.h>
struct rectangle
{
float len, brd;
};
Page 40 of 74
Data Structures and its Applications(B24CS302)
struct rectangle r;
r.len = 10.50; r.brd = 20.5;
area(r.len, r.brd);
return 0;
}
return 0;
}
Output
When you run this code, it will produce the following output −
Length: 10.500000
Breadth: 20.500000
Area: 215.250000
Let us modify the above example to pass the struct variable itself (instead of its elements) to the area() function.
The rectangle struct type also has an additional element called "area".
Example
Inside the function, the elements of the struct variable are accessed though the dot operator (.) and the area is
calculated.
Open Compiler
#include <stdio.h>
struct rectangle{
float len, brd;
double area;
};
int main(){
struct rectangle r;
r.len = 10.50; r.brd = 20.5;
area(r);
return 0;
}
r.area = (double)(r.len*r.brd);
printf("Length: %f \nBreadth: %f \nArea: %lf\n", r.len, r.brd, r.area);
return 0;
}
Output
Run the code and check its output −
Length: 10.500000
Breadth: 20.500000
Area: 215.250000
struct rectangle {
float len, brd;
double area;
};
struct rectangle r;
float x, y;
x = 10.5; y = 20.5;
r = area(x, y);
return 0;
}
struct rectangle area(float x, float y){
Area: 215.250000
In C language, a function may be defined to have its arguments passed by value or reference. A reference is
the pointer to an existing variable.
Example
In this example, a struct variable of "rectangle" type is declared in main() and its address is passed to a user-
defined function called area().
When the area() function is called, it can use the elements of the variable with the indirection operator (). It
computes the result and assigns it to the area element "r area".
#include <stdio.h>
struct rectangle{
float len, brd;
double area;
};
int main(){
struct rectangle r;
r.len = 10.50; r.brd = 20.5;
area(&r);
return 0;
}
return 0;
}
Output
Run the code and check its output −
Length: 10.500000
Breadth: 20.500000
Area: 215.250000
Let us rewrite the above code to define the area() function and return a pointer to a struct of rectangle data type.
Example
Page 43 of 74
Data Structures and its Applications(B24CS302)
The area() function has two call-by-value arguments. The main() function reads the length and breadth from the
user and passes them to the area() function, which populates a struct variable and passes its reference back to the
main() function.
#include <stdio.h>
struct rectangle {
float len, brd;
double area;
};
x = 10.5; y = 20.5;
r = area(x, y);
printf("Length: %f \n Breadth: %f \n Area: %lf\n", r->len, r->brd, r->area);
return 0;
}
return &r;
}
Output
When you run this code, it will produce the following output −
Length: 10.500000
Breadth: 20.500000
Area: 215.250000
Unions in C
A union is a special data type available in C that allows to store different data types in the same memory location.
You can define a union with many members, but only one member can contain a value at any given time. Unions
provide an efficient way of using the same memory location for multiple purpose.
All the members of a union share the same memory location. Therefore, if we need to use the same memory
location for two or more members, then union is the best data type for that. The largest union member defines the
size of the union.
Defining a Union
Page 44 of 74
Data Structures and its Applications(B24CS302)
Union variables are created in same manner as structure variables. The keyword union is used to define unions in
C language.
Syntax
The "union tag" is optional and each member definition is a normal variable definition, such as "int i;" or "float f;"
or any other valid variable definition.
At the end of the union's definition, before the final semicolon, you can specify one or more union variables.
To access any member of a union, we use the member access operator (.). The member access operator is coded as
a period between the union variable name and the union member that we wish to access. You would use the
keyword union to define variables of union type.
Syntax
Here is the syntax to access the members of a union in C language −
union_name.member_name;
Syntax
Example
The following code statement shows to initialization of the member "i" of union "data" −
data.i = 10;
Examples of Union
Example 1
The following example shows how to use unions in a program −
Open Compiler
#include <stdio.h>
#include <string.h>
union Data{
int i;
float f;
char str[20];
};
Page 45 of 74
Data Structures and its Applications(B24CS302)
int main(){
union Data data;
data.i = 10;
data.f = 220.5;
strcpy(data.str, "C Programming");
Here, we can see that the values of i and f (members of the union) show garbage values because the final value
assigned to the variable has occupied the memory location and this is the reason that the value of str member is
getting printed very well.
Example 2:
#include <stdio.h>
#include <string.h>
union Data{
int i;
float f;
char str[20];
};
int main(){
union Data data;
data.i = 10;
printf("data.i: %d \n", data.i);
data.f = 220.5;
printf("data.f: %f \n", data.f);
strcpy(data.str, "C Programming");
printf("data.str: %s \n", data.str);
return 0;
}
Output
When the above code is compiled and executed, it produces the following result −
data.i: 10
data.f: 220.500000
data.str: C Programming
Here, the values of all the Union members are getting printed very well because one member is being used at a
time.
Size of a Union
Page 46 of 74
Data Structures and its Applications(B24CS302)
The size of a union is the size of its largest member. For example, if a union contains two members
of char and int types. In that case, the size of the union will be the size of int because int is the largest member.
You can use the sizeof( ) operator to get the size of a union.
Example
// Define a union
union Data {
int a;
float b;
char c[20];
};
int main() {
union Data data;
// Printing the size of the each member of union
printf("Size of a: %lu bytes\n", sizeof(data.a));
printf("Size of b: %lu bytes\n", sizeof(data.b));
printf("Size of c: %lu bytes\n", sizeof(data.c));
// Printing the size of the union
printf("Size of union: %lu bytes\n", sizeof(data));
return 0;
}
Output
When you compile and execute the code, it will produce the following output −
Size of a: 4 bytes
Size of b: 4 bytes
Size of c: 20 bytes
Size of union: 20 bytes
A structure is a user-defined data type A union is a user-defined data type that allows
that groups different data types into a storing different data types at the same
Definition single entity. memory location.
The size is the sum of the sizes of all The size is equal to the size of the largest
Size members, with padding if necessary. member, with possible padding.
Page 47 of 74
Data Structures and its Applications(B24CS302)
Data No data overlap as members are Full data overlap as members shares the same
Overlap independent. memory.
Both structures and unions are composite data types in C programming. The most significant difference between a
structure and a union is the way they store their data. A structure stores each member in separate memory
locations, whereas a union stores all its members in the same memory location.
Here is a definition of union type called myunion −
union myunion{
int a;
double b;
char c;
};
The definition of a union is similar to the definition of a structure. A definition of "struct type mystruct" with the
same elements looks like this −
struct mystruct{
int a;
double b;
char c;
};
The main difference between a struct and a union is the size of the variables. The compiler allocates the memory to
a struct variable, to be able to store the values for all the elements. In mystruct, there are three elements − an int, a
double, and char, requiring 13 bytes (4 + 8 + 1). Hence, sizeof(struct mystruct) returns 13.
For a union type variable, the compiler allocates a chunk of memory of the size enough to accommodate the
element of the largest byte size.
The myunion type has an int, a double and a char element. Out of the three elements, the size of the double variable
is the largest, i.e., 8. Hence, sizeof(union myunion) returns 8.
What is a Polynomial?
Page 48 of 74
Data Structures and its Applications(B24CS302)
A polynomial 'p(x)' is an expression in variable 'x' taking the form '(axn + bxn-1 + …. + jx+ k)', where 'a, b,
c ….', k are real numbers, and 'n' is a non-negative integer known as the degree of the polynomial. Each
term in a polynomial comprises a coefficient and an exponent.
Example: In the polynomial '10x2 + 26x', 10 and 26 are coefficients, and 2 and 1 are their respective
exponents.
#include <stdio.h>
#include <stdlib.h>
Page 49 of 74
Data Structures and its Applications(B24CS302)
if (coeff != 0) {
addTerm(&result, coeff, exp);
}
}
return result;
}
// Function to display a polynomial
voiddisplayPolynomial(struct Term* poly) {
while (poly != NULL) {
printf("%dx^%d", poly->coeff, poly->exp);
if (poly->next != NULL) {
printf(" + ");
}
poly = poly->next;
}
printf("\n");
}
// Main function
int main() {
struct Term* poly1 = NULL;
struct Term* poly2 = NULL;
Page 50 of 74
Data Structures and its Applications(B24CS302)
A sparse matrix in which most of its elements are zero. It is characterized by a small number of non-zero
elements compared to the total number of elements (mxn). In other words, a sparse matrix has a
significant proportion of zero values, often exceeding half of the total elements.
Given m and n, a sparse matrix of size mxn can be defined as follows:
m: The number of rows
n: The number of columns
For example, consider the following 4x4 matrix:
0001
0000
2000
0003
Sparse matrices are extremely useful because they allow efficient storage and computational
performance. Instead of storing all elements, including the zeros, sparse matrix representations store
only the non-zero elements, which reduces memory consumption and speeds up computations. This is
vital in applications such as machine learning, where large datasets often contain numerous zero-values
such as text data. By utilizing sparse matrices, we can work with these datasets without loading large
amounts of redundant data.
Storing and processing these datasets using sparse matrix representations helps reduce computational
cost and memory usage, making it possible to train models more efficiently.
Example: Note that other entries of matrices will be zero as matrices are sparse.
Input :
Matrix 1: (4x4)
Row Column Value
Page 51 of 74
Data Structures and its Applications(B24CS302)
1 2 10
1 4 12
3 3 5
4 1 15
4 2 12
Matrix 2: (4X4)
Row Column Value
1 3 8
2 4 23
3 3 9
4 1 20
4 2 25
Output :
Result of Addition: (4x4)
Row Column Value
1 2 10
1 3 8
1 4 12
2 4 23
3 3 14
4 1 35
4 2 37
Result of Multiplication: (4x4)
Row Column Value
1 1 240
1 2 300
1 4 230
3 3 45
4 3 120
4 4 276
Result of transpose on the first matrix: (4x4)
Page 52 of 74
Data Structures and its Applications(B24CS302)
1 4 15
2 1 10
2 4 12
3 3 5
4 1 12
The sparse matrix used anywhere in the program is sorted according to its row values. Two elements
with the same row values are further sorted according to their column values.
Now to Add the matrices, we simply traverse through both matrices element by element and insert the
smaller element (one with smaller row and col value) into the resultant matrix. If we come across an
element with the same row and column value, we simply add their values and insert the added data into
the resultant matrix.
To Transpose a matrix, we can simply change every column value to the row value and vice-versa,
however, in this case, the resultant matrix won't be sorted as we require. Hence, we initially determine
the number of elements less than the current element's column being inserted in order to get the exact
index of the resultant matrix where the current element should be placed. This is done by maintaining an
array index[] whose ith value indicates the number of elements in the matrix less than the column i.
To Multiply the matrices, we first calculate transpose of the second matrix to simplify our comparisons
and maintain the sorted order. So, the resultant matrix is obtained by traversing through the entire
length of both matrices and summing the appropriate multiplied values.
Any row value equal to x in the first matrix and row value equal to y in the second matrix (transposed
one) will contribute towards result[x][y]. This is obtained by multiplying all such elements having col
value in both matrices and adding only those with the row as x in first matrix and row as y in the second
transposed matrix to get the result[x][y].
For example: Consider 2 matrices:
Row Col Val Row Col Val
1 2 10 1 1 2
1 3 12 1 2 5
2 1 1 2 2 1
2 3 2 3 1 8
Page 53 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
Page 54 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
Page 55 of 74
Data Structures and its Applications(B24CS302)
int size = 0;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 5; j++)
if (sparseMatrix[i][j] != 0)
size++;
int compactMatrix[3][size];
Page 56 of 74
Data Structures and its Applications(B24CS302)
printf("\n");
}
return 0;
}
Output
001133
242312
345726
Strings in C
A string is an array of characters terminated by a special character '\0' (null character). This null
character marks the end of the string and is essential for proper string manipulation.
Unlike many modern languages, C does not have a built-in string data type. Instead, strings are
implemented as arrays of char.
Page 57 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
Example :
#include <stdio.h>
int /void main( ) {
// declaring and initializing a string
charstr[ ] = "Geeks";
Output
The string is: Geeks
charstr[ ] = "Geeks";
nd initializes it with the string "Hello World!". Internally,
This line declares a character array str and
this creates an array like:
{ 'G', 'e', 'e', 'k', 's', '\0'}
The null character '\0' is automatically added at the end to terminate the string.
printf("The string is: %s\n",
n", str);
%s is the format specifier used to print a string. printf starts at the memory location of str and
prints each character until it finds the terminating null character '\0'.
Declaration
one dimensional array of character type. Below is the
Declaring a string is as simple as declaring a one-dimensional
syntax for declaring a string.
char string_name[size];
In the above syntax string_name is any name given to the string variable and size is used to define the
length of the string, i.e. the number of characters strings will store.
char array_name[ ];
Page 58 of 74
Data Structures and its Applications(B24CS302)
Initialization
We can initialize a string either by specifying the list of characters or string literal.
// Using character list
charstr[] = {'G', 'e', 'e', 'k', 's', '\0'};
// Using string literal
charstr[] = "Geeks";
Note: When a Sequence of characters enclosed in the double quotation marks is encountered by the
compiler, a null character '\0' is appended at the end of the string by default.
Accessing
We can access any character of the string by providing the position of the character, like in array. We pass
the index inside square brackets [] with the name of the string.
Example:
#include <stdio.h>
int main( )
{
charstr[ ] = "Geeks";
// Access first character of string
printf("%c", str[0]);
return 0;
}
Update
Updating a character in a string is also possible. We can update any character of a string by using the
index of that character.
Example :
#include <stdio.h>
int main( ) {
charstr[] = "Geeks";
// Update the first character of string
str[0] = 'R';
printf("%c", str[0]);
return 0;
}
String Length
To find the length of a string in C, you need to iterate through each character until you reach the null
terminator '\0', which marks the end of the string. This process is handled efficiently by the
strlen( ) function from the C standard library.
Example
#include <stdio.h>
int main() {
charstr[ ] = "Geeks";
Page 59 of 74
Data Structures and its Applications(B24CS302)
printf("%d", strlen(str));
return 0;
}
Output
5
In this example, strlen() returns the length of the string "Geeks", which is 5, excluding the null character.
C language also provides several other useful string library functions to perform operations like copying,
comparing, and concatenating strings. You can refer to standard string functions for more details.
String Input
In C, reading a string from the user can be done using different functions, and depending on the use case,
one method might be chosen over another. Below, the common methods of reading strings in C will be
discussed, including how to handle whitespace, and concepts will be clarified to better understand how
string input works.
Using scanf()
The simplest way to read a string in C is by using the scanf( ) function.
Example :
#include<stdio.h>
int main() {
charstr[5];
// Read string
// from the user
scanf("%s",str);
Example
#include <stdio.h>
int main() {
charstr[20];
// Reading the string (with spaces) using fgets
fgets(str, 20, stdin);
// Displaying the string using puts
printf("%s", str);
return 0;
}
Page 60 of 74
Data Structures and its Applications(B24CS302
Applications(B24CS302)
Output
Geeks For Geeks (Enter by user)
Geeks For Geeks
Passing Strings to Function
As strings
rings are character arrays, we can pass strings to functions in the same way we pass an array to a
function.. Below is a sample program to do this:
#include <stdio.h>
voidprintStr(char str[]) {
printf("%s", str);
}
int main() {
charstr[] = "GeeksforGeeks";
// Passing string to a function
printStr(str);
return 0;
}
Similar to arrays, In C, we can create a character pointer to a string that points to the starting address of
string. The string can be accessed with the help of pointers
the string which is the first character of the string. pointers.
Example :
#include <stdio.h>
int main(){
charstr[20] = "Geeks";
// Pointer variable which store the starting address ofthe character array str
char* ptr = str;
// While loop will run till the
he character value is notequal to null character
while (*ptr != '\0') {
printf("%c", *ptr);
ptr++;
}
return 0;
}
Strings Literals
Page 61 of 74
Data Structures and its Applications(B24CS302)
A string literal is a sequence of characters enclosed in double quotes, like "Hello" or "1234". Internally, it
is stored as a constant character array terminated by a null character '\0'.
#include <stdio.h>
int main( )
{
// pointer to a string literal
const char *str = "Hello World";
printf("%s\n", str);
return 0;
}
Output
Hello World
C strings are arrays of characters terminated by a null character (\0). They are widely used in C
programming for text manipulation. Below is an overview of common operations and pattern-
matching techniques in C strings:
String Basics in C
In C programming, strings are fundamental data structures used to store and manipulate text. Unlike
some high-level languages, C does not have a built-in string type. Instead, strings are represented as
arrays of characters terminated by a null character (\0).
String Declaration and Initialization
There are multiple ways to declare and initialize strings in C:
// Method 1: Character array declaration
char str1[10] = "Hello";
Page 62 of 74
Data Structures and its Applications(B24CS302)
The null terminator is crucial in C strings. It indicates the end of the string and is used by string
manipulation functions.
String Memory
Hello'\0'
Common String Operations
Operation Function Description
#include <stdio.h>
#include <string.h>
int main() {
charstr[] = "Hello, World!";
printf("Length: %lu\n", strlen(str));
return 0;
}
2. String Copy (strcpy):
o Copies one string into another.
#include <stdio.h>
#include <string.h>
int main() {
charsrc[] = "Copy me!";
chardest[20];
strcpy(dest, src);
printf("Copied String: %s\n", dest);
return 0;
}
3. String Concatenation (strcat):
o Appends one string to another.
#include <stdio.h>
#include <string.h>
int main() {
char str1[20] = "Hello, ";
char str2[] = "World!";
Page 63 of 74
Data Structures and its Applications(B24CS302)
strcat(str1, str2);
printf("Concatenated String: %s\n", str1);
return 0;
}
4. String Comparison (strcmp):
o Compares two strings lexicographically.
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "apple";
char str2[] = "banana";
int result = strcmp(str1, str2);
printf("Comparison Result: %d\n", result); // Negative if str1 < str2
return 0;
}
5. Finding a Substring (strstr):
o Locates the first occurrence of a substring in a string.
#include <stdio.h>
#include <string.h>
int main() {
charstr[] = "Find the needle in the haystack.";
char *substr = strstr(str, "needle");
if (substr) {
printf("Substring found: %s\n", substr);
} else {
printf("Substring not found.\n");
}
return 0;
}
Pattern Matching in C Strings
Page 64 of 74
Data Structures and its Applications(B24CS302)
Remember, brute force is the simplest way to solve string matching or searching, but it is also the
slowest and most inefficient. The time complexity of this algorithm is O(nm), where 'n' is the length of
the text and 'm' is the length of the pattern. This means that in the worst case, we have to compare
every character of the text with every character of the pattern, which can be very slow if n and m are
large.
Example
In this example, we will practically demonstrates the brute force approach to solve a pattern matching
problem in various programming languages.
#include <stdio.h>
#include <string.h>
// method to find match
Page 65 of 74
Data Structures and its Applications(B24CS302)
Pattern matching involves searching for a specific sequence of characters (pattern) within a larger
string. Below are some common techniques:
#include <stdio.h>
#include <string.h>
voidnaivePatternMatch(char *text, char *pattern) {
int n = strlen(text);
int m = strlen(pattern);
for (inti = 0; i<= n - m; i++) {
int j;
for (j = 0; j < m; j++) {
if (text[i + j] != pattern[j]) {
break;
}
}
if (j == m) {
printf("Pattern found at index %d\n", i);
}
}
Page 66 of 74
Data Structures and its Applications(B24CS302)
}
int main( ) {
char text[] = "ababcabcabababd";
char pattern[] = "ababd";
naivePatternMatch(text, pattern);
return 0;
}
2. Boyer-Moore Algorithm:
Efficient algorithm that skips unnecessary comparisons by using precomputed tables.
Implementation is more complex but faster for large texts.
Example
In the following example, we are going to illustrate the working of Boyer-Moore Algorithm in various
programming languages.
#include<stdio.h>
#include<string.h> // Function for full suffix match
voidcomputeFullShift(intshiftArr[], intlongSuffArr[], char patrn[], int n)
{
inti = n;
int j = n+1;
longSuffArr[i] = j;
while(i> 0)
{
// Searching right if (i-1)th and (j-1)th item are not the same
while(j <= n &&patrn[i-1] != patrn[j-1] )
{
// to shift pattern from i to j
if(shiftArr[j] == 0) { shiftArr[j] = j-i;
}
// Updating long suffix value
j = longSuffArr[j];
}
i--;
j--;
longSuffArr[i] = j;
}
}
// Function for good suffix match
voidcomputeGoodSuffix(intshiftArr[], intlongSuffArr[], char patrn[], int n)
{
int j;
j = longSuffArr[0];
{
// Updating long suffix value
j = longSuffArr[j];
}
}
}
}
// Function for searching the pattern
voidsearchPattern(char orgnStr[], char patrn[], int array[], int *index)
{
{
int j = patLen - 1;
// decrement j when pattern and main string character is matching
while(j >= 0 &&patrn[j] == orgnStr[shift+j])
{
j--;
}
if(j < 0)
{
(*index)++;
// to store the position where pattern is found
array[(*index)] = shift; shift += shiftArr[0];
}
else
{
shift += shiftArr[j+1];
}
}
}
int main( )
{
// original string
Page 68 of 74
Data Structures and its Applications(B24CS302)
charorgnStr[] = "AABAAABCEDBABCDDEBC";
// Pattern to be searched
charpatrn[] = "ABC";
// Array to store the positions where pattern is found
intlocArray[strlen(orgnStr)];
int index = -1;
// Calling the searchPattern function
searchPattern(orgnStr, patrn, locArray, &index);
// Printing the positions where pattern is found
for(inti = 0; i<= index; i++)
{
printf("Pattern found at position: %d\n", locArray[i]);
}
return 0;
}
while (i< m) {
if (pattern[i] == pattern[len]) {
len++;
lps[i] = len;
i++;
} else {
if (len != 0)
len = lps[len - 1];
else {
lps[i] = 0;
i++;
}
}
}
}
inti = 0, j = 0;
while (i< n) {
if (pattern[j] == text[i]) {
Page 69 of 74
Data Structures and its Applications(B24CS302)
i++;
j++;
}
if (j == m)
returni - j;
int main()
{
char source[] = "Hello, World!";
char destination[50];
strcpy(destination, source);
printf("Source: %s\n", source);
printf("Destination: %s\n", destination);
return 0;
}
int main( ) {
char source[100], destination[100];
printf("Enter a string: ");
fgets(source, sizeof(source), stdin);
copyString(source, destination);
printf("Copied string: %s", destination);
Page 70 of 74
Data Structures and its Applications(B24CS302)
return 0;
}
Example 2 :
//Compare 2 strings without strcmp( )
/* without using strcmp() */
#include <stdio.h>
#include <string.h>
int main()
{
char Str1[100], Str2[100];
int result, i;
printf("\n Please Enter the First String : ");
gets(Str1);
printf("\n Please Enter the Second String : ");
gets(Str2);
for(i = 0; Str1[i] == Str2[i] && Str1[i] == '\0'; i++);
if(Str1[i] < Str2[i])
{
printf("\n str1 is Less than str2");
}
else if(Str1[i] > Str2[i])
{
printf("\n str2 is Less than str1");
}
else
{
printf("\n str1 is Equal to str2");
}
return 0;
}
Example 3:
//program to reverse a string
#include <stdio.h>
#include <string.h>
int main() {
charstr[100], temp;
inti, j;
j = strlen(str) - 1;
#include <stdio.h>
intmain()
{
// Define the size of the arrays
int size = 5;
return 0;
}
Page 72 of 74
Data Structures and its Applications(B24CS302)
Page 73 of 74