You are on page 1of 48

Data Structure Practical

53003190073

PRACTICAL 1
1.1. Write a program to store the elements in 1-D array and perform the operations like searching, sorting and
reversing the elements. [Menu Driven]

1.1.1 Searching Operation


Theory: Searching is an operation or a technique that helps finds the place of a given element or
value in the list. Any search is said to be successful or unsuccessful depending upon whether the
element that is being searched is found or not. Some of the standard searching technique that is
being followed in the data structure is listed below:
 Linear Search or Sequential Search
 Binary Search

 Linear Search or Sequential Search: This is the simplest method for searching. In this
technique of searching, the element to be found in searching the elements to be found is
searched sequentially in the list. This method can be performed on a sorted or an unsorted list
(usually arrays). In case of a sorted list searching starts from 0 th element and continues until
the element is found from the list or the element whose value is greater than (assuming the list
is sorted in ascending order), the value being searched is reached.

Algorithm: Consider LA is a linear array with N elements and K is a positive integer such


that K<=N. Following is the algorithm to find an element with a value of ITEM using sequential
search.
1. Start
2. Set J = 0
3. Repeat steps 4 and 5 while J < N
4. IF LA[J] is equal ITEM THEN GOTO STEP 6
5. Set J = J +1
6. PRINT J, ITEM
7. Stop

Code for Searching operation:


#include<stdio.h>
#include<conio.h>
void main()
{
int A[]={1,3,5,7,8};
int item=5,n=5;
int i=0,j=0;
printf("The original array elements are:\n");
for(i=0;i<n;i++)
{
printf("A[%d]=%d\n",i,A[i]);
}

1
Data Structure Practical
53003190073

while(j<n)
{
if(A[j]==item)
{
break;
}
j=j+1;
}
printf("Found element %d at position %d \n",item,j+1);
}

Output:

Conclusion: In the above practical, element 5 was found at position 3 in the array A=[1,3,5,7,8]
using search operation.

1.1.2 Sorting Operation


Theory: Sorting refers to the operation or technique of arranging and rearranging sets of data in
some specific order. A collection of records called a list where every record has one or more
fields. The fields which contain a unique value for each record is termed as the key field. For
example, a phone number directory can be thought of as a list where each record has three fields
- 'name' of the person, 'address' of that person, and their 'phone numbers'. Being unique phone
number can work as a key to locate any record in the list.

2
Data Structure Practical
53003190073

Sorting is the operation performed to arrange the records of a table or list in some order
according to some specific ordering criterion. Sorting is performed according to some key value
of each record.
The records are either sorted either numerically or alphanumerically. The records are then
arranged in ascending or descending order depending on the numerical value of the key. Here is
an example, where the sorting of a lists of marks obtained by a student in any particular subject
of a class.

Algorithm: Consider LA is a linear array with N elements and K is a positive integer such that
K<=N. Following is the algorithm to update an element available at the Kth position of LA.
1. Start
2. Set LA[K-1] = ITEM
3. Stop

Code for Sorting Operation:


//C program to sort the array in an

//ascending order using selection sort

#include<stdio.h>

#include<conio.h>

void swap(int* xp,int* yp)

int temp=*xp;

*xp=*yp;

*yp=temp;

//Functionto perform Selection Sort

void selectionSort(int arr[],int n)

int i,j,min_idx;

//One by one move boundary of unsorted subarray

for(i=0;i<n-1;i++)

//Find the minimum element in unsorted array

min_idx=i;

3
Data Structure Practical
53003190073

for(j=i+1;j<n;j++)

if(arr[j]<arr[min_idx])

min_idx=j;

//Swap the found minimum element

//with the first element

swap(&arr[min_idx],&arr[i]);

//Function to print an array

void printArray(int arr[],int size)

int i;

for(i=0;i<size;i++)

printf("%d",arr[i]);

printf("\n");

//Driver code

int main()

int arr[]={0,23,14,12,9};

int n=sizeof(arr)/sizeof(arr[0]);

clrscr();

printf("Original array: \n");

printArray(arr,n);

selectionSort(arr,n);

printf("\n Sorted array in Ascending order: \n");

printArray(arr,n);

getch();

return 0;

4
Data Structure Practical
53003190073

Output:

Conclusion: In the above experiment, the array arr[]={0,23,14,12,9} is sorted and the output is
arr[]={0,9,12,14,23}.

1.1.3 Reversing of an element


Theory: Reversing string is an operation of Stack by using Stack we can reverse any string, here
we implemented a program in C - this will reverse given string using Stack. The logic behind to
implement this program: Read a string. Push all characters until NULL is not found - Characters
will be stored in stack variable.

Algorithm:
STEP 1: START
STEP 2: INITIALIZE arr[] = {1, 2, 3, 4, 5}
STEP 3: length= sizeof(arr)/sizeof(arr[0])
STEP 4: PRINT "Original Array:"
STEP 5: REPEAT STEP 6 and STEP 7 UNTIL i<length
STEP 6: PRINT arr[i]
STEP 7: i=i+1
STEP 8: PRINT new line.
STEP 9: PRINT "Array in reverse order"
STEP 10: SET i=length-1. REPEAT STEP 11 and STEP 12 UNTIL i>=0
STEP 11: PRINT a[i]
STEP 12: i=i-1
STEP 13: RETURN 0.
STEP 14: END

5
Data Structure Practical
53003190073

Code for Reverse of an Array:

#include<stdio.h>
#include<conio.h>
void reverseArray(int arr[],int start,int end)
{
int temp;
while(start<end)
{
temp=arr[start];
arr[start]=arr[end];
arr[end]=temp;
start++;
end--;
}
}
void printArray(int arr[],int size)
{
int i;
for(i=0;i<size;i++)
printf("%d",arr[i]);
printf("\n");
}
int main()
{
int arr[]={1,2,3,4,5,6};
int n=sizeof(arr)/sizeof(arr[0]);
clrscr();
printArray(arr,n);
reverseArray(arr,0,n-1);
printf("Reverse array is: \n");
printArray(arr,n);
getch();
return 0;
}

6
Data Structure Practical
53003190073

Output:

