1DSA
1DSA
UNIT - 1: INTRODUCTION
by - Hari Krishna
Page 2
Data Structures:
Classifications:
Non
by - Hari Krishna
Page 3
Integer(2 bytes) - The integer data type contains the numeric values. It
contains the whole numbers that can be either negative or positive.
Ex: 10, 97, -41
Float(4 bytes) - The float is a data type that can hold decimal values upto
6 digits.
Ex: 3.127461
Character(1 byte) - It is a data type that can hold a single character value
both uppercase and lowercase such as 'A' or 'a'.
Boolean(1 byte) - It is a data type that can hold either a True or a False
value.
Ex: 1 or 0 (True or False).
Non-primitive data structures are complex data structures that are derived
from primitive data structures. It can hold multiple values either in a contiguous
location or random locations.
The non-primitive data types are defined by the programmer. The non-primitive
data structure is further classified into two categories.
by - Hari Krishna
Page 4
Linked List: A linked list is a linear data structures that is used to maintain
a list-like structure in the computer memory. It is a group of nodes that are
not stored at contiguous locations. Each node of the list is linked to its
adjacent node with the help of pointers.
by - Hari Krishna
Page 5
Stack
Queue
by - Hari Krishna
Page 6
Non-linear Data Structures do not have any set sequence of connecting all
its elements and every element can have multiple paths to attach to other
elements.
Trees
Graph
by - Hari Krishna
Page 7
The common operations that can be performed on the data structures are as
follows
by - Hari Krishna
Page 8
Arrays:
When we declare an array, we are just allocating space for its elements; no
values are stored in the array. There are three ways to store values in an array.
by - Hari Krishna
Page 9
scanf(“%d”, &marks[i]);
by - Hari Krishna
Page 10
3 types of arrays
One-dimensional array
Two-dimensional array
Multi-dimensional array
A single dimension array holds various elements of the same data type.
To identify and find the value of a particular component, we use the array
name and the value of an index element.
Array in C, is always used with only one subscript ([]).
Declaration of an array:
by - Hari Krishna
Page 11
Program:
#include <stdio.h>
int main()
{
int numbers[5];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
numbers[3] = 40;
numbers[4] = 50;
for(int i=0; i<5; i++)
{
printf("numbers[%d] = %d\n", i, numbers[i]);
}
return 0;
}
Output:
numbers[0] = 10
numbers[1] = 20
numbers[2] = 30
numbers[3] = 40
numbers[4] = 50
by - Hari Krishna
Page 12
Two-Dimensional Array in C:
Syntax:
data_type array_name[rows][columns];
Example:
int twodimen[4][3];
int arr[4][3]={{1,2,3},{2,3,4},{3,4,5},{4,5,6}};
by - Hari Krishna
Page 13
Program:
#include<stdio.h>
int main()
{
int i=0,j=0;
int arr[4][3]={{1,2,3},{2,3,4},{3,4,5},{4,5,6}};
//traversing 2D array
for(i=0;i<4;i++)
{
for(j=0;j<3;j++)
{
printf("arr[%d] [%d] = %d \n",i,j,arr[i][j]);
}//end of j
}//end of i
return 0;
}
Output:
arr [0][0] = 1
arr [0][1] = 2
arr [0][2] = 3
arr [1][0] = 2
arr [1][1] = 3
arr [1][2] = 4
arr [2][0] = 3
arr [2][1] = 4
arr [2][2] = 5
arr [3][0] = 4
arr [3][1] = 5
arr [3][2] = 6
by - Hari Krishna
Page 14
Multi-dimensional array:
int arr[3][4] = {
{0, 1, 2, 3} , /* initializers for row indexed by 0 */
{4, 5, 6, 7} , /* initializers for row indexed by 1 */
{8, 9, 10, 11} /* initializers for row indexed by 2 */
};
Program:
#include <stdio.h>
void arr(int x[][3]); //function prototype
int main ()
{
int a[2][3] = {{1,2,3}, {4,5,6}}; //initializing array
int b[2][3] = {1, 2, 3, 4, 5};
int c[2][3] = {{1, 2}, {4}};
printf("values in array a by row:\n");
arr(a);
by - Hari Krishna
Page 15
Output:
values in array a by row:
1 2 3
4 5 6
values in array b by row:
1 2 3
4 5 0
values in array c by row:
1 2 0
4 0 0
by - Hari Krishna
Page 16
Operations on arrays:
by - Hari Krishna
Page 17
Structures:
Structure is a user defined data type that can store related information
(even of different data types) together.
Structure Declaration:
char name[20];
float fees;
};
by - Hari Krishna
Page 18
Initialization of structures:
Syntax:
struct struct_name
data_type member_name1;
data_type member_name2;
data_type member_name3;
.......................
Example:
struct student
int r_no;
char name[20];
char course[20];
float fees;
by - Hari Krishna
Page 19
Program:
#include <stdio.h>
#include <string.h>
struct Person // create struct with person1 variable
{
char name[50];
int Id;
float salary;
} person1;
int main()
{
strcpy(person1.name, "Bavvy");
person1.Id = 1234; // assign values to other person1 variables
person1. salary = 50000;
printf("Name: %s\n", person1.name); // print struct variables
printf("Emp Id No.: %d\n", person1. Id);
printf("Salary: %.2f", person1.salary);
return 0;
}
Output:
Name: Bavvy
Emp Id No.: 1234
Salary: 50000.00
by - Hari Krishna
Page 20
Self-Referential Structures:
int val;
};
Here, the structure node will contain two types of data: an integer val and
a pointer next. You must be wondering why we need such a structure. Actually,
self-referential structure is the foundation of other data structures.
Program:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
by - Hari Krishna
Page 21
};
void display (struct Node* temp)
{
while (temp)
{
printf(" %d ", temp->data);
temp= temp->next;
}
}
void main()
{
struct Node* head =NULL; // assign each node a null value to avoid any
refrence error
Output:
100 200 300
by - Hari Krishna
Page 22
Program:
#include<stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *left;
struct node *right;
};
struct node* createNode(int data)
{
struct node *newNode= (struct node *)malloc(sizeof(struct node));
newNode->data= data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
void inorder(struct node *temp)
{
if(temp) // traverse untill root is NULL
{
inorder(temp->left);
printf("%d ", temp->data);
inorder(temp->right);
}
else
return;
}
by - Hari Krishna
Page 23
void main()
{
struct node *root= createNode (10); // create root node
root->left= createNode(100); //making links to child nodes
root->right= createNode(200);
root->left->left= createNode(300); // making further connections
root->left->right= createNode(400);
root->right->left= createNode(500);
root->right->right= createNode(600);
printf("In Order Traversal of Binary Tree \n");
inorder(root); // calling inorder traversal function
}
Output:
In Order Traversal of Binary Tree
300 100 400 10 500 200 600
Unions:
Union is a collection of variables of different data types, that you can only
store information in one field at any one time.
Thus, unions are used to save memory. They are useful for applications that
involve multiple members, where values need not be assigned to all the members
at any one time.
data_type var–name;
data_type var–name;
..................
};
by - Hari Krishna
Page 24
Program:
#include <stdio.h>
#include <string.h>
union Data
{
int i;
float f;
char str[20];
};
int main( )
{
union Data data;
data.i = 10;
data.f = 220.5;
strcpy( data.str, "C Programming");
printf( "data.i : %d\n", data.i);
printf( "data.f : %f\n", data.f);
printf( "data.str : %s\n", data.str);
return 0;
}
Output:
data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming
by - Hari Krishna
Page 25
Pointers
A pointer variable points to a data type (like int) of the same type, and is
created with the * operator.
The ‘*’ informs the compiler that ptr is a pointer variable and the int
specifies that it will store the address of an integer variable.
The ‘&’ operator retrieves the address of x, and copies that to the contents
of the pointer ptr.
by - Hari Krishna
Page 26
Program:
#include <stdio.h>
int main ()
{
int var = 20; /* actual variable declaration */
int *ip; /* pointer variable declaration */
ip = &var; /* store address of var in pointer variable*/
printf("Address of var variable: %x\n", &var );
/* address stored in pointer variable */
printf("Address stored in ip variable: %x\n", ip );
/* access the value using the pointer */
printf("Value of *ip variable: %d\n", *ip );
return 0;
}
Output:
Address of var variable: 1586877c
Address stored in ip variable: 1586877c
Value of *ip variable: 20
by - Hari Krishna
Page 27
Null Pointer
A NULL pointer which is a special pointer value and does not point to any
value.
This means that a NULL pointer does not point to any valid memory
address.
Program:
#include <stdio.h>
int main ()
{
int *ptr = NULL;
printf("The value of ptr is : %x\n", &ptr );
return 0;
}
Output: The value of ptr is: 0
by - Hari Krishna
Page 28
Generic Pointer
A generic pointer is a pointer variable that has void as its data type. The
void pointer, or the generic pointer, is a special type of pointer that can
point to variables of any data type.
Generic pointers are used when a pointer has to point to data of different
types at different time.
Pointer to Pointer
by - Hari Krishna
Page 29
Pointers are used for storing address of dynamically allocated arrays and
for arrays which are passed as arguments to functions.
Program:
#include <stdio.h>
int main()
{
int arr[] = { 10, 20, 30, 40, 50, 60 };
int* ptr = arr;
Output:
Size of arr[] : 24
Size of ptr : 8
by - Hari Krishna
Page 30
Pointer to Array:
Program:
#include <stdio.h>
int main ()
{
int *arr[3];
int *a;
printf( "Value of array pointer variable : %d", arr);
printf( "Value of pointer variable : %d", &a);
return 0;
}
Output:
by - Hari Krishna
Page 31
Array of Pointers in C:
Program:
#include <stdio.h>
int main()
{
int var1 = 100; // declaring some temp variables
int var2 = 200;
int var3 = 300;
int* ptr_arr[3] = { &var1, &var2, &var3 }; // array of
pointers to integers
for (int i = 0; i < 3; i++) // traversing using loop
{
printf("Value of var%d: %d\tAddress: %p\n", i + 1,
*ptr_arr[i], ptr_arr[i]);
}
return 0;
}
Output:
by - Hari Krishna
Page 32
malloc( )
Example:
by - Hari Krishna
Page 33
Program:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n, i,*ptr, sum=0;
printf("Enter number of elements: ");
scanf("%d",&n);
ptr=(int*)malloc(n*sizeof(int));
if(ptr==NULL)
{
printf("Sorry! unable to allocate memory");
exit(0);
}
printf("Enter elements of array: ");
for(i=0;i<n;++i)
{
scanf("%d", ptr+i);
sum += *(ptr+i);
}
printf("Sum=%d", sum);
free(ptr);
return 0;
}
Output:
Enter number of elements:
3
Enter elements of array:
10
20
30
Sum=60
by - Hari Krishna
Page 34
calloc( )
Example:
Program:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n,i,*ptr,sum=0;
printf("Enter number of elements: ");
scanf("%d",&n);
ptr=(int*)calloc(n,sizeof(int)); //memory allocated using calloc
if(ptr==NULL)
{
printf("Sorry! unable to allocate memory");
exit(0);
}
printf("Enter elements of array: ");
for(i=0;i<n;++i)
{
scanf("%d",ptr+i);
sum += *(ptr+i);
by - Hari Krishna
Page 35
}
printf("Sum=%d",sum);
free(ptr);
return 0;
}
Output:
Enter number of elements: 3
Enter elements of array:
10
10
10
Sum=30
free( )
Syntax: free(ptr)
by - Hari Krishna
Page 36
Example:
Program:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr = (int *)malloc(sizeof(int));
*ptr = 5;
printf("*ptr = %d", *ptr);
free(ptr); // deallocating the memory
printf("\nptr = %d", ptr); // ptr now contains a garbage value address
ptr = NULL;// assigning NULL to escape the garbage value errors
printf("\nMemory freed at runtime!");
return 0;
}
Output: *ptr = 5
ptr = -1172241760
Memory freed at runtime!
by - Hari Krishna
Page 37
realloc( )
Example:
by - Hari Krishna
Page 38
Program:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *ptr;
int x = 20;
ptr = malloc(sizeof(int)); // allocating memory using malloc
ptr[0] = x;
printf("Value of ptr before memory reallocation : %d\n", ptr[0]);
ptr = realloc(ptr, 5 * sizeof(int)); // reallocating memory using realloc
printf("Value of ptr after memory reallocation : %d", ptr[0]);
return 0;
}
Output:
Value of ptr before memory reallocation: 20
Value of ptr after memory reallocation: 20
by - Hari Krishna
Page 39
Functions:
In the figure, we can see that main() calls a function named func1(). Therefore,
main() is known as the calling function and func1() is known as the called
function
by - Hari Krishna
Page 40
Function Declaration:
Function Definition:
Function Call:
by - Hari Krishna
Page 41
There are two ways in which arguments or parameters can be passed to the
called function.
Call by value - The values of the variables are passed by the calling
function to the called function.
Call by reference - The addresses of the variables are passed by the calling
function to the called function.
Unlike a fixed array, where the array size must be fixed at compile time,
dynamically allocating an array allows us to choose an array length at
runtime.
A dynamic array is quite similar to a regular array, but its size is modifiable
during program runtime.
A dynamic array can expand its size even after it has been filled.
Dynamically allocated arrays are allocated on the heap at run time.
by - Hari Krishna
Page 42
by - Hari Krishna
Page 43
Example: (malloc)
#include <stdio.h>
#include <stdlib.h>
typedef struct vector
{
int size;
int arr[];
}vector;
int main()
{
int n;
printf("Enter Size of the array: ");
scanf("%d", &n);
vector *ptr = (vector * ) malloc( sizeof (vector * ) + n * sizeof(int));
// This implies 'ptr->arr' can hold `n` integers.
by - Hari Krishna
Page 44
Example:2 calloc
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n;
printf("Size of the array: ");
scanf("%d", &n);
int *arr = calloc(n, sizeof(int)); // Creating enough space for 'n' integers.
if (arr == NULL)
{
printf("Unable to allocate memory\n");
by - Hari Krishna
Page 45
return -1;
}
printf("Enter the elements (space/newline separated): ");
for (int i = 0; i < n; i++)
scanf("%d", arr + i); // Notice that, (arr + i) points to ith element
printf("Given array: ");
for (int i = 0; i < n; i++)
printf("%d ", *(arr + i)); // Dereferencing the pointer
printf("\n");
printf("Removing first element i.e., arr[0] = %d.\n", arr[0]);
for (int i = 1; i < n; i++)
arr[i - 1] = arr[i];
arr = realloc(arr, (n - 1) * sizeof(int));
printf("Modified Array: ");
for (int i = 0; i < n - 1; i++)
printf("%d ", arr[i]);
printf("\n");
free(arr);
return 0;
}
Output:
Given array: 10 20 30 40 50
Modified Array: 20 30 40 50
by - Hari Krishna
Page 46
Properties of array:
There are some of the properties of an array that are listed as follows -
Each element in an array is of the same data type and carries the same size
that is 4 bytes.
Elements in the array are stored at contiguous memory locations from
which the first element is stored at the smallest memory location.
Elements of the array can be randomly accessed since we can calculate the
address of each element of the array with the given base address and the
size of the data element.
Representation of an array:
As stated above, all the data elements of an array are stored at contiguous
locations in the main memory.
The name of the array represents the base address or the address of the first
element in the main memory.
Each element of the array is represented by proper indexing.
by - Hari Krishna
Page 47
Length of Arry: 5
First Index: 0
Last Index: 4
Basic operations:
by - Hari Krishna
Page 48
Insertion operation:
This operation is performed to insert one or more elements into the array.
As per the requirements, an element can be added at the beginning, end, or
at any index of the array.
Now, let's see the implementation of inserting an element into the array.
Example:
#include <stdio.h>
int main()
{
int arr[20] = { 10, 20, 30, 40 };
int i, x, pos, n = 5;
printf("Array elements before insertion\n");
for (i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
x = 50; // element to be inserted
pos = 4;
n++;
for (i = n-1; i >= pos; i--)
arr[i] = arr[i - 1];
arr[pos - 1] = x;
printf("Array elements after insertion\n");
for (i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
Output:
by - Hari Krishna
Page 49
Deletion operation:
As the name implies, this operation removes an element from the array and
then reorganizes all of the array elements.
Example:
#include <stdio.h>
void main()
{
int arr[] = {100, 200, 300, 400, 500};
int k = 30, n = 5;
int i, j;
printf("Given array elements are :\n");
for(i = 0; i<n; i++)
{
printf("arr[%d] = %d, ", i, arr[i]);
}
j = k;
while( j < n)
{
arr[j-1] = arr[j];
j = j + 1;
}
n = n -1;
printf("\nElements of array after deletion:\n");
for(i = 0; i<n; i++)
{
printf("arr[%d] = %d, ", i, arr[i]);
}
}
Output:
by - Hari Krishna
Page 50
Search operation:
Example:
#include <stdio.h>
void main()
{
int arr[10] = { 10, 20, 30, 40, 50,60,70,80,90,100};
int item = 70, i, j=0 ;
printf("Given array elements are :\n");
for(i = 0; i<10; i++)
{
printf("arr[%d] = %d, ", i, arr[i]);
}
printf("\n Element to be searched = %d", item);
while( j < 10)
{
if( arr[j] == item )
{
break;
}
j = j + 1;
}
printf("\n Element %d is found at %d position", item, j+1);
}
Output:
by - Hari Krishna
Page 51
Update operation:
Example:
#include <stdio.h>
void main()
{
int arr[5] = {18, 30, 15, 70, 12};
int item = 50, i, pos = 3;
printf("Given array elements are :\n");
for(i = 0; i<5; i++)
{
printf("arr[%d] = %d, ", i, arr[i]);
}
arr[pos-1] = item;
printf("\n Array elements after pupation :\n");
for(i = 0; i<5; i++)
{
printf("arr[%d] = %d, ", i, arr[i]);
}
}
Output:
arr[0] = 10, arr[1] = 20, arr[2] = 30, arr[3] = 40, arr[4] = 50,
arr[0] = 10, arr[1] = 20, arr[2] = 60, arr[3] = 40, arr[4] = 50,
by - Hari Krishna
Page 52
Algorithm
1. Time Complexity
2. Space Complexity
Space Complexity
Fixed part: The space needed for storing instructions, constants, variables,
and structures variables (like arrays and structures).
Variable part: The space needed for recursion stack, and for structured
variables that are allocated space dynamically during runtime of a program.
The space needed by both parts may varies from problem to problem.
by - Hari Krishna
Page 53
Time Complexity
This denotes the behavior of the algorithm with respect to the worst
possible case of the input instance.
It gives us an assurance that the algorithm will never go beyond this time
limit.
Notations
by - Hari Krishna
Page 54
If f(n) and g(n) are the functions defined on a positive integer number n,
then f(n) = O(g(n)).
For example, if an algorithm’s running time is O(n), then it means that
the running time of the algorithm increases linearly with the input size n
or less.
by - Hari Krishna
Page 55
This notation provides both an upper and lower bound on the growth rate
of an algorithm’s running time or space usage.
It represents the average-case scenario, i.e., the amount of time or space
an algorithm typically needs to solve a problem.
For example, if an algorithm’s running time is Θ(n), then it means that
the running time of the algorithm increases linearly with the input size n.
by - Hari Krishna
Page 56
Algorithm Efficiency:
f(n) = efficiency
Linear loops
Logarithmic Loops
for(i = 1; i < n; i *= 2)
statement block;
f(n) = log n
Linear logarithmic
Quadratic loop
by - Hari Krishna
Page 57
Dependent Quadratic
by - Hari Krishna