Data Structures With C
Data Structures With C
Chapter 1
Pointers
1.1 What Is A Pointer?
1.2 Pointer Declaration
1.3 Pointer Arithmetic
1.4 Accessing Variables Using Pointer
1.5 Address Operator (&)
1.6 Dereferencing Operator (*)
1.7 .One And Two Dimensional Arrays Using Pointers
1.8 Void Pointers
1.9 Pointers In Function Arguments
1.10 Recursion
1.11 Direct Recursion
1.12 Indirect Recursion
1.13 Array Of Pointers
1.14 Pointer To Pointer
1.15 Pointers To Strings
1.16 Pointers to functions
Exercises
Chapter 2
Structures and Unions
2.1 Definition
2.2 Accessing The Members Of A Structure
2.3 Array Of Structures
2.4 Structures Within Structure (Nested Structure)
2.5 Pointers To Structures
2.6 Structure In Functions
2.7 Unions
2.8 Difference and Similarity Between Structure And Union
Exercises
Chapter 3
Strings and String Operations
3.1 Strings
3.2 Strlen()
3.3 Strcmp()
3.4 Strcat()
3.5 Strcpy()
3.6 Pattern Matching
3.7 Dynamic Memory Allocation
3.8 Malloc()
3.9 Calloc()
3.10 Realloc
3.11 Freeing Memory
Exercises
Chapter 4
Sorting and Searching
4.1 Sorting
4.2 Different Sorting Techniques
4.3 Bubble sort Implementation
4.4 Selection sort
4.5 Selection sort implementation
4.6 Insertion sort
4,7 Insertion sort Implementation
4.8 Quick sort
4.9 Quick sort implementation
4.10 Merge Sort
4.11 Merge Sort Example
4.12 Bucket Sort
4.13 Heap Sort
4.14 Comparison Of Different Sorting Algorithms
4.15 Searching
4.16 Linear Search
4.17 Binary Search
4.18 Difference between Linear Search & Binary Search
Exercises
5
Chapter 5 Stacks and Queues
5.1 Stack
5.2 Implementation of Stack using Arrays and pointers
5.3 Applications of Stacks
5.4 Queues
5.5 Circular Queue
5.6 Priority Queue
5.7 Dequeue
5.8 Input Restricted Dequeues
5.9 Output Restricted Dequeues
5.10 Applications of Queues
Exercises
Chapter 6 Linked lists
6.1 Linked List
6.2 Creation of Linked List
6.3 Inserting Node
6.4 Deletion of Nodes
6.5 Doubly Linked List
6.6 Operations on Doubly Linked List
6.7 Circular Linked List
6.8 Circular Doubly Linked List
6.9 Advantages/Disadvantages of Linked List
Exercises
Chapter 7 Trees
7.1 Tree
7.2 Root
7.3 Degree
7.4 Path length
7.5 Level
7.6 Forest
7.7 Labeled Trees
7.8 Binary Tree
7.9 Application Of Trees
7.10 Binary Tree Operations
7.11 Tree Traversal Methods
7.12 The Binary Search Tree
7.13 Threaded Binary Tree
7.14 Use Of Threaded Binary Tree
Exercises
Chapter 8 Graphs
8.1 Graphs
8.2 Definition
8.3 Adjacency List Representation
8.4 DFS And BFS
8.5 Depth First Search (DFS)
8.6 Breadth First Search (BFS)
8.7 Shortest Path
8.8 Weighted Graph
8.9 Dijkstra Algorithm
Exercises
Exercises
Definition:
A pointer is a variable that contains the address of another variable. We can
have a pointer to any variable type. Using pointers complex data types can be
declared and accessed efficiently.
After declaring a pointer variable one must assign values to it. That is the
pointer must be assigned to some address. We can assign value to pointer in same
way as any other variable data type.
• Here the content of the pointer variable p1 is assigned to the variable sum. That
is, value of p1 is the address of the integer variable sum.
Figure 1.1
A pointer to p1 to an integer variable sum Program to display the address
and contents of a pointer is given next.
Program1.1
#include<stdio.h> void main() { int x; int *p; //
Here A pointer variable of base type integer is declared x=50; p=&x; //The
pointer variable p is assigned the address of x printf(“Value of x is %d\n”,x);
printf(“Value of the variable pointed by p is %d\n”,*p); printf(“Address of x is
%d”,p); getch(); }
Output of the program
Value of x is 50
Value of the variable pointed by p is 50 Address of x is 43522
1.2. Pointer Arithmetic
C language supports four arithmetic operations on pointers.
• Addition +
• Subtraction
• Incrementation ++
• Decrementation -
Here ++ increments the pointer to the address of the next memory location of
the same type variable. The increment is done not by one but by the number of
bytes required for the data type. That is if an integer is 4 bytes, ++ will increment
an integer pointer by 4 and not by 1. Similarly for other operators.
In C you can see two type of unary operators for declaring a pointer type
variable. They are listed below,
• Address operator &
• Dereferencing operator *
1.4. Address Operator(&)
This can be represented the combination of *(asterisk) along with the variable.
Asterisk should be before the variable name. It is also a unary operator that returns
the value of the variable located at the address.
For example: a=*p; Here a gets the value pointed by the pointer p.
Pointers and arrays are equivalent in the following sense. The name of the array
acts as a pointer to the first element of the array. Let us explain this with two
examples:
int a [50]; The above statement declares an array of integers of size 50, having
elements a[0], a[1] ,.., a[49]. This is a one dimensional array.
The variable a can be used as a pointer to the array. Variable a will point to
the starting address of
the array, that is a [0]. The elements of this array are a [0], a[1], …, a[49].
They are integer variables. Logically, these elements are stored in 50 consecutive
memory locations. Therefore a pointer variable of base type integer can point to
these elements.
We know that int *ip declares ip as an integer type pointer. Now the two
statements below, taken together are equivalent to the statement a[3] =7
ip = &a[3]; *ip = 7; taken
together are equivalent to the
statement a[3] =7
Also the statement ip= a is equivalent to saying that ip = &a[0]. Similarly,
ip= a+5 is equivalent to saying that ip = &a[5].Generalizing ,We can say that the
following is true.
If a is an array of size n, having elements a[0], …… a[n-1], of a particular
data type, then a is a pointer of that base type whose value is the address of a[0]
and a+k points to a[k] for any k between 1 and n-1.
Figure 1.2 A two dimensional array b[3][4] with three rows and four
columns.
C treats a two dimensional array as a one dimensional array of rows. Each row
itself is again a one dimensional array.
Now b will point to b[0],which is the first row of the array. Also b+1, b+2,
….. Will be used to access to successive rows of the array b[ ][ ].Now b[0], is the
first row .Since the first row is a one dimensional array,b[0] is a pointer to the first
element b[0][0] of that array . Similarly b[1] is a pointer to the first element b[1][0]
in the second row and so on. Also b[0]+j is a pointer to b[0][j]. Again
*(b+i) is actually same as b[ i] and *(*(b+i)+j) is the pointer representation of
b[i][j].
#define maxsize 50
#include<stdio.h> void main(){ int b[maxsize][maxsize],n_of_rows, n_of_cols, i,*p, j, tvalue;
printf("Enter The number of rows: ");scanf("%d",&n_of_rows); printf("Enter the number of
columns: "); scanf("%d",&n_of_cols);for(i=0;i<=n_of_rows-1;i++){
for(j=0;j<=n_of_cols-1;j++)
{ printf("Enter the (%d,%d) element ", i,j);scanf("%d",&b[i][j]);
}}printf("Contents of array\n");
for(i=0;i<=n_of_rows-1;i++) {
for(j=0;j<=n_of_cols-1;j++){
tvalue=*(*(b+i)+j);printf("%d\t",tvalue); }printf("\n");
}}
9 10 11 12
1.10 Recursion
Definition:
Recursion is a technique widely used to make write complex functions in a simple
way. A function which invokes itself directly or indirectly is called as recursive
function.
int f1 (int n)
{ if (n<=0) return n; return (n+ f1(n-1));
}
The above function contains a call to itself, and so it’s directly recursive.
When you have a large array of data items, names for example, and you want to
access them in sorted order one method is to use an array of pointers. We can use
array of pointers like any other array. The declaration for an integer pointer array
p1 of size 15 is
int *p1 [15];
The elements of above array are p1 [0], p1 [1],...,p1 [14], all of them pointers of
base type integer. An array of pointers can be defined in such a manner that each
item of the array point to an item in the data array. We will illustrate this with a
figure.
A B
0 Rajesh
1 Suresh
2 Aneesh
3 Hridary
4 Joseph
5 Fransis
6 Kannan
Now A is the array of pointers, pointing to the data array B. Instead of sorting B in
alphabetical order, we just sort A in the alphabetical order of elements of B and access
elements of B from elements of
A. This type of sorting has the following advantages.
1. The original data is not changed
2. We save time, because sorting of pointers is simple, compared to sorting of
strings.
Program1.6
Program1.7
#include <stdio.h>
main()
{
int v;
int *p1,**p2;
v=50;
printf("number is =%d\n",v);
p1=&v;
p2=&p1;
printf("address of the number is = %u\n",&v);
printf("value pointed by pointer2 =%u\n",*p2);
printf("value of pointer1 =%u\n",p1);
printf("Value pointed by pointer1=%d\n",*p1);
printf("Value pointed by the pointer pointed by pointer2=%d\n",**p2); }
Pointer to Functions
Just like any other variable,a function is also stored at a memory location and has an
address. The name of the function is a pointer to it. We can also declare pointer to a
function.
The following program illustrates an example for function pointer.
Program1.9
#include <stdio.h> void sampleFunction(int n) { printf( "%d\n", n ); } int main()
{ void (*pointer_to_function)(int);//Declaring a function pointer
pointer_to_function = &sampleFunction;//Intitialising the function pointer
pointer_to_function( 10 );// calling the function using the
function pointer
getch(); return 0; }
10
Chapter II
Structures And Unions
2.1 Definition
A structure is used to represent a related group of items. Each individual item in the structure is
called as a member.
Example:
struct employee
{
char empName[10];
char address[20] ;
char place[10];
int pinCode;
} emp1;
Suppose you want to store the details of 100 students in an array. Each student has a roll no. and name
and the structure student is defined as,
struct student
{
int Roll no;
Char Name[20];
};
Now you can declare an array of size 100 as shown below:
Student NRoll [100];
Each element of the array can be the details of the student. That is an array of structures can be used
just like an ordinary array, to store data having structure.
A member of structure may be another structure. When a structure is declared as the member of
another structure we call it as nested Structure. Using this feature we can build complex structures.
Example:
struct date
{
int day;
int month;
int year
};
struct student
{
char name[20];
int roll no;
struct date dob;
};
We can pass a structure variable as a parameter to a function just as we pass any other variable.
The following program is an example for passing a structure as a parameter to a function.
Program2.2
#include<stdio.h>
struct dob //Declaring a structure
{
int day;
int month;
int year;
};
void main()
{
struct dob d1; //Declaring a structure variable
d1.day=26;
d1.month=8;
d1.year=2007;
display(d1);
getch();
}
void display (struct dob n);
{
printf(“date is%d/%/d/%d\n”,n.day,n.month,n.year);
}
Output of the program
date is 26 /8/ 2007
2.7 Unions
We have a situation where we want to interpret the value of a variable depending upon the context
of the variable. Union stores values of different data types in a single location. This saves memory.
Declaration and usage of union is same as that of structure with the keyword struct replaced by the
keyword union.
For example a merchant may sell items by number or by weight (example: two bottles of squash and
3.5 k.g sugar).In this case the field quantity
sold can be taken as a union of an integer and a float.
.
Declaration
union quantity
{
int no_of_items;
float weight;
};
struct saledetails
{
int type;
union quantity quantity_sold;
};
#include<stdio.h>
typedef union
{
int trucknumber;
char truckname[8];
}load;
typedef struct
{
char itemname[10];
load item;
}goods;
int main()
{
goods gd[10];
int i,n;
printf ("Enter no of shipping items\t");
scanf("%d",&n);
for (i=0;i<n;i++)
{
printf("\nItemname=%s",gd[i].itemname);
printf("\nTruckNumber=%d",gd[i].item.trucknumber);
}
printf("\n");
for (i=0; i<n; i++)
{
printf("Enter the truckname\t");
scanf("%s",gd[i].item.truckname);
}
for (i=0;i<n;i++)
{
printf("\nTruckname=%s",gd[i].item.truckname);
printf("\nTruckNumber=%d",gd[i].item.trucknumber);
}
getch();
return 0;
}
Output of the Program
Enter no of shipping items 2
Enter the itemname ,trucknumber Steel 5678
Enter the itemname ,trucknumber Nickel 6665
Itemname=Steel
TruckNumber=5678
Itemname=Nickel
TruckNumber=6665
Enter the truckname Bangar
Enter the truckname Star7
Truckname=Bangar
TruckNumber=1735287106
Truckname=Star7
TruckNumber=1918989395
In the above program you can see that when we try to print the truck number after reading truck name
it is showing some unknown value. This is because the same space is used for storing truck number
and truck name. So truck name overwrites the truck number.
2.8 Difference and similarity between structure and union
3. Union allocates the memory equal to the maximum memory required by any member of the
union, but structure allocates the memory equal to the total memory required by all the members.
2. In union, one block is used to store all the members of the union. That is, all the members
share same memory. In the case of a structure, each member has their own memory space.
2. Accessing members also have the same syntax (using the . Operator)
3.1 Strings
In C, a string is viewed as an array of characters. A special character called null denoted by “\0”
ends the string.
The following is an example of a string stored as an array of characters.
I L O V E I N D I A \0
C provides for many strings operators. Let us discuss the following in detail.
3.2 strlen ( )
We are using strlen() for knowing the length of the string. The strlen ()checks each array position to
see whether it is null or not.
N=strlen (string);
Sample program to check the length of the string is given below
Program 3.1
#include < stdio.h >
#include < string.h>
void main()
{
char name[100];
int length;
printf(“Enter the string=”);
gets(name);
length=strlen(name);
printf(“\nNumber of characters in the string is=%d”,length);
}
3.3 strcmp()
This function is used to compares two strings. This function returns value 1 if the two strings are
same and it will returns 0 otherwise. This is one of the most commonly used of the string handling
functions.
Example:
strcmp(char *a1, char *a2);
3.4 strcat()
strcat (string1,string2)
string1 and string2 are strings. When the function strcat is executed string2 is appended to string1.
The string at string2 remains unchanged.
strcpy (string1,”sri”);
strcat (string2,”devi”);
printf (“%s”,strcat(string1,string2);
From the above program segment the value of string1 becomes sridevi string at str2 remains
unchanged as devi.
The following shows the implementation of strcat as a program
Program3.2
#include<stdio.h>
void main()
{
char s1[10 ],s2[10 ],s3[30];
int k=0,k1;
printf("Enter the first string\n");
gets(s1);
printf("Enter the second string\n");
gets(s2);
for(k=0;s1[k]!='\0';k++)
s3[k]=s1[k];
k1=k;
k=0;
for(k=0;s2[k]!='\0';k++)
s3[k1+k]=s2[k];
k1=k1+k;
printf("The concatenated string is given below\n");
for (k=0;k<k1;k++)
printf ("%c",s3[k]);
getch();
}
3.5.strcpy()
C does not allow you to assign the characters to a string directly as in the statement Name=”sandya”;
instead use strcpy like this
strcpy (Name,”sandya”);
In the above example sandya is assigned to the string called Name.
void strcpy(s,s1)
{
int k;
char s[],s1[];
for(k=0;s1[k]!=”\0”;k++)
{
s1[k]=s[k];
}
s1[k]=”\0”;
}
Pattern matching in strings is the process of checking whether a given pattern of letters (string) occur
as a substring in a given string. Here we have two inputs the given string, and the pattern string.
Clearly the length of the pattern should not exceed the length of the given string.
The C compiler needs to allocate memory to variables. This Memory allocation can be classified into
two types.
In static memory allocation memory required for a variable is allocated at the time for
compilation.
For example, if you declare x as a float variable by
float x;
Then the memory required for x is the size of a float and allocated at the time of compilation.
Similarly if you want to declare an array of 10 integers by
int a [10];
Then 10 times size of an integer is reserved at the compile time. This has the following
disadvantages.
1. You cannot use more memory than what you have already allocated.
2. If you use less memory than allocated, the remaining memory is wasted. This causes inefficient use
of memory.
This function is used to allocate a heap of storage. The name stands for memory allocation.
The general declaration of malloc function,
char *malloc (size)
int size;
The following program segment illustrate the use of malloc function
struct linkedlist
{
int value
struct linkedlist *value;
};
struct linkedlist *pnode;
pnode=(struct linkedlist*)malloc (sizeof(struct linkedlist));
3.9 Calloc
Calloc is used to allocate contiguous memory on an element-by-element basis. The name stands for
calculated allocation. This is useful in the case of array like structure where continuity of memory
required.
void calloc(elements, element_size);
Thus to assign 500 integer elements that are all initially zero you would do:
int *pnode;
pnode = (int *) calloc(500, sizeof(int));
The following program illustrates the dynamic allocation of arrays using calloc
Program 3.3
#include<stdio.h>
int main()
{
int *array,n,i;
printf("Enter the size of array\t");
scanf("%d",&n);
array=(int*)calloc(n,sizeof(int));
printf("Enter %d numbers\n",n);
for(i=0;i<n;i++)
scanf("%d",&array[i]);
printf("Numbers Entered \n");
for(i=0;i<n;i++)
printf("%d\t",array[i]);
getch();
return 0;
}
3.10 Realloc
Realloc is a function which attempts to change the size of a previously allocated block of memory.
(Realloc stands for reallocate) The new size can be larger or smaller. If the block is made larger then
the old contents remain unchanged and memory is added to the end of the block. If the size is made
smaller then the remaining contents are unchanged
The general declaration for the realloc function is given below
char *realloc (oldblocksize,newblocksize)
int oldblocksize;
int newblocksize;
3.11 Freeing Memory
Memory allocated with malloc lasts as long as you want it. When you have finished using a portion of
memory you should always free(deallocate) it. If you want to deallocate the memory that allocate by
malloc function call, we can use function
free ().
The general declaration for free () function is given below
int free (pnode)
char *pnode;
The following program illustrates the use of malloc( ) to allocate some bytes then use realloc( )
to allocate more bytes and finally use free( ) to deallocate the allocated bytes.
Program 3.4
#include<stdio.h>
int main()
{
char *p,size,newsize;
printf("Enter the size\t");
scanf("%d",&size);
p=(char *)malloc(size); //allocating size bytes to character pointer p.
printf("Enter a string of length %d\t",size);
getchar();
gets(p);
puts(p);
printf("Enter the new size\t");
scanf("%d",&newsize);
p=realloc(size,newsize); //reallocating newsize bytes to character pointer p.
printf("Enter a string of length %d\t",newsize);
getchar();
gets(p);
puts(p);
free(p); //deallocating memory.
printf("Memory is deallocated\n");
getch();
}
4.1 Sorting
1. Bubble sort
It is the oldest and simplest sorting technique. In bubble sort pairs of adjacent values are sorted by
comparing the values with each other. Therefore an item bubbles the entire list, until it reaches one
value that compare to be smaller than the first value. Suppose we have an n number of elements in our
list to sort, then we have to do (n-1) passes (iterations).
Advantages:
Bubble sort is simple and easy to implement.
Disadvantages:
For n no of elements there will be n-1 iterations. So Bubble sort is considered as the most inefficient
sorting algorithm.
Best case:
Under best case if array is already sorted then also the outer loop to execute n-1 times. Time
complexity for best case is O (n ).
2
In order to explain bubble sort we are taking an array of three items. This is shown below.
a[0] 160
a[1] 155
a[2] 120
3. In first iteration i=0, 0th element 160 is compared with 155. Since 160 is greater than 155, we
interchange them. Resulting array is 155,160,120.
Now 160 is in a[1]th position. It is compared with the a[2].120 is less than 160, so we
interchange them. Array is now 155,120,160
2. For the second iteration 0th element 155 is compared with first element. Here 120 is less than
155, so we interchange them. Resulting array is 120,155,160.Now 155 is in a [1], it is compared
with a[2].155 is less than 160,we cannot interchange them. Now the array is in its sorted order.
Resulting array is 120,155, 160.
a[0] 120
a[1] 155
a[2] 160
}
for(i=0;i<n;i++)
{
for(j=0;j<n-1;j++)
{
if(array[j]>array[j+1])
{
tempvalue=array[j];
array[j]=array[j+1];
array[j+1]=tempvalue;
}
}
}
printf("The list sorted in ascending order is\n");
for(i=0;i<n;i++)
{
printf("%d\n",array[i]);
}
getch();
}
Ouput of the Program
Enter the size
5
Enter 5 numbers
99
77
88
66
55
The list sorted in ascending order is
55
66
77
88
99
4.4. Selection sort
In selection sort we are taking the smallest item (unsorted) in the list, and swapping it with the item in
the very next position. Suppose we want to sort the given numbers in ascending order, 0th element is
compared with other elements present in the list, .If the 0th element is greater than the compared
element then they are interchanged. After the first iteration the smallest element is placed in 0th
position. Similar procedure is repeated for the entire list of elements.
Advantages:
Simple technique and easy to implement.
Disadvantages:
Inefficient for large list of elements.
Program for selection sort
a[0] 250
150
a[1]
a[2] 200
a[3] 100
2. For the first iteration i=0, 0t h element is compared with a[1]. 150 is less than 250, we
interchange them. Resulting array is 150 250 200,100.a[0]t h element is again compared with
a[2]th element, which is greater than a[0]th element so we can’t interchange them. Again 150
compared with a[3].100 is less than 150, we interchange them. The resulting array is
100,250,200,150.
3. For the second iteration i=1, a [1] th element compared with a [2]. 200 is less than 250, we
interchange them. Resulting array is 100,200,250,150.
th
a [3] element compared with a[1]. 150 is less than 200, we interchange
them. Resulting array is 100,150,250,200.
3. For the third iteration i=2,250 is compared with a [3]. 200 is less than
250 we interchange them. Resulting array is
a[0] 100
150
a[1]
a[2] 200
a[3] 250
#include<stdio.h>
void main()
{
int array[12],i,n,smallvalue,j,position,tempvalue;
printf("Enter the size\n");
scanf("%d",&n);
printf("enter %d elements\n",n);
for(i=0;i<n;i++)
scanf("%d",&array[i]);
for(i=0;i<n-1;i++)
{
smallvalue=array[i];
position=i;
for(j=i+1;j<n;j++)
{
if(array[j]<smallvalue)
{
smallvalue=array[j];
position=j;
}
}
tempvalue=array[i];
array[i]=smallvalue;
array[position]=tempvalue;
}
printf("\n Sorted array is\n");
for(i=0;i<n;i++)
{
printf("%d\n", array[i]);
}
getch();
}
Sorted array is
33
66
77
88
99
Advantage:
Comparatively simple and it is easy to implement.
Disadvantage:
Inefficient for large lists.
Here we have an array a[3], consists of 3 elements. We can see how insertion sort is going to
implement for sorting numbers in ascending order.
a[0] 160
a[1] 152
a[2] 100
1. For the first iteration i=1, a[1] is compared with a[0].we have found that 152 is less than 160, we
interchange them.
2. For the second iteration i=2, the second element 100 is compared with 160.
Then we interchange them.100 is again compared with 152. The resulting
Array is shown below.
a[0] 100
a[1] 152
a[2] 160
#include<stdio.h>
void main()
{
int array[12],i,j,n,tempvalue;
printf("Enter the size of numbers to sort\n");
scanf("%d",&n);
printf("enter %d numbers\n",n);
for(i=0;i<n;i++)
scanf("%d",&array[i]);
for(i=1;i<n;i++)
{
tempvalue=array[i];
j=i-1;
while((tempvalue<array[j]&&(j>=0)))
{
array[j+1]=array[j];
j=j-1;
}
array[j+1]=tempvalue;
}
printf("Sorted array is \n");
for(i=0;i<n;i++)
printf("%d\n",array[i]);
getch();
}
4.8Quick sort
The quick sort is one of the fastest sorting techniques. Quick sort is an algorithm using recursion.
There are four steps in the algorithm.
If there are no elements or just one element in the array to be sorted, return immediately.
1. Select an element in the array as a “pivot” point. Mainly we are taking the leftmost element in
the array
2. Split the array into two parts - one with elements larger than the pivot and the other with
elements smaller than the pivot.
3. Repeat the algorithm for both halves of the original array.
The efficiency of the algorithm mainly depends upon which element is chosen as the pivot
element. The worst-case efficiency of the quick sort, O (n ), occurs when we have taken the
2
left-most element. As long as the pivot point is chosen randomly, the quick sort has its
algorithmic complexity of O (n log n).
Advantage:
Extremely fast one.
Disadvantage:
Very complex algorithm and highly recursive one.
4.9 Quick sort implementation
We can explain the Quick sort by the following example. We have an array of 7
Elements.
a[0] 56
12
a[1]
a[2] 25
a[3] 33
a[5] 100
a[6] 70
a[7] 80
There are a number of ways to pick the pivot element. In this example, we will use the first element in
the array as pivot element.
Given a pivot, partition the elements of the array such that the resulting array consists of:
3.1. One sub-array that contains elements >= pivot
3.2. Another sub-array that contains elements < pivot
56 12 25 33 100 70 80
Quick sort starts with 0th element 56. Read the elements from right to left. Compare element with 56
on starting from right to left. Stop at the element which has
less value of that 56. The number is 33, we interchange them. Resulting array look like this
33 12 25 56 100 70 80.
We take 56 as the Pivot element. Because the elements of the array to left are smaller than 56;
elements of the array to right are greater than 56. Here we are dividing the array into two parts, one is
right side of 56, other one is left side of 56.The above procedure is repeated for the two sub arrays,
until we get the sorted array.
Program 4.4
#include<stdio.h>
int main()
{
int array[30],n,i;
printf("\nEnter size of the array :");
scanf("%d",&n);
printf("Enter %d elements : ",n);
for(i=0;i<n;i++) // reading elements
scanf("%d",&array[i]);
Consider an array of 4 integers 7,3,5,4. Now merge sort first divides the array
in to two sub array [7,3], and [5,4].In the next step[ 7,3] and [5,4 ] are divided
in to [7]&[3] and [5]&[4].Now these two are merged back to form[3,7] and[4,5],
which is again merged to form 3,4,5,7. The below figure explains the idea.
Program for Merge sort
Program 4.5
#include<stdio.h>
#define maxsize 50
void merge( int array1[maxsize],int start1,int end1, int end2)
{
//merges two sorted sub arrays array1[start1],..., array1[end1] and
//array1[end1+1]...
// array1[end2] into a single sorted array.
while((index1<=end1)&&(index2<=end2))
if(array1[index1]<array1[index2]) //If an element in the first subarray
// is lesser,move it to the result array
{
result[index3]=array1[index1];
index1++;
index3++;
}
else
{
result[index3]=array1[index2]; //otherwise move the element of
//the second part to the result array
index2++;
index3++;
}
if(index1>end1) //first part is over.
// So copy the second part to the result array
while(index2<=end2)
{
result[index3]=array1[index2];
index2++;
index3++;
}
else //second part is over
while(index1<=end1)
{
result[index3]=array1[index1];
index1++;
index3++;
}
Bucket Sort is another approach based on comparing digits. Bucket sort assumes that the range of
input is known beforehand .It assumes that the input is uniformly distributed over the range. In
this method the range of input is divided in to sub intervals called Buckets and place the input
into these buckets. Then these buckets are sorted and listed in order.
Program for Bucket Sort
Program 4.6
#include <stdio.h>
void bucketSort(int array[],int n);
int main()
{
int array [10] = {1,7,4,6,4,2,8,1,2,9};
int n = 10;
int i;
printf("The array is\n\n");
for (i = 0;i < n;i++)
printf("%d ", array [i]);
printf("\n");
bucketSort(array, n);
printf("The Sorted array is\n\n");
for (i = 0;i < n;i++)
{
printf("%d ", array [i]);
}
printf("\n");
getch();
return 0;
}
for(i=0;i<n;i++)
{
(a[array [i]])++;
}
for(i=0,j=0;i<n;i++)
{
for(;a[i]>0;(a[i])--)
{
array [j++] = i;
}
}
}
We have seen different sorting and searching algorithms. Depending up on the types of data and the
operation one may perform on data, we are choosing different sorting algorithm.
We compare algorithms based on time complexity .The time complexity of algorithm measures the
running time of the algorithm compared to the input data.
Time complexity is represented using the O notation. An algorithm is O(n) if the running time is less
than or equal to a constant times n. Here n is the size of the input. Similarly an algorithm is O (n ) if
2
it’s running time less than or equal to a constant time n , and so on. And O(n) algorithm is considered
2
better than O (nlogn) algorithm, which in turn is consider better than an O(n ) algorithm and so on.
2
4.14 Searching
Searching is the process of determining whether a given element is in a list. A search technique will
give the position of the element if one is found. Otherwise it will say that element is not found.
It is a technique to find out a particular value in a sorted list of items. Binary search is a fast and
efficient searching technique. In binary search we are comparing the elements with the element in the
middle of the list(mid).we are taking the middle element by taking the first and last element of the list
Mid= (beg+last) /2.
A fast way to search a sorted array is to use a binary search. We are going to take the element in the
middle for seaching purpose. If the element we want to search is equal to mid element, the search is
finished. If the element is less than the mid element, we are searching on the first half. If it’s greater,
we are searching at the second half.
Advantage:
Fast and easy to implement.
Disadvantage:
Works only on sorted array.
Program 4.9
Program for Binary search
#include<stdio.h>
void main()
{
int array[10],i,j,t,begin,end,n,middest,num;
printf("Enter the size of the array\n");
scanf("%d",&n);
printf("Enter the elements in sorted order\n");
for(i=0;i<n;i++)
scanf("%d",&array[i]);
begin=0;
end=n;
printf("Enter the element to search\n");
scanf("%d",&num);
while(begin<end)
{
middest=(begin+end)/2;
if(array[middest]==num)
{
printf("Search is success element found at location at %d",
middest);
break;
}
if(num>array[middest])
begin=middest+1;
else
end = middest-1;
}
if(begin==end)
printf("unsuccessful search");
getch();
}
5. We use linear search for a small set of values. But we can use Binary search for a large set of
values.
6. On comparing with binary search technique linear search is a slower one.
7. Binary search is applicable in the case of sorted elements only. But using linear search you
can find out the element from unsorted list. In the case of an unsorted array linear search is the
best one.
Exercises
5.1 Stack
Stack is a data structure which uses the principle of Last in first out (LIFO). In stacks we are
removing the element that we recently added in to the list. The most recently added item is at the top
of the stack. Here insertion and deletion is carried out at one end. Basic stack operations are push and
pop.
Insertion of elements in to the stack is known as PUSH operation and deletion of elements from stack
is known as POP operation. Stack can represented using both an array and a linked list.
Figure 5.1
Different operations on a stack
Push : Places an object on the top of the stack
Pop : Removes an object from the top of the stack
Empty : Reports whether the stack is empty or not.
Program 5.1
#include<stdio.h>
#define Size 4
void pushoperation(); //add item to stack
void popoperation(); //delete item from stack
void showstack(); //to show stack
int stack[Size],Top=-1;
void main()
{
int option;
do
{
printf("Which stack operation you want?\n");
printf("1-PUSH\n2-POP\n3-SHOW\n4.Exit\n");
scanf("%d",&option);
switch(option)
{
case 1:pushoperation();
break;
case 2:popoperation();
break;
case 3:showstack();
break;
}
}while(option<4);
getch();
}
{
int t;
if(Top==-1)
{
printf("Sorry stack is empty");
return;
}
else
{
t=stack[Top];
Top=Top-1;
printf("%d popped from the stack\n",t);
}
{
int i;
if (Top==-1)
printf("Stack is empty ");
else
{
printf("Stack contents are..\n");
for(i=Top;i>=0;i--)
{
printf("%d\n", stack[i]);
}
}
}
Output of the program
Which stack operation you want?
1-PUSH
2-POP
3-SHOW
4.Exit
1
Please enter the element in to the stack
111
Which stack operation you want?
1-PUSH
2-POP
3-SHOW
4.Exit
1
Please enter the element in to the stack
222
Which stack operation you want?
1-PUSH
2-POP
3-SHOW
4.Exit
1
Please enter the element in to the stack
333
Which stack operation you want?
1-PUSH
2-POP
3-SHOW
4.Exit
3
Stack contents are..
333
222
111
Which stack operation you want?
1-PUSH
2-POP
3-SHOW
4.Exit
2
333 popped from the stack
Which stack operation you want?
1-PUSH
2-POP
3-SHOW
4.Exit
3
Stack contents are..
222
111
Which stack operation you want?
1-PUSH
2-POP
3-SHOW
4.Exit
4
Program 5.2
#include<stdio.h>
struct stack
{
int value;
struct stack *link;
};
struct stack *pushoperation(struct stack *top,int val);
struct stack *popoperation(struct stack *top,int *val);
void showstack(struct stack *top);
void main()
{
struct stack *top;
int val,ch;
top=NULL;
do
{
printf("\n Menu for stack operation");
printf("\n 1.Add\n 2.Delete\n 3.Show\n");
printf("\nEnter u r choice\n");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("Enter the element to push in to stack\n");
scanf("%d",&val);
top=pushoperation(top,val);
break;
case 2:
top=popoperation(top,&val);
if(top!=NULL)
printf("the deleted value is %d",val);
break;
case 3:
showstack(top);
break;
}
}while(ch<4);
getch();
}
Stack is a very useful data structure which finds applications in a variety of areas. They include:
Evaluation of arithmetic Expression
An arithmetic expression like A+B-C/2 consists of operators like +,-,*and operand which are
numeric values or variables like a, b , c in order to convert such an expression to instruction
understandable by the computer one has to ,first determine the exact order in which the
operators are evaluated. Each operator is given a priority and the expression is evaluated
using these priorities. In this evaluation we use the stack to store the different operators and
operands.
Recursion:
During recursion a function calls itself. The values of the variables in the calling function are
pushed in to a stack. They are popped out, when the called function returns.
n operating systems when a running process A (also called process) passes control to
another process B the details of the former process A is kept in the stack.
5.4 Queues
A queue is a linear data structure in which addition of new element takes place at one end called
‘rear’. And deletion of existing elements takes place at another end called ‘front’.
A queue is often called as FIRST IN FIRST OUT (FIFO) structure.
Figure 5.2
Program 5.3
#include<stdio.h>
#define size 5 // Size of the queue
int front,rear;
int queue[size];
int i,j;
void show();
void insert(int);
void delete();
void main()
{
int j,i,ch,v;
front=-1;
rear=-1;
do
{
printf("Select the Menu operation\n");
printf("\n1.InsertQueue\n2.DeleteQueue\n3.Show\n4.Quit\n");
printf("Enter your choice\n");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("Enter the value\t");
scanf("%d",&v);
insert(v);
break;
case 2:
delete();
break;
case 3:
show();
break;
}
}while(ch<4);
getch();
}
#include<stdio.h>
struct queue
{
int v1;
struct queue *link;
};
struct queue * addqueue(struct queue *rear,int val);
struct queue * deletequeue(struct queue *front ,int *val);
void showqueue(struct queue *front);
void main()
{
struct queue *front,*rear;
int val,ch;
front=rear=NULL;
do
{
printf("\n Menu for queue operation");
printf("\n 1.Add\n 2.Delete\n 3.Show\n 4.Exit");
printf("\nEnter u r choice\n");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("Enter the value to be added\n");
scanf("%d",&val);
rear=addqueue(rear,val);
if(front==NULL) front=rear;
break;
case 2:
front=deletequeue(front,&val);
if(val!=-1)
printf("The deleted value is %d",val);
if(front==NULL)
rear=front;
break;
case 3:
showqueue(front);
break;
}
}while(ch<4);
getch();
}
struct queue *addqueue(struct queue *rear,int val) //Add item to Queue
{
struct queue *w;
w=(struct queue *)malloc (sizeof(struct queue));
w->v1=val;
w->link=NULL;
if(rear!=NULL)
rear->link=w;
rear=w;
return(rear);
}
struct queue *deletequeue(struct queue *front ,int *val) //Remove item
{
struct queue *w;
if(front==NULL)
{
printf("\n Sorry Queue is empty");
*val=-1;
}
else
{
w=front;
front=front->link;
*val=w->v1;
}
return front;
}
void showqueue(struct queue *front) // Display Queue items
{
struct queue *p;
p=front;
printf("\nThe contents of queue is\n");
while(p!=NULL)
{
printf("%d",p->v1);
p=p->link;
}
}
Figure 5.3
Circular Queue implementation
5.5 Program
#include<stdio.h>
#include<conio.h>
void addcirqueue (int cq [],int*rear,int val,int *front);
int deletecirqueue(int cq [],int *front,int *rear);
void showcirqueue(int cq [],int *front,int *rear);
int n;
void main()
{
int cq [35];
int ch,front,rear,val;
printf("Enter the size of the circular queue\n");
scanf("%d",&n);
front=rear=0;
do
{
printf("\nMenu for circular queue operation");
printf("\n 1.Add\n 2.Delete\n 3.Show\n");
printf("\nEnter u r choice\n");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("Enter the value to be added\n");
scanf("%d",&val);
addcirqueue(cq,&rear,val,&front);
break;
case 2:
val=deletecirqueue(cq,&front,&rear);
if(val!=0)
printf("The deleted value is %d",val);
break;
case 3:
showcirqueue(cq,&front,&rear);
break;
}
}while(ch<4);
getch();
}
void addcirqueue (int cq[],int*rear,int val,int *front)
{
if((*rear+1)%n==*front)
{
printf("Queue is full");
}
else
{
*rear=(*rear+1)%n;
cq[*rear]=val;
}
}
int deletecirqueue(int cq[],int *front,int *rear)
{
int v1;
if(*front!=*rear)
{
*front=(*front+1)%n;
v1=cq[*front];
return v1;
}
else
{
printf("Queue is empty");
return 0;
}
}
void showcirqueue(int cq[],int *front,int *rear)
{
int j;
j=*front;
printf("Contents");
while(j!=*rear)
{
j=(j+1)%n;
printf("\n%d",cq[j]);
}
}
Enter u r choice
1
Enter the value to be added
222
Enter u r choice
1
Enter the value to be added
444
Menu for circular queue operation
1.Add
2.Delete
3.Show
Enter u r choice
3
Contents
222
444
Menu for circular queue operation
1.Add
2.Delete
3.Show
Enter u r choice
2
The deleted value is 222
Menu for circular queue operation
1.Add
2.Delete
3.Show
Enter u r choice
3
Contents
444
Menu for circular queue operation
1.Add
2.Delete
3.Show
Enter u r choice
4
Priority queue is another type of data structure in which each element is having a priority and
elements having same priority form a separate queue. Thus a priority queue is equivalent to a queue of
multiple queues, where elements having higher priority are processed before elements having lower
priority.
Implementation view
Figure 5.5
void main()
{
int option,item1,priority;
headptr=(struct node*)malloc(sizeof(struct node));//a pointer to head node
head =*headptr;
(*headptr).leftlink=NULL;
(*headptr).rightlink=NULL;
(*headptr).data=0;
(*headptr).priority=-99;
do
{
printf("\n 1)Add 2)Delete 3)Show 4)Exit\n");
scanf("%d",&option);
switch(option)
{
case 1:
printf("\nEnter the value to insert:\t");
scanf("%d",&item1);
printf("\nenter the priority:\t");
scanf("%d",&priority);
insert( item1, priority);
break;
case 2:
printf("\nEnter the priority value to delete: ");
scanf("%d",&priority);
item1= delete( priority);
break;
case 3:
show();
break;
}
}
while(option!=4);
getch();
}
void insert(int item ,int p)
{
ptr=headptr;
(*new).data=item;
(*new).priority=p;
while( ((*ptr).priority>p)&&(ptr!=headptr))
{
ptr=(*ptr).leftlink;
}
if((ptr==headptr)||(*ptr).priority<p)
{
printf("no item with that priority");
return(1);
}
else
if((*ptr).priority==p)
{
ptr1=(*ptr).leftlink;
ptr2=(*ptr).rightlink;
if(ptr==rear)
{
rear=ptr1;
(*ptr1).rightlink=NULL;
}
else
{
(*ptr1).rightlink=ptr2;
(*ptr2).leftlink=ptr1;
}
}
}
return((*ptr).data);
}
void show()
{
if((*headptr).rightlink==NULL)
{
printf("the queue is empty");
return;
}
ptr1= (*headptr).rightlink;
while(ptr1!=NULL)
{
printf("DATA: %d Priority %d\n",(*ptr1).data,(*ptr1).priority );
ptr1=(*ptr1).rightlink;
};
}
5.7 Dequeue
Another data structure similar to queue, but operation such as insertion and deletion is made to or
from both end of the queue. But insertion and deletion is not possible at the middle of the queue.
There are two types of dequeue
1. Input restricted dequeue
2. Output restricted dequeue
5.8. Input Restricted Dequeue
This allows insertion only at one end of the array or list, but deletion allowed at both ends.
5.9 Output Restricted Dequeue
This allows insertion at both ends of the list but deletion allowed at only one end of the array.
DEQUEUE
Figure 5.5
Sample program for Dequeue
5.7 Program
#include<stdio.h>
#define maxsize 30
int left,right;
int dequeue[maxsize];
int i,j;
void insertright(int item) // insert element to the right
{
if( ( (left==0)&&(right==(maxsize-1))))
{
printf("queue is full");
return;
}
else if( left==-1)//empty queue
{
left++;
right++;
}
else if(right==maxsize-1)
right=0;
else
right++;
dequeue[right]= item;
}
void show() // Displays the dequeue
{
int front=left;
int rear =right;
if (left== -1)
{
printf("empty queue");
return;
}
if(left <right)
for(i=front;i<=rear;i++)
printf("%d ",dequeue[i]);
else
{
for(i=front;i <=maxsize-1;i++)
printf("%d ",dequeue[i]);
for(i=0;i<=right;i++)
printf("%d ",dequeue[i]);
}
printf("\n");
}
void insertleft(int item) // Insert element to the left
{
if((left==0&&right==(maxsize-1))||(left==right+1))
{
printf("\nq overflow");
return;
}
if(left==-1)
{
left++;
right++;
}
else
{
if(left==0)
left=maxsize-1;
else
left=left-1;
dequeue[left]=item;
}
}
void deleteleft() // Delete element from left
{
if(left==-1)
{
printf("\nqueue underflow");
return;
}
printf("element deleted from q is%d\n",dequeue[left]);
if(left==right)
{
left=-1;
right=-1;
}
else
if(left==maxsize-1)
left=0;
else
left=left+1;
}
void deleteright() //Delete element from right
{
if(left==-1)
{
printf("queue underflow");
return;
}
printf("element deleted from q is%d\n ",dequeue[right]);
if(left==right)
{
left=-1;
right=-1;
}
else
if(right==0)
right=maxsize-1;
else
right=right-1;
}
void main()
{
int j,i,ch,v;
left=-1;
right=-1;
do
{
printf("Select the Menu operation\n");
printf("\n1.InsertRight\n2.InsertLeft\n3.DeleteRight\n");
printf("4.DeleteLeft\n5.Show\n6.Quit\n");
printf("\nEnter your choice\n");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("Enter the value ");
scanf("%d",&v);
insertright(v);
break;
case 2:
printf("Enter the value ");
scanf("%d",&v);
insertleft(v);
break;
case 3:
deleteright();
break;
case 4:
deleteleft();
break;
case 5:
show();
break;
}
}while(ch<6);
getch();
}
Exercises
11.2. Define stack
11.3. Explain push and pop operations in the stack
11.4. Write a c Program to implement a stack using an array
11.5. List out the applications of Stack
11.6. Define Queue
11.7. List Applications of queues
11.8. Write a C program to implement queue using Array
11.9. Implement a circular queue
11.10. What is a priority queue?
11.11. What are dequeues?
11.12. Implement a dequeue
Chapter Vl
Linked List
A linked list is a data structure. Linked list is a linear list of nodes, each containing data area and
one or two pointers (“links”) pointing to the next coming or previous nodes.
Advantage of linked list over array is that we do not need to mention the size of the elements in linked
list application Using linked list we can insert and delete nodes from any point in the list. But linked
list never allow doing random access of nodes.
Several different types of linked list exist: singly-linked lists, doubly-linked lists, circularly-linked
list and circular doubly linked lists. The following fig is an example for single Linked list.
We can insert and delete items in a linked list when it is necessary. The nodes of a linked list
are written as structures. We use some memory location to store the nodes (structure variable).This
location is accessed by means of pointers. The “struct” declaration does not allocate storage, but it
describes the format of the nodes. Storage space of a node is created by the dynamic memory
allocation function malloc.
Here Pnode points to the structure variable node. Initially pointer points to the first node. Creation of
linked list contains the following steps.
11. First we check that pnode1==NULL, if so we dynamically allocate memory for the pnode1
(first node).make pnode’s link as NULL. Assign pnode as the first node.
12. If pnode1! =NULL, then we are allocating memory for the next node (pnode1 link).
2. Insertion at the end section: This is done by adding a new node at the end point of the list.
3. Insertion in specified position: We need to mention the position of insertion. For that we are
searching the entire list and insert the node at the right position.
We are deleting a node from the linked list by mentioning its data .And we are searching the
entire linked list for the data, until we get it. Then we use free function to delete the node.
123
333
444
123
333
444
#include<stdio.h>
struct node1
{
int value;
struct node1 *link;
};
struct node1 *pnode1,*first,*x,*t,*w;
void main()
{
int ch;
void addList();
void deleteList();
void displayList();
pnode1=NULL;
while(ch!=4)
{
printf("\nLinked list operation menu");
printf("\n1.Add\n2.Delete\n3.Display\n4.Exit\n");
printf("Enter u r choice\t");
scanf("%d",&ch);
switch(ch)
{
case 1:
addList();
break;
case 2:
deleteList();
break;
case 3:
displayList();
break;
}
}
getch();
}
222->111->NULL
Linked list operation menu
1.Add
2.Delete
3.Display
4.Exit
Enter u r choice 2
enter the value to delete111
Node Deleted
Linked list operation menu
1.Add
2.Delete
3.Display
4.Exit
Enter u r choice 3
222->NULL
Linked list operation menu
1.Add
2.Delete
3.Display
4.Exit
Enter u r choice 4
Another type of linked list is a doubly-linked list or two-way linked list. Each node has two links:
one points to the previous node, or points to a null value and one points to the next, or points to a null
value .Here a node is divided into three parts, where three fields of information are stored.
Leftlink: Holds the address of previous node.
Data field: Holds the data item.
Right link: Holds the address of the next node.
The following figure for doubly linked list.
Figure 6.4 Doubly linked list
Using a doubly Linked List we can traverse both sides. Main operations of doubly Linked list are
listed below.
3. creation
2. Insertion
3. Deletion
4. Traversal
Here pnode1 (first node) has two links that are rlink and llink. Initially creating the first node in
doubly linked list we are setting the first and last pointers points to that node. Again we are
creating an another node, then last pointer points to the newly created node (t).Insertion and
deletion operations are similar to the linear linked list.
while(temp->no!=val)
{
temp=temp->rlink;
if(temp==NULL)
{
printf("Value not found");
return;
}
}
if(temp->no==val)
{
newnode=(struct dlinklist*) malloc(sizeof(struct dlinklist));
printf("\n Enter the value to insert ");
scanf("%d",&newnode->no);
newnode->rlink=temp->rlink;
temp->rlink=newnode;
newnode->llink=temp;
newnode->rlink->llink=newnode;
}
}
void deleteNode() //Delete element from the list
{
int val;
printf("Enter the value to delete ");
scanf("%d",&val);
if(first->no==val)
{
first=first->rlink;
first->llink=NULL;
}
else
{
temp=first;
while(temp!=NULL&&temp->rlink->no!=val)
temp=temp->rlink;
if(temp==NULL)
{
printf("value not found in the list");
}
temp->rlink=temp->rlink->rlink;
temp->rlink->llink=temp;
}
}
Circular linked list is similar to singly linked list. In the last node of the circular linked list we are
storing the address of the first node. So we can directly go to the first node from last node
Advantage:
Back traversal is possible in circular linked list.
Disadvantage:
In circular linked list there is a probability for an infinite loop.
void main()
{
int option;
int n,value,position,i;
lastnode=NULL;
do
{
printf("1.MakeList\n");
printf("2.Insert First\n");
printf("3.Insert After \n");
printf("4.Delete\n");
printf("5.ShowList\n");
printf("6.Quit\n");
printf("Enter your choice : ");
scanf("%d",&option);
switch(option)
{
case 1:
printf("Enter the number of nodes ");
scanf("%d",&n);
for(i=0; i < n;i++)
{
scanf("%d",&value);
makeList(value);
}
break;
case 2:
printf("Enter the element : ");
scanf("%d",&value);
insertFirst(value);
break;
case 3:
printf("Enter the element : ");
scanf("%d",&value);
printf("Enter the position after which this element is inserted : ");
scanf("%d",&position);
insertAfter(value,position);
break;
case 4:
if(lastnode == NULL)
{
printf("List underflow\n");
continue;
}
printf("Enter the number for deletion : ");
scanf("%d",&value);
deleteNode(value);
break;
case 5:
showList();
break;
}/*End of switch*/
}while(option<6);/*End of while*/
getch();
}/*End of main()*/
if(lastnode == NULL)
{
lastnode = tmp;
tmp->next = lastnode;
}
else
{
tmp->next = lastnode->next; /*added at the end of list*/
lastnode->next = tmp;
lastnode = tmp;
}
}/*End of makeList()*/
}
}
4. Linked lists use dynamic memory allocation. This makes efficient use of main memory.
5. Insertion and deletion of nodes arbitrary positions is easy. For insertion and deletion we need
to just adjust the pointers.
6. We can move both directions using doubly linked list.
7. Linked lists do not require continuous memory blocks for allocation.
8. Linked list can grow and shrink according to user requiements
Disadvantage:
8. We have to mention the proper termination otherwise there is a probability for an infinite
loop.
9. Doubly linked list take additional space to hold the address of the next node and address of
the previous node.
10. Linked list allows only sequential access to elements access time is greater.
EXERCISE
7.1 Tree:
A tree is a finite set of nodes such that there is a special node called the ‘ROOT’ and remaining nodes
are divided in to disjoined sets, where each of the set is a tree.
7.2 ROOT:
Root is a special node .It is the first node or top node in the tree. Every tree
has only one root. In the above figure (7.1) ‘T’ is the root node.
7.3 Degree:
Degree of a node is the number of sub trees of the node, example, t1.t2, t3.Trees with ‘0’ degree is
known as leaf nodes or terminal nodes.
Root of the sub tree of a node is called children of the node. If X is a node, Y is a child of X then X is
called the parent of Y.Nodes having the same parents are called as Siblings. The maximum degree of
nodes of a tree is called the degree of the tree. A path among two nodes X and Y of a tree is list of
nodes starting from X and ending in Y with no node repeating.
7.4 Pathlengh
The number edges on a path are called the length of the path. it is one less than the number of nodes in
the path.
7.5 Level
A set of trees which are disjoint (Having no common nodes) is called as forest.
For example: If we take the tree in the above example and delete the root node, we get a forest
consisting of three disjoint trees.
Forest
A
E
F
B
C
D
F
G
H
B
C
D
F
E
G
H
A binary tree can be defined as tree in which every node has degree at most ‘two’. That is a tree is a
binary tree if every node has ‘Zero’, ‘One’ or ’Two’ children. The two sub trees of a binary tree are
called left sub tree and right sub tree.
• Decision trees : when taking a decision we will have to consider several alternative and the
decision is based on various condition this can be formulated as a tree
If it rains or if it hot I will stay onside, else I will go out.
• Representing sets: In a set element can be represented by nodes and disjoint sub sets can be
represented by sub trees. This representation makes operation like union very convenient.
• Oct trees and quad trees are used in computer graphics where a picture or a solid object is
divided in to different parts, and each part is further divided, forming a tree representation of the
picture or object. This representation saves much space and also is convenient for manipulating
picture and objects.
2. Deleting a node
In deletion there are three cases
2. The node to be deleted is a leaf node.
In this case in the parent of the node, the pointer to the node is made Null and the node is freed.
Consider a tree having sub trees on both sides; here we are going to delete the node 25, for that
we need to find out the inorder successor of the node 25.We get the Inorder successor by
traversing the tree in inorder. Tree visited in sequence 20, 25,30,40,45,120,125,140,150. From
sequence we found that 30 come after 25. After deletion tree looks like fig(7.5).
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
struct BinaryTree
{
int n;
struct BinaryTree *left;
struct BinaryTree *right;
}typedef BinaryTree;
BinaryTree *root,*ptr,*prev,*bfor,*x,*y;
int num;
void main()
{
int ch;
void createNewTree();
void displayTree(BinaryTree *);
void searchTree(BinaryTree *);
void insertTree(BinaryTree *);
void deleteTree(BinaryTree *);
do
{
printf("\n1.CREATENEW\n2.PRINT\n3.SEARCH\n4.INSERT\n5.DELETE\n6.EXIT");
printf("\nEnter your choice\t");
scanf("%d",&ch);
switch(ch)
{
case 1 :
{
createNewTree();
break;
}
case 2 :
{
displayTree(root);
break;
}
case 3 :
{
searchTree(root);
break;
}
case 4 :
{
insertTree(root);
break;
}
case 5 :
{
deleteTree(root);
break;
}
}
}while(ch<6);
getch();
}
while(ptr)
{
if(ptr->n == num)
{
printf("Search Successfull...");
return;
}
else
if(ptr->n<num)
ptr=ptr->right;
else
ptr=ptr->left;
}
printf("Search UnSuccessfull...");
}
do
{
if(num<ptr->n)
{
prev=ptr;
ptr=ptr->left;
}
else if(num > ptr->n)
{
prev=ptr;
ptr=ptr->right;
}
else
{
prev=NULL;
break;
}
}while(ptr);
if(prev)
{
temp=(BinaryTree *)malloc(sizeof(BinaryTree ));
temp->n=num;
temp->left=temp->right=NULL;
if(temp->n <prev->n)
prev->left=temp;
if(temp->n > prev->n)
prev->right=temp;
printf("'%d' is inserted...",num);
}
else
printf("'%d' is already present...",num);
return;
}
void deleteTree(BinaryTree *ptr) // Deletes a particular element
{
if(!ptr)
{
if(ptr == root)
{
printf("Empty Tree");
return;
}
}
printf("Enter the number to be deleted : ");
scanf("%d",&num);
prev=ptr;
while(ptr)
{
if(ptr->n == num)
{
if(ptr==root)
{
x=ptr->right;
root=x;
while(x->left)
x=x->left;
x->left=ptr->left;
free(ptr);
printf("'%d' is deleted...",num);
return;
}
else if(!(ptr->left) && !(ptr->right))
{
if(prev->left == ptr)
prev->left=NULL;
else
prev->right=NULL;
free(ptr);
printf("'%d' is deleted...",num);
return;
}
else if(!(ptr->left))
{
if(prev->left == ptr)
{
prev->left=ptr->right;
free(ptr);
}
else if(prev->right == ptr)
{
prev->right=ptr->right;
free(ptr);
}
printf("'%d' is deleted...",num);
return;
}
else if(!(ptr->right))
{
if(prev->left == ptr)
{
prev->left=ptr->left;
free(ptr);
}
else if(prev->right == ptr)
{
prev->right=ptr->left;
free(ptr);
}
printf("'%d' is deleted...",num);
return;
}
else
{
x=ptr->right;
while(x->left)
x=x->left;
x->left=ptr->left;
if(prev->left == ptr)
prev->left=ptr->right;
else if(prev->right == ptr)
prev->right=ptr->right;
free(ptr);
printf("'%d' is deleted...",num);
return;
}
}
else if(ptr->n <num)
{
prev=ptr;
ptr=ptr->right;
}
else
{
prev=ptr;
ptr=ptr->left;
}
}
printf("No Such Element Found..");
}
1.CREATENEW
2.PRINT
3.SEARCH
4.INSERT
5.DELETE
6.EXIT
Enter your choice 1
Enter the number of nodes 3
Enter the number 50
Enter the number 40
Enter the number 60
1.CREATENEW
2.PRINT
3.SEARCH
4.INSERT
5.DELETE
6.EXIT
Enter your choice 2
Root is '50'
Elements are .... 50 40 60
1.CREATENEW
2.PRINT
3.SEARCH
4.INSERT
5.DELETE
6.EXIT
Enter your choice 4
Enter number to be inserted : 70
'70' is inserted...
1.CREATENEW
2.PRINT
3.SEARCH
4.INSERT
5.DELETE
6.EXIT
Enter your choice 2
Root is '50'
Elements are .... 50 40 60 70
1.CREATENEW
2.PRINT
3.SEARCH
4.INSERT
5.DELETE
6.EXIT
Enter your choice 3
Enter the number to search : 70
Search Successfull...
1.CREATENEW
2.PRINT
3.SEARCH
4.INSERT
5.DELETE
6.EXIT
Enter your choice 5
Enter the number to be deleted : 60
'60' is deleted...
1.CREATENEW
2.PRINT
3.SEARCH
4.INSERT
5.DELETE
6.EXIT
Enter your choice 2
Root is '50'
Elements are .... 50 40 70
1.CREATENEW
2.PRINT
3.SEARCH
4.INSERT
5.DELETE
6.EXIT
Enter your choice 6
3. Inorder traversal
Traverse the left subtree in Inorder, visit the root and traverse the right sub tree in Inorder.
2. Pre order traversal
Visit the root node, traverse the left sub tree in pre order, and traverse the right sub tree in pre
order.
3. Post order traversal
Traverse the left sub tree in post order, traverse the right sub tree in post order, and visit the
root.
We can explain the tree traversal with the following example.
Figure 7.8
Inorder traversal 20, 25, 30, 40, 45, 120, 125, 140,150
Pre-order traversal 120, 45, 25, 20, 40, 30, 140, 125, 150
Post-order traversal 20, 30, 40, 25, 45, 125, 150, 140, 120
Program 7.1
#include<stdio.h>
struct treenode1
{
struct treenode1 *left;
char data;
struct treenode1 *right;
};
typedef struct treenode1 tree;
tree *root=NULL;
void inserttree();
void inorder(tree*);
void postorder(tree*);
void preorder(tree*);
int number,no;
void main()
{
int i,option;
printf("\n\tTree Operation-Menu\n");
printf("\n1.InsertNode\n2.Inorder\n3.Preorder\n4.Ppostorder\n5.Exit\n");
do
{
printf("\nEnter your operation\t");
scanf("%d",&option);
switch(option)
{
case 1:
inserttree();
break;
case 2:
printf("\nIn order traversal\n");
inorder(root);
break;
case 3:
printf("\nPre order traversal\n");
preorder(root);
break;
case 4:
printf("\nPost order traversal\n");
postorder(root);
break;
}
}while(option<5);
getch();
}
void inserttree() // Insert nodes to tree
{
tree *t,*p,*q;
printf("Enter a number\t");
scanf("%d",&number);
q=(tree*)malloc(sizeof(tree));
q->data=number;
q->left=NULL;
q->right=NULL;
if(root==NULL)
{
root=q;
return;
}
p=root;
t=NULL;
while(p!=NULL)
{
t=p;
if(p->data>number)
p=p->left;
else
p=p->right;
}
if(t->data>number)
t->left=q;
else
t->right=q;
}
void inorder(tree *p)
{
if(p!=NULL)
{
inorder(p->left);
printf("%d ",p->data);
inorder(p->right);
}
}
void preorder(tree *p)
{
if(p!=NULL)
{
printf("%d ",p->data);
preorder(p->left);
preorder(p->right);
}
}
void postorder(tree *p)
{
if(p!=NULL)
{
postorder(p->left);
postorder(p->right);
printf("%d ",p->data);
}
}
Tree Operation-Menu
1.InsertNode
2.Inorder
3.Preorder
4.Ppostorder
5.Exit
Enter your operation 1
Enter a number 50
Enter your operation 1
Enter a number 90
Enter your operation 1
Enter a number 80
Enter your operation 1
Enter a number 40
Enter your operation 1
Enter a number 30
Enter your operation 2
In order traversal
30 40 50 80 90
Enter your operation 3
Pre order traversal
50 40 30 90 80
Enter your operation 4
Post order traversal
30 40 80 90 50
Enter your operation 5
Threaded binary tree can be used in tree traversal. If we use a threaded binary tree we can avoid
recursion and the use of stacks. This saves a lot of memory and is much faster than recursive
methods.
Exercises
3. What is tree?
4. Define sub tree.
5. Define root node and leaf node.
6. Define degree and level of a tree.
7. Explain the terms forest and labeled tree.
8. Explain the Application of trees.
9. What is a binary tree? Discuss the binary tree operation.
10. Discuss the different tree traversal methods.
11. What is binary search tree?
12. What is threaded binary tree?
11. Write a C program to implement the binary tree operations.
12. Write a c program to implement tree traversal.
13. Discuss the use of threaded binary tree.
Chapter Vlll
GRAPH
8.1 Graph
Graph is also a nonlinear data structure which has application in many areas like networking,
geographical information systems, traffic planning’s, project management and chemistry.
8.2 Definition
A graph G consists of a set of V of vertices and a set E of edges between the vertices. It can be
represented as G= (V, E). Where V is a finate set of vertices and E is a set of pairs of vertices called
edges.
If( x, y) is an edge in a directed graph we say that xis adjacent to y. and y is adjacent from x.In
the case of a undirected graph if (x,y ) is an edge, we say that x and y are adjacent. In the above
example in figure (8.3), vertex a is adjacent to vertex c and vertex c is adjacent from a. In figure (8.4)
vertices a and c are adjacent to each other.
A subgraph of a graph G=(V,E) is a graph G’ =(V’,E’) such that the vertex set V’ of G’ is a
subset of the vertex set V of G,and the set of edges E’of G’ is a subset of the set of edges E of G.
A path from a vertex x to a vertex y in a graph G is a sequence of vertices.
x =v0 ,v1,…,vr=y such that all vertices except possibly the first and last are distinct and (v0,v1),
(v1,v2),…,(vr-1,vr) are edges in G.The number of edges in a path is called Length of a path. A cycle is
a path with first and last matrix is same.
An undirected graph is said to be connected if there is a path between every two distinct vertices.
Other wise it called as disconnected.
Representation of a Graph
A graph can be represented in many ways, but the most used methods are given
below:
1. Adjacency matrix representation
2. Adjacency list representation
Here a graph with n vertices {v1,v2,…,vn} is represented by an nxn matrix A. This matrix is
called the adjacency matrix of the graph. In this matrix, the i,j th entry A[i,j] is 1 if there is an
edge from vertex i to vertex j. Otherwise it is ‘0’.
Example:
Figure 8.5 Directed graph Figure 8.6 Adjacency Matrix
Given an undirected graph G and a vertex x, we may want to visit all vertices in G which are
reachable from x in a systematic fashion. There are many methods to do this. Two of the most popular
methods are listed below:
13. Depth First Search (DFS).
14. Breadth First Search (BFS).
In DFS we are going to visit the vertices in depth wise fashion. Starting from a vertex we are going to
visit one of its neighbors, and then one of its neighbors and so on until the current vertex has no
unvisited neighbors. Then we backtrack and continue visiting the next neighbor of the earlier vertex.
Figure (8.13) shows the DFS spanning tree for the tree given in figure (8.11).
In breadth first search we visit the vertices in a breadth wise fashion. Here first of all we start from a
vertex, then visit all its neighbors, and then visit the neighbors of the neighbors and so on. Queue data
structure is used here. Figure (8.12) shows the BFS spanning tree for the tree given in figure (8.11).
Figure 8.13
In the figures above an undirected graph is visited starting from vertex 1. The DFS and BFS generate
trees called the DFS tree and BFS tree respectively. These trees contain all the vertices of the graph
G and are spanning trees.
BFS algorithm
Input : A graph G and a source vertex s of G
Output: A BFS Tree of the graph
14. Create a queue Q
15. Add s to Q
16. mark s
17. make s as the root of the tree T
5. while Q is not empty:
6. Remove a vertex v from Q
7. for each edge (v ,w) of G
8. if w is not marked:
9. mark w,
10. Make v the parent of w in T
11. add w to Q
12. end if
13. end while
14. Return T
15. STOP
Applications of BFS
Breadth first search has many applications. Some of them are given below.
1 .Identifying connected components of a graph.
BFS can be used to find all connected components in a graph. By starting from an arbitrary vertex BFS ends when all the vertices which
are connected to that vertex is explored. Then start ing from a remaining vertex we get the next connected component.In this way we
can find all the connected components.
3.Finding the shortest path from one vertex to all other vertices.
A BFS starting from a single vertex gives a tree in which the path from the root to any other vertex is
a shortest path.
DFS algorithm
BFS algorithm
Input : A graph G and a source vertex s of G
Output: A DFS Tree of the graph
15. Create a Stack R
16. Push s to R
17. mark s
18. make s as the root of the tree T
Applications
DFS have a wide variety of applications.Some of them are given below.
15. .Finding the connected components of a graph.
16. In game playing
17. Solving mazes
18. Checking weather a given graph is planar (Weather it can be drawn on the pane without
edges crossing)
5.Topological sorting.
Notice That The only difference between DFS and BFS is that we use a Stack in DFS instead of a
queue in BFS.
A shortest path from a vertex x to y in a graph G is a path from x to y having minimum number of
edges .The length of any shortest path from x to y is the distance from x to y, and is denoted by
d(x,y)..In an undirected graph d(x, y) and d(y, x) are same.
8.9 Weighed graph
A directed graph in which weights are assigned on edges is called a weighted graph.
Figure 8.14
A weighed graph may be used to represent many real life problems. For example a weighed graph
may represent a road net work. Here vertices may represent cities; edges may represent roads
between the cities. Weights indicating the cost of moving from one city to another city.
A shortest path from a vertex x to a vertex y is a path from x to y B such that the sum of the weights of
the edges in the path is minimum.
Dijkstra algorithm is used to find the shortest path and the costs of the paths from
a given vertex x to all other vertices in a weighed graph G.
Here we assume that all the costs are non-negative. Dijkstra’s Algorithm works by keeping a set of
vertices whose distance from x is already determined. The algorithm proceeds by selecting a vertex v
not in S, whose distance from all vertices of S is minimum. The time complexity of the algorithm is O
(n ), where n is the number of vertices.
2
Program 8.1
#include <stdio.h>
int distanceMatrix[20][20]; // To store the distance matrix
int shortestPath[20]; // To store the shortest paths
int findMax(int a, int b) // Find maximum of two numbers
{
if(a>b)
return a;
else
return b;
}
void printPath(int sv,int n)// displays the shortest paths
{
int i;
printf("From To ShortestPath\n\n");
for (i = 1; i <= n; ++i)
{
printf("%d %d %ld\n",sv,i,shortestPath[i]);
}
printf("\n");
}
void findPath(int sv,int n) //Find the shortest paths using Dijkstra's algorithm
{
int i,j,minimum;
int checked[20];
for (i = 1; i <= n; ++i)
{
shortestPath[i] = 9999;
checked[i] = 0; // Setting all vertices as unvisited
}
shortestPath[sv] = 0;
int main()
{
int i,j,from,to,distance;
int n;
int n_of_edges;
int sourceVertex;
printf("Enter the number of edges\t");
scanf("%d", &n_of_edges);
for (i = 0; i < n_of_edges; ++i)
for (j = 0; j < n_of_edges; ++j)
distanceMatrix[i][j] = 0;
n = -1;
printf("Enter the edges in the order from--to--distance\n");
for (i = 0; i < n_of_edges; ++i)
{
scanf("%d%d%d", &from, &to, &distance);
distanceMatrix[from][to] = distance;
n = findMax(from, findMax(to, n));
}
110
128
139
145
157
Warshalls algorithm (Floyd warshall Algorithm) For finding all pairs of shortest paths.
In a weighted directed graph, Floyd warshall algorithm can be used to find all pairs of shortest paths
(distances between any pair of points)
The algorithm is given below
Algorithm
Input: The adjacency matrix of a directed weighted graph.
Output: a matrix d representing the shortest distances
9. for k = 0 to n-1
10. for i = 0 to n-1
11. for j = 0 to n-1
12. d[i][j] = min ( d[i][j], d[i][k]+d[k][j] )
13. STOP
The complexity of the algorithm is O(n3),Where n is the number of vertices of the graph.
Exercises
13. Define graph.
14. Explain Direct and undirected graph.
15. How can we represent graphs?
16. Define sub graph.
17. Define path.
18. Explain Adjacency matrix with an example.
19. Explain Adjacency list with an example.
20. Explain DFS and BFS.
21. What is shortest path?
22. What is weighted graph?
23. Explain and Implement Dijkstra algorithm.
Exercises
12. Define graph.
13. Explain Direct and undirected graph.
14. How can we represent graphs?
15. Define sub graph.
16. Define path.
17. Explain Adjacency matrix with an example.
18. Explain Adjacency list with an example.
19. Explain DFS and BFS.
20. What is shortest path?
21. What is weighted graph?
22. Explain and Implement Dijkstra algorithm.