Conclusion: In the above code, an Array arr[]={1,2,3,4,56} is reversed to get an output


arr[]={1,2,3,4,5,6}.

1.2. Read the two arrays from the user and merge them and display the elements in sorted order.

Theory: Merge sort is a sorting technique based on divide and conquer technique. With worst-
case time complexity being Ο(n log n), it is one of the most respected algorithms.
Merge sort first divides the array into equal halves and then combines them in a sorted manner.
It divides input array in two halves, calls itself for the two halves and then merges the two sorted
halves. The merge() function is used for merging two halves. The merge(arr, l, m, r) is key
process that assumes that arr[l..m] and arr[m+1..r] are sorted and merges the two sorted sub-
arrays into one.
Algorithm: 1. create two arrays of some fixed size and define their elements in sorted fashion.
2. Take two variables i and j, which will be at the 0th position of these two arrays.
3. Elements will be compared one by one using i and j in for loop, and whichever element is
smaller than the other, that element will get inserted to final array and the position (either i or j)
will move by one, whereas the other array’s track position will remain in that same place.
4. Above work will be done till we reach the end of either array. After that, one of the array
whose elements are still to be added, its elements will get straightaway added to the final array.

7
Data Structure Practical
53003190073

Code for Merge Sort:


#include <stdio.h>
// Merge arr1[0..n1-1] and arr2[0..n2-1] into
// arr3[0..n1+n2-1]
void mergeArrays(int arr1[], int arr2[], int n1, int n2, int arr3[])
{
int i = 0, j = 0, k = 0;

// Traverse both array


while (i<n1 && j <n2)
{
// Check if current element of first array is smaller than current
element
// of second array. If yes, store first array element and increment
first array
// index. Otherwise do same with second array
if (arr1[i] < arr2[j])
arr3[k++] = arr1[i++];
else
arr3[k++] = arr2[j++];
}
// Store remaining elements of first array
while (i < n1)
arr3[k++] = arr1[i++];
// Store remaining elements of second array
while (j < n2)
arr3[k++] = arr2[j++];
}

int main()
{
int arr1[] = {1, 3, 5, 7};
int n1 = sizeof(arr1) / sizeof(arr1[0]);

int arr2[] = {2, 4, 6, 8};


int n2 = sizeof(arr2) / sizeof(arr2[0]);

int arr3[n1+n2];
mergeArrays(arr1, arr2, n1, n2, arr3);

printf("Array after merging\n");


for (int i=0; i < n1+n2; i++)
printf("%d ", arr3[i]);

8
Data Structure Practical
53003190073

return 0;
}

Output:

Conclusion: In the above practical, element 8 was found at position 1 in the array after merging
1,2,3,4,5,6,7,8 using search operation.

1.3 Write a program to perform the Matrix addition, Multiplication and Transpose Operation.
1.3.1. Matrix Multiplication:

Theory: In article C Programming Matrix Multiplication a matrix is a grid that is used to store
data in a structured format. It is often used with a table, where the data is represented in
horizontal rows and vertical columns. Matrices are often used in programming languages and are
used to represent the data in a graphical structure. In programming if the user wants to multiply,
add, subtract and divide two matrices, then the order of the matrix should be declared first. Once
the order of the matrix is declared for the first and second matrix, then the elements (input) for
the matrices are needed to be entered by the user. If the order of the matrix is not proportionate to
each other, then the error message will be displayed which is implanted by a programmer in the
condition statement. If a matrix contains only one row then it is called a row vector, and if it
contains only one column then it is called a column vector.

9
Data Structure Practical
53003190073

A matrix that contains the same number of rows and columns then it is called a square matrix.
Matrix is used to store a group of related data. Some of the programming languages are used to
support matrices as a data type that offers more flexibility than a static array. Instead of storing
the values in a matrix, it can be stored as an individual variable, a program can access and
perform operations on the data more efficiently. In C programming matrix multiplications are
done by using arrays, functions, pointers. Therefore, we are going to discuss an algorithm for
Matrix multiplication along with the flowchart, which can be used to write programming code
for 3×3 matrix multiplication in a high-level language. This detailed explanation will help you to
analyze the working mechanism of matrix multiplication and will help to understand how to
write code.

Algorithm: Matrix multiplication:


1. Input the order of the matrix1 (m * n).
2. Input the order of matrix2 (p * q).
3. Input the matrix 1 elements.
4. Input the matrix 2 elements.
5. Repeat from i = 0 to m
6. Repeat from j = 0 to q
7. Repeat from k = 0 to p
8. sum=sum+ mat1[c][k] * mat2[k][d];
9. mat3[c][d]=sum
10. print mat3.

Code for Matrix Multiplication:


#include<stdio.h>

#include<conio.h>

#define N 4

void multiply(int mat1[][N],int mat2[][N],int res[][N])

int i,j,k;

for(i=0;i<N;i++)

for(j=0;j<N;j++)

res[i][j]=0;

for(k=0;k<N;k++)

res[i][j]+=mat1[i][k]*mat2[k][j];

10
Data Structure Practical
53003190073

int main()

int i,j;

int res[N][N];

int mat1[N][N]={{1,1,1,1},{2,2,2,2},{3,3,3,3},{4,4,4,4}};

int mat2[N][N]={{1,1,1,1},{2,2,2,2},{3,3,3,3},{4,4,4,4}};

clrscr();

multiply(mat1,mat2,res);

printf("Result matrix is: \n");

for(i=0;i<N;i++)

for(j=0;j<N;j++)

printf("%d",res[i][j]);

printf("\n");

getch();

return 0;

Output:

11
Data Structure Practical
53003190073

Conclusion: In the above practical, element 16 was found at position 4 in the matrix form
10 10 10 10
20 20 20 20
30 30 30 30
40 40 40 40 using search operation.
1.3.2. Matrix Addition
Theory:
• Addition of matrices is commutative which means A+B = B+A
• Addition of matrices is associative which means A+(B+C) = (A+B)+C
• The order of matrices A, B and A+B is always same
• If order of A and B is different, A+B can’t be computed
• The complexity of addition operation is O(m*n) where m*n is order of matrices

Algorithm/Pseudo code:
Matrix addition:
1. Input the order of the matrix.
2. Input the matrix 1 elements.
3. Input the matrix 2 elements.
12
Data Structure Practical
53003190073

4. Repeat from i = 0 to m
5. Repeat from j = 0 to n
6. mat3[i][j] = mat1[i][j] + mat2[i][j]
7. Print mat3.

Code for Matrix Addition operation:


// This function adds A[][] and B[][], and stores
// the result in C[][]
#include <stdio.h>
#define N 4
void add(int A[][N], int B[][N], int C[][N])
{
int i, j;
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
C[i][j] = A[i][j] + B[i][j];
}

int main()
{
int A[N][N] = { {1, 1, 1, 1},
{2, 2, 2, 2},
{3, 3, 3, 3},
{4, 4, 4, 4}};

int B[N][N] = { {1, 1, 1, 1},


{2, 2, 2, 2},
{3, 3, 3, 3},
{4, 4, 4, 4}};

int C[N][N]; // To store result


int i, j;
add(A, B, C);

printf("Result matrix is \n");


for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
printf("%d ", C[i][j]);
printf("\n");
}

return 0;
}

Output:

13
Data Structure Practical
53003190073

Conclusion: In the above practical, element 16 was found at position 4 in the matrix form
2222
4444
6666
8 8 8 8 using search operation.
1.3.3. Transpose Operation
Theory: Multiplication of matrices is non-commutative which means A*B ≠ B*A.
Multiplication of matrices is associative which means A*(B*C) = (A*B)*C. For computing
A*B, the number of columns in A must be equal to number of rows in B. Existence of A*B does
not imply existence of B*A. The complexity of multiplication operation (A*B) is O(m*n*p)
where m*n and n*p are order of A and B respectively. The order of matrix C computed as A*B
is m*p where m*n and n*p are order of A and B respectively.

Algorithm:
1. Input the order of the matrix1 (m * n).
2. Input the order of matrix2 (p * q).
3. Input the matrix 1 elements.
4. Input the matrix 2 elements.
5. Repeat from i = 0 to m

14
Data Structure Practical
53003190073

6. Repeat from j = 0 to q
7. repeat from k = 0 to p
8. sum=sum+ mat1[c][k] * mat2[k][d];
9. mat3[c][d]=sum
10. print mat3.

Code for Transpose Operation:


#include<stdio.h>

#include<conio.h>

#define N 4

void transpose(int A[][N],int B[][N])

int i,j;

for(i=0;i<N;i++)

for(j=0;j<N;j++)

B[i][j]=A[j][i];

int main()

int A[N][N]={{1,1,1,1},{2,2,2,2},{3,3,3,3},{4,4,4,4}};

int B[N][N],i,j;

clrscr();

transpose(A,B);

printf("Result matrix is: \n");

for(i=0;i<N;i++)

for(j=0;j<N;j++)

printf("%d",B[i][j]);

printf("\n");

getch();

return 0;

15
Data Structure Practical
53003190073

Output:

Conclusion: In the above practical, element 16 was found at position 4 in the matrix form
1234
1234
1234
1 2 3 4 using search operation.

16
Data Structure Practical
53003190073

PRACTICAL 2
2.1 Program to demonstrate all insertion methods on Linked List

Theory:
Like arrays, Linked List is a linear data structure. Unlike arrays, linked list elements are not
stored at a contiguous location; the elements are linked using pointers.

A linked list is represented by a pointer to the first node of the linked list. The first node is called
the head. If the linked list is empty, then the value of the head is NULL.
Each node in a list consists of at least two parts:
1) Data
2) Pointer (Or Reference) to the next node
In C, we can represent a node using structures.

Algorithm/Pseudo code:
Add a node at the front:
1. allocate node
2. put in the data
3. Make next of new node as head
4. move the head to point to the new node

insert a new node after the given prev_node


1. Check if the given prev_node is NULL
17
Data Structure Practical
53003190073

2. Allocate new node


3. Put in the data
4. Make next of new node as next of prev_node
5. move the next of prev_node as new_node

appends a new node at the end


1. allocate node
2. Put in the data
3. This new node is going to be the last node, so make next of it as NULL
4. If the Linked List is empty, then make the new node as head
5. Else traverse till the last node
6. Change the next of last node

Code for insertion:


// C++ program to demonstrate all insertion methods on Linked List

#include<stdio.h>
#include<conio.h>
#include<malloc.h>

// A linked list node


struct Node
{
int data;
struct Node* next;
};

/* Given a reference (pointer to pointer) to the first of a list and an


int, inserts
a new node on the front of the list. */
void pushfront(struct Node** first_ref, int new_data)
{
/* 1. allocate node */
struct Node *new_node;
new_node = (struct Node*)malloc(sizeof(struct Node));

/* 2. put in the data */


new_node->data = new_data;

/* 3. Make next of new node as first */


new_node->next = (*first_ref);

/* 4. move the first to point to the new node */


(*first_ref) = new_node;
}

/* Given a node prev_node, insert a new node after the given


prev_node */
void insertAfter(struct Node* prev_node, int new_data)
{
/*1. check if the given prev_node is NULL */
if (prev_node == NULL)
18
Data Structure Practical
53003190073

{
printf("the given previous node cannot be NULL");
return;
}

/* 2. allocate new node */


//Node* new_node = new Node();
struct Node *new_node;
new_node = (struct Node*)malloc(sizeof(struct Node));

/* 3. put in the data */


new_node->data = new_data;

/* 4. Make next of new node as next of prev_node */


new_node->next = prev_node->next;

/* 5. move the next of prev_node as new_node */


prev_node->next = new_node;
}

/* Given a reference (pointer to pointer) to the first


of a list and an int, appends a new node at the end */
void append(struct Node** first_ref, int new_data)
{
/* 1. allocate node */
//Node* new_node = new Node();
struct Node *new_node;
new_node = (struct Node*)malloc(sizeof(struct Node));

Node last = *first_ref; / used in step 5*/

/* 2. put in the data */


new_node->data = new_data;

/* 3. This new node is going to be


the last node, so make next of
it as NULL*/
new_node->next = NULL;

/* 4. If the Linked List is empty,


then make the new node as first */
if (*first_ref == NULL)
{
*first_ref = new_node;
return;
}

/* 5. Else traverse till the last node */


while (last->next != NULL)
last = last->next;

/* 6. Change the next of last node */


last->next = new_node;
return;
}
19
Data Structure Practical
53003190073

void searchdata(struct Node *node, int item)


{
while (node != NULL)
{
if(node->data==item)
{
printf("%d found in the list:\n",node->data);
return;
}
node = node->next;
}
}

void reverselist(struct Node** second_ref, Node *first)


{ // check if empty
if(first==NULL) {
printf("\nNothing to reverse in list\n");
return; }
//reverse list till
while(first->next!=NULL)
{
struct Node *new_node;
new_node = (struct Node*)malloc(sizeof(struct Node)); // create
new node
// new_node->next=NULL;
new_node->data = first->data;
first=first->next;
new_node->next=(*second_ref);
(*second_ref)=new_node;
}
// add the last node to the reverse list
//Node* new_node = new Node();
struct Node *new_node;
new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->data=first->data;
new_node->next=(*second_ref);
(*second_ref)=new_node;
return;
}

// This function prints contents of


// linked list starting from first
void printList(struct Node *node)
{
while (node != NULL)
{
printf("\t %d",node->data);
node = node->next;
}
return;
}

/* Main Driver code*/


int main()
{
20
Data Structure Practical
53003190073

/* Start with the empty list */


struct Node *first=NULL;
struct Node *second_ref = NULL;
int item;

// clrscr();
printf("Insert 6. So linked list becomes 6->NULL\n");
append(&first, 6);
printf("Created Linked list is: ");
printList(first);

printf("\nInsert 7 at the beginning,So linked list becomes 7->6-


>NULL\n");
pushfront(&first, 7);
printf("Created Linked list is: ");
printList(first);

printf("\nInsert 1 at the beginning.So linked list becomes 1->7-


>6->NULL\n");
pushfront(&first, 1);
printf("Created Linked list is: ");
printList(first);

printf("\nInsert 4 at the end. So linked list becomes 1->7->6->4-


>NULL\n");
append(&first, 4);
printf("Created Linked list is: ");
printList(first);

printf("\nInsert 8, after 7. So linked list becomes 1->7->8->6->4-


>NULL\n");
insertAfter(first->next, 8);

printf("Created Linked list is: ");


printList(first);

printf("\nEnetr the item to search: ");


scanf("%d",&item);
searchdata(first,item);

printf("Printing Revese of the List: ");


reverselist(&second_ref,first);
printList(second_ref);

getch();

return 0;
}

21
Data Structure Practical
53003190073

Output:

Conclusion:
Why Linked List?
Arrays can be used to store linear data of similar types, but arrays have the following limitations.
1) The size of the arrays is fixed: So we must know the upper limit on the number of elements in
advance. Also, generally, the allocated memory is equal to the upper limit irrespective of the
usage.
2) Inserting a new element in an array of elements is expensive because the room has to be
created for the new elements and to create room existing elements have to be shifted.
Advantages over arrays
1) Dynamic size
2) Ease of insertion/deletion
Drawbacks:
1) Random access is not allowed. We have to access elements sequentially starting from the first
node. So we cannot do binary search with linked lists efficiently with its default implementation.
Read about it here.
2) Extra memory space for a pointer is required with each element of the list.
3) Not cache friendly. Since array elements are contiguous locations, there is locality of
reference which is not there in case of linked lists.

1.2. Given a reference (pointer to pointer) to the head of a list and an int, inserts a new
node on the front of the list.

Theory:
Like arrays, Linked List is a linear data structure. Unlike arrays, linked list elements are not
stored at a contiguous location; the elements are linked using pointers.

22
Data Structure Practical
53003190073

A linked list is represented by a pointer to the first node of the linked list. The first node is called
the head. If the linked list is empty, then the value of the head is NULL.
Each node in a list consists of at least two parts:
1) Data
2) Pointer (Or Reference) to the next node
In C, we can represent a node using structures

Algorithm/Pseudo code:

Inserts a new node on the front of the list.


1. allocate node
2. put in the data
3. Make next of new node as head and previous as NULL
4. change prev of head node to new node
5. move the head to point to the new node

insert a new node after the given node


1. allocate new node
2. check if the given prev_node is NULL
3. put in the data
4. Make next of new node as next of prev_node
5. Make the next of prev_node as new_node
6. Make prev_node as previous of new_node
7. Change previous of new_node's next node
appends a new node at the end
1. allocate node
2. put in the data
3. This new node is going to be the last node, so make next of it as NULL
4. If the Linked List is empty, then make the new node as head
5. Else traverse till the last node
6. Change the next of last node
7. Make last node as previous of new node

Code:
#include<stdio.h>
#include<conio.h>
// A linked list node
struct Node {
int data;
struct Node* next;
struct Node* prev;
};

/* Given a reference (pointer to pointer) to the head of a list


and an int, inserts a new node on the front of the list. */
void insertfront(struct Node** head_ref, int new_data)
{
/* 1. allocate node */

23
Data Structure Practical
53003190073

struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));

/* 2. put in the data */


new_node->data = new_data

/* 3. Make next of new node as head and previous as NULL */


new_node->next = (*head_ref);
new_node->prev = NULL;

/* 4. change prev of head node to new node */


if ((*head_ref) != NULL)
(*head_ref)->prev = new_node;

/* 5. move the head to point to the new node */


(*head_ref) = new_node;
}

/* Given a node as prev_node, insert a new node after the given node */
void insertAfter(struct Node* prev_node, int new_data)
{
/* 1. allocate new node */
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
/*2. check if the given prev_node is NULL */
if (prev_node == NULL) {
printf("the given previous node cannot be NULL");
return;
}
/* 3. put in the data */
new_node->data = new_data;
/* 4. Make next of new node as next of prev_node */
new_node->next = prev_node->next;
/* 5. Make the next of prev_node as new_node */
prev_node->next = new_node;
/* 6. Make prev_node as previous of new_node */
new_node->prev = prev_node;
/* 7. Change previous of new_node's next node */
if (new_node->next != NULL)
new_node->next->prev = new_node;
}

/* Given a reference (pointer to pointer) to the head


of a DLL and an int, appends a new node at the end */
void append(struct Node** head_ref, int new_data)
{
/* 1. allocate node */
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
struct Node* last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->data = new_data;
/* 3. This new node is going to be the last node, so make next of
it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new
node as head */
if (*head_ref == NULL) {
new_node->prev = NULL;
*head_ref = new_node;
24
Data Structure Practical
53003190073

return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
/* 7. Make last node as previous of new node */
new_node->prev = last;
return;
}

// This function prints contents of linked list starting from the given
node
void printList(struct Node* node)
{
struct Node* last;
printf("\nTraversal in forward direction \n");
while (node != NULL) {
printf(" %d ", node->data);
last = node;
node = node->next;
}

printf("\nTraversal in reverse direction \n");


while (last != NULL) {
printf(" %d ", last->data);
last = last->prev;
}
}

/* Drier program to test above functions*/


int main()
{
/* Start with the empty list */
struct Node* head = NULL;
clrscr();
// Insert 6. So linked list becomes 6->NULL
insertfront(&head, 15);
// append(&head, 6);
// Insert 7 at the beginning. So linked list becomes 7->6->NULL
insertfront(&head, 7);
// Insert 1 at the beginning. So linked list becomes 1->7->6->NULL
insertfront(&head, 1);
// Insert 4 at the end. So linked list becomes 1->7->6->4->NULL
// append(&head, 4);
// Insert 8, after 7. So linked list becomes 1->7->8->6->4->NULL
insertAfter(head, 8);
printf("DLL in Original order ");
// and reverse oreder is: ");
printList(head);
getch();
return 0;
}

Output:

25
Data Structure Practical
53003190073

Conclusion:
The above program shows different types for insertion of nodes in linked list.

PRACTICAL 3
3. Implement the following for Stack:
3.1. Write a program to implement the concept of Stack with Push, Pop, Display
and Exit operations.

Theory:
Stack is a LIFO (last in first out) structure. It is an ordered list of the same type of elements. A
stack is a linear list where all insertions and deletions are permitted only at one end of the list.
When elements are added to stack it grow at one end. Similarly, when elements are deleted from
a stack, it shrinks at the same end.

Algorithm/ Pseudo code:


peek()
Algorithm of peek() function −

begin procedure peek


return stack[top]
end procedure

isfull()
Algorithm of isfull() function −
26
Data Structure Practical
53003190073

begin procedure isfull

if top equals to MAXSIZE


return true
else
return false
endif

end procedure

isempty()
Algorithm of isempty() function −

begin procedure isempty

if top less than 1


return true
else
return false
endif

end procedure

Push Operation
The process of putting a new data element onto stack is known as a Push Operation. Push
operation involves a series of steps −

Step 1 − Checks if the stack is full.

Step 2 − If the stack is full, produces an error and exit.

Step 3 − If the stack is not full, increments top to point next empty space.

Step 4 − Adds data element to the stack location, where top is pointing.

Step 5 − Returns success.

Pop Operation
A Pop operation may involve the following steps −

Step 1 − Checks if the stack is empty.

Step 2 − If the stack is empty, produces an error and exit.

Step 3 − If the stack is not empty, accesses the data element at which top is pointing.

27
Data Structure Practical
53003190073

Step 4 − Decreases the value of top by 1.

Step 5 − Returns success.

Code:

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

struct Stack {
int top;
unsigned capacity;
int* array;
};

struct Stack* createStack(unsigned capacity)


{
struct Stack* stack = (struct Stack*)malloc(sizeof(struct Stack));
stack->capacity = capacity;
stack->top = -1;
stack->array = (int*)malloc(stack->capacity * sizeof(int));
return stack;
}

int isFull(struct Stack* stack)


{
return stack->top == stack->capacity - 1;
}

int isEmpty(struct Stack* stack)


{
return stack->top == -1;
}

void push(struct Stack* stack, int item)


{
if (isFull(stack))
return;
stack->array[++stack->top] = item;
printf("%d pushed to stack\n", item);
}

int pop(struct Stack* stack)


{
if (isEmpty(stack))
return INT_MIN;
return stack->array[stack->top--];
}

int peek(struct Stack* stack)


{
if (isEmpty(stack))
return INT_MIN;
return stack->array[stack->top];
}
28
Data Structure Practical
53003190073

int main()
{
struct Stack* stack = createStack(100);

push(stack, 10);
push(stack, 20);
push(stack, 30);
push(stack, 40);
push(stack, 50);
push(stack, 60);

printf("%d popped from stack\n", pop(stack));


printf("Top element is %d\n", peek(stack));

push(stack, 130);
push(stack, 230);
printf("%d popped from stack\n", pop(stack));
printf("Top element is %d\n", peek(stack));

return 0;
}

Output:

Conclusion:
If the stack is full isfull function is called and according to pop and push input from user
respective function is called and peek is used to display the output.

29
Data Structure Practical
53003190073

3.2. Write a program to convert an infix expression to postfix and prefix conversion

Theory:
One of the applications of Stack is in the conversion of arithmetic expressions in high-level
programming languages into machine readable form. As our computer system can only
understand and work on a binary language, it assumes that an arithmetic operation can take place
in two operands only e.g., A+B, C*D,D/A etc. But in our usual form an arithmetic expression
may consist of more than one operator and two operands e.g. (A+B)*C(D/(J+D)).

These complex arithmetic operations can be converted into polish notation using stacks which
then can be executed in two operands and an operator form.

Infix Expression
It follows the scheme of <operand><operator><operand> i.e. an <operator> is preceded and
succeeded by an <operand>. Such an expression is termed infix expression. E.g., A+B

Postfix Expression
It follows the scheme of <operand><operand><operator> i.e. an <operator> is succeeded by both
the <operand>. E.g., AB+

Algorithm/Pseudo code:

Let, X is an arithmetic expression written in infix notation. This algorithm finds the
equivalent postfix expression Y.

1. Push “(“onto Stack, and add “)” to the end of X.


2. Scan X from left to right and repeat Step 3 to 6 for each element of X until the Stack
is empty.
3. If an operand is encountered, add it to Y.
4. If a left parenthesis is encountered, push it onto Stack.
5. If an operator is encountered ,then:
1. Repeatedly pop from Stack and add to Y each operator (on the top of Stack)
which has the same precedence as or higher precedence than operator.
2. Add operator to Stack.
[End of If]
6. If a right parenthesis is encountered ,then:
1. Repeatedly pop from Stack and add to Y each operator (on the top of Stack)
until a left parenthesis is encountered.
2. Remove the left Parenthesis.
[End of If]
[End of If]
7. END

Code:
30
Data Structure Practical
53003190073

// C program to convert infix expression to postfix


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

// Stack type
struct Stack
{
int top;
unsigned capacity;
int* array; //array implemenation
};

// Stack Operations
struct Stack* createStack( unsigned capacity )
{
struct Stack* stack = (struct Stack*) malloc(sizeof(struct Stack));

if (!stack)
return NULL;

stack->top = -1; //empty stack condition


stack->capacity = capacity; //size of the stack

stack->array = (int*) malloc(stack->capacity * sizeof(int));


//allocating memory to stack (size)

return stack;
}
int isEmpty(struct Stack* stack)
{
return stack->top == -1 ;
}
char peek(struct Stack* stack)
{
return stack->array[stack->top]; // to read top element from stack
}
char pop(struct Stack* stack)
{
if (!isEmpty(stack))
return stack->array[stack->top--] ;
return '$';
}
void push(struct Stack* stack, char op)
{
stack->array[++stack->top] = op;
}

// A utility function to check if the given character is operand


int isOperand(char ch)
{
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}

// A utility function to return precedence of a given operator


// Higher returned value means higher precedence
31
Data Structure Practical
53003190073

int Prec(char ch)


{
switch (ch)
{
case '+':
case '-':
return 1;

case '*':
case '/':
return 2;

case '^':
return 3;
}
return -1;
}

// The main function that converts given infix expression


// to postfix expression.
int infixToPostfix(char* exp)
{
int i, k;

// Create a stack of capacity equal to expression size


struct Stack* stack = createStack(strlen(exp));
if(!stack) // See if stack was created successfully
return -1 ;

for (i = 0, k = -1; exp[i]; ++i)


{
// If the scanned character is an operand, add it to output.
if (isOperand(exp[i]))
exp[++k] = exp[i];

// If the scanned character is an ‘(‘, push it to the stack.


else if (exp[i] == '(')
push(stack, exp[i]);

// If the scanned character is an ‘)’, pop and output from the stack
// until an ‘(‘ is encountered.
else if (exp[i] == ')')
{
while (!isEmpty(stack) && peek(stack) != '(')
exp[++k] = pop(stack);
if (!isEmpty(stack) && peek(stack) != '(')
return -1; // invalid expression
else
pop(stack);
}
else // an operator is encountered
{
while (!isEmpty(stack) && Prec(exp[i]) <= Prec(peek(stack)))
exp[++k] = pop(stack);
push(stack, exp[i]);
}
32
Data Structure Practical
53003190073

// pop all the operators from the stack


while (!isEmpty(stack))
exp[++k] = pop(stack );

exp[++k] = '\0';
printf( "%s", exp );
}

// Driver program to test above functions


int main()
{
char exp[] = "a+b*(c^d-e)^(f+g*h)-i";
printf("The Postfix for %s is: ",exp);
infixToPostfix(exp);

char exp2[] = "a+b*c-(d/e+f)-g";


printf("\nThe Postfix for %s is: ",exp2);
infixToPostfix(exp2);

char exp3[] = "a+b*c";


printf("\nThe Postfix for %s is: ",exp3);
infixToPostfix(exp3);

return 0;
}

Output:

Conclusion:
After the running of the program the infix is converted to postfix.

33
Data Structure Practical
53003190073

3.3. Write a program to implement Tower of Hanoi problem.

Theory:
Tower of Hanoi is a mathematical puzzle where we have three rods and n disks. The objective of the
puzzle is to move the entire stack to another rod, obeying the following simple rules:
1) Only one disk can be moved at a time.
2) Each move consists of taking the upper disk from one of the stacks and placing it on top of another
stack i.e. a disk can only be moved if it is the uppermost disk on a stack.
3) No disk may be placed on top of a smaller disk.

Algorithm/Pseudo code:
Take an example for 2 disks:
Let rod 1 = 'A', rod 2 = 'B', rod 3 = 'C'.

Step 1: Shift first disk from 'A' to 'B'.


Step 2: Shift second disk from 'A' to 'C'.
Step 3: Shift first disk from 'B' to 'C'.

The pattern here is:


Shift 'n-1' disks from 'A' to 'B'.
Shift last disk from 'A' to 'C'.
Shift 'n-1' disks from 'B' to 'C'.

Code:
#include <stdio.h>
int i=0;
// C recursive function to solve tower of hanoi puzzle
void towerOfHanoi(int n, char from_rod, char to_rod, char aux_rod)
{
if (n == 1)
{
printf("\n Step %d: Move disk 1 from rod %c to rod %c", ++i,from_rod,
to_rod);
return;
}
towerOfHanoi(n-1, from_rod, aux_rod, to_rod);
printf("\n Step %d: Move disk %d from rod %c to rod %c", ++i,n, from_rod,
to_rod);
towerOfHanoi(n-1, aux_rod, to_rod, from_rod);
}
int main()
{
int n = 4; // Number of disks
towerOfHanoi(n, 'A', 'C', 'B'); // A, B and C are names of rods
return 0;
}

Output:

34
Data Structure Practical
53003190073

Conclusion:
In the above program we have successfully moved the entire stack from one rod to another
without breaking the simple rules.

PRACTICAL 4
4. Implement the following for Queue:
4.1. Write a program to implement the concept of Queue with Insert, Delete, Display and
Exit operations

Theory: A Queue is a linear structure which follows a particular order in which the operations
are performed. The order is First In First Out (FIFO). A good example of a queue is any queue of
consumers for a resource where the consumer that came first is served first. The difference
between stacks and queues is in removing. In a stack we remove the item the most recently
added; in a queue, we remove the item the least recently added.
To implement a queue using array, create an array arr of size n and take two variables front and
rear both of which will be initialized to 0 which means the queue is currently empty. Element
rear is the index upto which the elements are stored in the array and front is the index of the first
element of the array.

Algorithm/Pseudo code:
Now, some of the implementation of queue operations are as follows:
35
Data Structure Practical
53003190073

Enqueue: Addition of an element to the queue. Adding an element will be performed after
checking whether the queue is full or not. If rear < n which indicates that the array is not full then
store the element at arr[rear] and increment rear by 1 but if rear == n then it is said to be an
Overflow condition as the array is full.
Dequeue: Removal of an element from the queue. An element can only be deleted when there is
at least an element to delete i.e. rear > 0. Now, element at arr[front] can be deleted but all the
remaining elements have to shifted to the left by one position in order for the dequeue operation
to delete the second element from the left on another dequeue operation.
Front: Get the front element from the queue i.e. arr[front] if queue is not empty.
Display: Print all element of the queue. If the queue is non-empty, traverse and print all the
elements from index front to rear.

Code for Queue:


// Queue implementation in C
#include <stdio.h>
#define SIZE 5

//function for Queue operations


void enQueue(int);
void deQueue();
void display();

//initialize size and pointers


int items[SIZE], front = -1, rear = -1;

int main() {
//deQueue is not possible on empty queue
deQueue();

//enQueue 5 elements
enQueue(1);
enQueue(2);
enQueue(3);
enQueue(4);
enQueue(5);

//6th element can't be added to queue because queue is full


enQueue(6);

display();

//deQueue removes element entered first i.e. 1


deQueue();

//Now we have just 4 elements


display();

return 0;
}
36
Data Structure Practical
53003190073

//insertion in the queue at the rer end


void enQueue(int value) {
if (rear == SIZE - 1)
printf("\nQueue is Full!!");
else {
if (front == -1) //empty queue
front = 0;
rear++;
items[rear] = value;
printf("\nInserted -> %d", value);
}
}

//deletion from the front end


void deQueue() {
if (front == -1)
printf("\nQueue is Empty!!");
else {
printf("\nDeleted : %d", items[front]);
front++;
if (front > rear)
front = rear = -1;
}
}

// Function to print the queue


void display() {
if (rear == -1)
printf("\nQueue is Empty!!!");
else {
int i;
printf("\nQueue elements are:\n");
for (i = front; i <= rear; i++)
printf("%d ", items[i]);
}
printf("\n");
}

Output:

37
Data Structure Practical
53003190073

Conclusion:
In the above program if the queue is empty data is inserted and if the queue is full the message is
prompted that queue is full and when delete function is called the first element which came in is
deleted.

4.2. Write a program to implement the concept of Circular Queue


Theory: Circular Queue is a linear data structure in which the operations are performed based on
FIFO (First In First Out) principle and the last position is connected back to the first position to
make a circle. It is also called ‘Ring Buffer’.
How Circular Queue Works?
Circular Queue works by the process of circular increment i.e. when we try to increment the
pointer and we reach the end of the queue, we start from the beginning of the queue.
38
Data Structure Practical
53003190073

Algorithm/Pseudo code:
Circular Queue Operations
The circular queue work as follows:

two pointers FRONT and REAR


FRONT track the first element of the queue
REAR track the last elements of the queue
initially, set value of FRONT and REAR to -1

1. Enqueue Operation
check if the queue is full
for the first element, set value of FRONT to 0
circularly increase the REAR index by 1 (i.e. if the rear reaches the end, next it would be at
the start of the queue)
add the new element in the position pointed to by REAR

2. Dequeue Operation
check if the queue is empty
return the value pointed by FRONT
circularly increase the FRONT index by 1
for the last element, reset the values of FRONT and REAR to -1

However, the check for full queue has a new additional case:
Case 1: FRONT = 0 && REAR == SIZE - 1
Case 2: FRONT = REAR + 1
The second case happens when REAR starts from 0 due to circular increment and when its
value is just 1 less than FRONT, the queue is full.

Code for Circular Queue:


// Circular Queue implementation in C

#include <stdio.h>

#define SIZE 5

int items[SIZE];
int front = -1, rear = -1;//condition for empty queue

// Check if the queue is full


int isFull() {
if ((front == rear + 1) || (front == 0 && rear == SIZE - 1)) return 1;
return 0;
}

// Check if the queue is empty


int isEmpty() {

39
Data Structure Practical
53003190073

if (front == -1) return 1;


return 0;
}

// Adding an element
void enQueue(int element) {
if (isFull())
printf("\n Queue is full!! \n");
else {
if (front == -1) front = 0;//condition whn queue was empty... set
new front
rear = (rear + 1) % SIZE; //set the new rear
items[rear] = element;
printf("\n Inserted -> %d", element);
}
}

// Removing an element
int deQueue() {
int element;
if (isEmpty()) {
printf("\n Queue is empty !! \n");
return (-1);
} else {
element = items[front];
if (front == rear) {//when there is only one element
front = -1;
rear = -1;
}
// Q has only one element, so we reset the
// queue after dequeing it. ?
else {
front = (front + 1) % SIZE;
}
printf("\n Deleted element -> %d \n", element);
return (element);
}
}

// Display the queue


void display() {
int i;
if (isEmpty())
printf(" \n Empty Queue\n");
else {
printf("\n Front -> %d ", front);
printf("\n Items -> ");
for (i = front; i != rear; i = (i + 1) % SIZE) {
printf("%d ", items[i]);
}
printf("%d ", items[i]);
printf("\n Rear -> %d \n", rear);
}
}

int main() {
// Fails because front = -1
40
Data Structure Practical
53003190073

deQueue();

enQueue(1);
enQueue(2);
enQueue(3);
enQueue(4);
enQueue(5);

// Fails to enqueue because front == 0 && rear == SIZE - 1


enQueue(6);

display();
deQueue();

display();

enQueue(7);
display();

// Fails to enqueue because front == rear + 1


enQueue(8);

return 0;
}

Output:

41
Data Structure Practical
53003190073

Conclusion:
The circular queue works just as normal queue but there is no overflow condition in a circular
queue until the queue is actually full. Therefore, entering a new element is easy.

4.3. Write a program to implement the concept of Deque


Theory: Deque or Double Ended Queue is a generalized version of Queue data structure that
allows insert and delete at both ends.
Applications of Deque: Since Deque supports both stack and queue operations, it can be used as
both. The Deque data structure supports clockwise and anticlockwise rotations in O(1) time
which can be useful in certain applications.
Also, the problems where elements need to be removed and or added both ends can be efficiently
solved using Deque.

Algorithm/Pseudo code:
1. Create an empty array ‘arr’ of size ‘n’
initialize front = -1 , rear = 0
Inserting First element in deque, at either front or rear will lead to the same result.
After insert Front Points = 0 and Rear points = 0

Insert Elements at Rear end


a). First we check deque if Full or Not
42
Data Structure Practical
53003190073

b). IF Rear == Size-1


then reinitialize Rear = 0 ;
Else increment Rear by '1'
and push current key into Arr[ rear ] = key
Front remain same.

Insert Elements at Front end


a). First we check deque if Full or Not
b). IF Front == 0 || initial position, move Front
to points last index of array
front = size - 1
Else decremented front by '1' and push
current key into Arr[ Front] = key
Rear remain same.

Delete Element From Rear end


a). first Check deque is Empty or Not
b). If deque has only one element
front = -1 ; rear =-1 ;
Else IF Rear points to the first index of array
it's means we have to move rear to points
last index [ now first inserted element at
front end become rear end ]
rear = size-1 ;
Else || decrease rear by '1'
rear = rear-1;

Delete Element From Front end

43
Data Structure Practical
53003190073

a). first Check deque is Empty or Not


b). If deque has only one element
front = -1 ; rear =-1 ;
Else IF front points to the last index of the array
it's means we have no more elements in array so
we move front to points first index of array
front = 0 ;
Else || increment Front by '1'
front = front+1;

Code for Dequeue:


/* C Program to implement Deque using circular array */
#include<stdio.h>
#include<stdlib.h>
#define MAX 7

int deque_arr[MAX];
int front=-1;
int rear=-1;

void insert_frontEnd(int item);


void insert_rearEnd(int item);
int delete_frontEnd();
int delete_rearEnd();
void display();
int isEmpty();
int isFull();

int main()
{
int choice,item;
while(1)
{
printf("\n\n1.Insert at the front end\n");
printf("2.Insert at the rear end\n");
printf("3.Delete from front end\n");
printf("4.Delete from rear end\n");
printf("5.Display\n");
printf("6.Quit\n");
printf("\nEnter your choice : ");
scanf("%d",&choice);

switch(choice)
{
case 1:

44
Data Structure Practical
53003190073

printf("\nInput the element for adding in queue :


");
scanf("%d",&item);
insert_frontEnd(item);
break;
case 2:
printf("\nInput the element for adding in queue :
");
scanf("%d",&item);
insert_rearEnd(item);
break;
case 3:
printf("\nElement deleted from front end is :
%d\n",delete_frontEnd());
break;
case 4:
printf("\nElement deleted from rear end is :
%d\n",delete_rearEnd());
break;
case 5:
display();
break;
case 6:
exit(1);
default:
printf("\nWrong choice\n");
}/*End of switch*/
printf("\nfront = %d, rear =%d\n", front , rear);
display();
}/*End of while*/
}/*End of main()*/

void insert_frontEnd(int item)


{
if( isFull() )
{
printf("\nQueue Overflow\n");
return;
}
if( front==-1 )/*If queue is initially empty*/
{
front=0;
rear=0;
}
else if(front==0)
front=MAX-1;
else
front=front-1;
deque_arr[front]=item ;
}/*End of insert_frontEnd()*/

void insert_rearEnd(int item)


{
if( isFull() )
{
printf("\nQueue Overflow\n");
return;
45
Data Structure Practical
53003190073

}
if(front==-1) /*if queue is initially empty*/
{
front=0;
rear=0;
}
else if(rear==MAX-1) /*rear is at last position of queue */
rear=0;
else
rear=rear+1;
deque_arr[rear]=item ;
}/*End of insert_rearEnd()*/

int delete_frontEnd()
{
int item;
if( isEmpty() )
{
printf("\nQueue Underflow\n");
exit(1);
}
item=deque_arr[front];
if(front==rear) /*Queue has only one element */
{
front=-1;
rear=-1;
}
else
if(front==MAX-1)
front=0;
else
front=front+1;
return item;
}/*End of delete_frontEnd()*/

int delete_rearEnd()
{
int item;
if( isEmpty() )
{
printf("\nQueue Underflow\n");
exit(1);
}
item=deque_arr[rear];

if(front==rear) /*queue has only one element*/


{
front=-1;
rear=-1;
}
else if(rear==0)
rear=MAX-1;
else
rear=rear-1;
return item;
}/*End of delete_rearEnd() */

46
Data Structure Practical
53003190073

int isFull()
{
if ( (front==0 && rear==MAX-1) || (front==rear+1) )
return 1;
else
return 0;
}/*End of isFull()*/

int isEmpty()
{
if( front == -1)
return 1;
else
return 0;
}/*End of isEmpty()*/

void display()
{
int i;
if( isEmpty() )
{
printf("\nQueue is empty\n");
return;
}
printf("\nQueue elements :\n");
i=front;
if( front<=rear )
{
while(i<=rear)
printf("%d ",deque_arr[i++]);
}
else
{
while(i<=MAX-1)
printf("%d ",deque_arr[i++]);
i=0;
while(i<=rear)
printf("%d ",deque_arr[i++]);
}
printf("\n");
}/*End of display() */

Output:

47
Data Structure Practical
53003190073

Conclusion:
In in the above program we can do insertion and deletion for both front and rear end.

48

You might also like