Data Structures in C: Comprehensive Guide
Data Structures in C: Comprehensive Guide
 ity
 Structure:
 rs
 1.1.2 Algorithm Design
 1.1.3 Complexity, Time-Space Tradeoffs
 1.1.4 Use of pointers in data structures
 ve
 Unit-1.2: Arrays
 1.2.1 Array Definition and Analysis
 1.2.2 Representation of Linear Arrays in Memory
 1.2.3 Traversing of Linear Arrays
 ni
 1.2.4 Insertion and Deletion
 1.2.5 Single Dimensional Arrays
 1.2.6 Two Dimensional Arrays
 1.2.7 Multidimensional Arrays
 U
 1.2.8 Function Associated with Arrays
 Unit-1.3: Strings
 1.3.1 Character String in C
 ity
 ity
 1.1.1 Definition and Types of Data structure
 Data structure is a representation of data and the operations allowed on that
 data. A data structure is a way to store and organize data to facilitate the access and
 modifications. The data structure name indicates itself that organizing the data in
 memory. There are many ways of organizing the data in the memory. Data Structure
 rs
 are the method of representing of logical relationships between individual data elements
 related to the solution of a given problem. To structure the data in memory, ‘n’ number
 of algorithms were used, and all these algorithms are known as Abstract data types.
 ve
 access and modification. Here are several basic and advanced structure types.
 ni
 The structure should be simple enough that one can effectively process the
 data when necessary.
 Data Structure
 U
 Linear data Non-linear data
 Structure Structure
 Linked
 Array Stack Queue Graphs Trees
 ity
list
 There are two types of data structures: The primitive data structures are primitive
 data types. The int, char, float, double, and pointer are the primitive data structures
 m
 that can hold a single value. The non-primitive data structure is divided into two types:
 Linear data structure & Non-linear data structure.
 Other than linear and non-linear there are below more types of data structures
 available.
 )A
 Static or dynamic data structures: This type tells how the data structures are
 compiled. Static data structures have fixed sizes and Dynamic data structures have
 flexible size. In Static data structure, the content of the data structure can be modified
 but without changing the memory space allocated to it. Dynamic data structure can be
 modified during the operations performed on it. Dynamic data structures are designed Notes
 ity
 to facilitate change of data structures in the run time.
 Linear Data Structures: In Linear data structure, values are arranged in linear
 fashion. The data structures used for this purpose are Arrays, Linked list, Stacks,
 and Queues. In these data structures, one element is connected to only one another
 element in a linear form.
 rs
 ●● Array: A collection of items when we store at adjoining memory locations
 is called an Array. Same type of elements gets stored together so that the
 position of each element can be calculated or retrieved easily. Arrays can be
 of fixed or flexible length. It is a finite group of data and is allocated contiguous
 memory locations. To access an element within the array can be accessed by
 ve
 an index key.
 Example: The syntax for storing and displaying the values in an array typically
 looks something like this:
arrayname[0] = “This “;
arrayname[1] = “is “;
 print arrayname[0];
 ni
 U
 print arrayname[1];
print arrayname[2];
 The above commands would print the first three values of the array, or “This is
 pretty simple.” By using a “while” or “for” loop, the programmer can tell the program
 ity
 to output each value in the array until the last value has been reached. So not only do
 arrays help manage memory more efficiently, they make the programmer’s job more
 efficient as well.
 Element
 First index (at index 8)
 m
0 1 2 3 4 5 6 7 8 9 Indices
 Array length is 10
 )A
An array of 10 elements
 particular order in which the operations are applied is called stack. This order
 could be last in first out (LIFO) or first in first out (FIFO). In LIFO, elements are
 added to top and removed from top.
Notes
 ity
 3
 1 3
 2 2 2
 1 1 1
 rs
 stack
 ve
 middle or end of linked list. Linked list contains data elements along with its
 pointer which points to the next data element. In this case memory locations
 are not contiguous. In linked list
 Linked List contains a link called first. Each link carries a data field and a link field.
 Link field is called next. Each link is linked with its next link using its next link. Last
 ni
 link carries a link as null to mark the end of the list. The various types of linked list are
 Simple Linked List, Doubly Linked List, Circular Linked List.
 U
 Data
 Pointer to the
 Head next node
 A Node
 5 7 2 15
 ity
Notes
 ity
 Back Front
 Dequeue
 Enqueue
 rs
 Fig 1.5: Queue
 ve
 Non-Linear Data Structures: The data values in this structure are not arranged in
 order.
 ●● Hash tables: Hash tables, also known as hash map, stores a collection of
 data in an associative manner. Array items are associated with keys. Items
 are in (key, value) format. It is an unordered list which use a ‘hash function’ to
 ●●
 ●●
 insert and search.
 Tree: Data is organized in branches.
 ni
 Graph: A more general branching structure, with less strict connection
 conditions than for a tree
 U
 Liner Vs. Non Linear Data Structure:
 6. Its examples are: array, stack, queue, While its examples are: trees and
 linked list, etc. graphs.
 ity
 Algorithm is a step-by-step procedure, which defines a set of instructions to be
 executed in a certain order to get the desired output. Algorithms are generally created
 independent of underlying languages, i.e., an algorithm can be implemented in more
 than one programming language.
 Characteristics of an Algorithm
 rs
 Not all procedures can be called an algorithm. An algorithm should have the
 following characteristics −
 ve
 ●● Input − An algorithm should have 0 or more well-defined inputs.
 ●● Output − An algorithm should have 1 or more well-defined outputs and should
 match the desired output.
 ●● Finiteness − Algorithms must terminate after a finite number of steps.
 ●●
 ●●
 ni
 Feasibility − Should be feasible with the available resources.
 Independent − An algorithm should have step-by-step directions, which should
 be independent of any programming code.
 U
 1.1.3 Complexity, Time-Space Tradeoffs
 Algorithm Analysis
 Analysis, we evaluate the performance of an algorithm in terms of input size (we don’t
 measure the actual running time). We calculate, how the time (or space) taken by an
 algorithm increases with the input size. For example, let us consider the search problem
 (searching a given item) in a sorted array. One way to search is Linear Search (order of
 growth is linear) and the other way is Binary Search (order of growth is logarithmic).
 m
 which means that A is 5000 times more powerful than B. For small values of input array
 size n, the fast computer may take less time. But, after a certain value of input array
 size, the Binary Search will definitely start taking less time compared to the Linear
 Search even though the Binary Search is being run on a slow machine. The reason is
 the order of growth of Binary Search with respect to input size is logarithmic while the
 order of growth of Linear Search is linear. So the machine dependent constants can
(c
 ity
 ●● Identify unknown quantities that can be used to describe the frequency of
 execution of the basic operations.
 ●● Develop a realistic model for the input to the program.
 ●● Analyze the unknown quantities, assuming the modelled input.
 ●● Calculate the total running time by multiplying the time by the frequency for
 rs
 each operation, then adding all the products.
 ●● A Priori Analysis − This is a theoretical analysis of an algorithm. Efficiency
 of an algorithm is measured by assuming that all other factors, for example,
 processor speed, are constant and have no effect on the implementation.
 ve
 ●● A Posterior Analysis − This is an empirical analysis of an algorithm. The
 selected algorithm is implemented using programming language. This is then
 executed on target computer machine. In this analysis, actual statistics like
 running time and space required, are collected.
Algorithm Complexity
 ni
 Suppose X is an algorithm and n is the size of input data, the time and space
 used by the algorithm X are the two main factors, which decide the efficiency of X.
 Space Complexity
 ity
 ●● A fixed part that is a space required to store certain data and variables, that
 are independent of the size of the problem. For example, simple variables and
 constants used, program size, etc.
 m
 Time Complexity
 Time Complexity of an algorithm is the representation of the amount of time
 required by the algorithm to execute to completion. Time requirements can be denoted
 or defined as a numerical function t(N), where t(N) can be measured as the number of
 steps, provided each step takes constant time.
 For example, in case of addition of two n-bit integers, N steps are taken.
(c
 Consequently, the total computational time is t(N) = c*n, where c is the time consumed
 for addition of two bits. Here, we observe that t(N) grows linearly as input size
 increases.
 In divide and conquer approach, a problem is divided into smaller problems, then
 Notes the smaller problems are solved independently, and finally the solutions of smaller
 ity
 problems are combined into a solution for the large problem.
 ●● Divide the problem into a number of sub-problems that are smaller instances
 of the same problem.
 ●● Conquer the sub-problems by solving them recursively. If they are small
 rs
 enough, solve the sub-problems as base cases.
 ●● Combine the solutions to the sub-problems into the solution for the original
 problem.
 ●● Divide and conquer approach supports parallelism as sub-problems are
 ve
 independent. Hence, an algorithm, which is designed using this technique,
 can run on the multiprocessor system or in different machines simultaneously.
 ●● In this approach, most of the algorithms are designed using recursion, hence
 memory management is very high. For recursive function stack is used, where
 function state needs to be stored.
conquer approach.
 ●●
 ni
 Following are some problems, which are solved using divide and
 The Max-Min Problem in algorithm analysis is finding the maximum and minimum
 value in an array.
 Solution
 To find the maximum and minimum numbers in a given array numbers[] of size n,
 the following algorithm can be used. First we are representing the naive method and
 m
 the pointer is something like a variable that holds that memory address of the variable.
 One can easily find the page using the location referred to there. Such pointers usage
 helps in the dynamic implementation of various data structures such as stack or list.
 Optimization of our code and improving the time complexity of one algorithm. Since
 using pointers helps to reduce the time needed by an algorithm to copy data from one
 place to another. Since it used the memory locations directly, any change made to the
(c
 Like we have pointers to int, char and other data-types, we also have pointers
 pointing to structures. These pointers are called structure pointers.
 ity
 struct structure_name
data-type member-1;
data-type member-1;
 rs
 data-type member-1;
data-type member-1;
};
 ve
 int main()
 ni
 U
 ity
 m
 )A
(c
 Unit-1.2: Arrays
 Notes
 ity
 1.2.1 Array Definition and Analysis
 An array is a collection of items stored at contiguous memory locations. The idea is
 to store multiple items of the same type together. This makes it easier to calculate the
 position of each element by simply adding an offset to a base value, i.e., the memory
 location of the first element of the array (generally denoted by the name of the array).
 rs
 Memory Location
 200 201 202 203 204 205 206 ▪ ▪ ▪
 U B F D A E C ▪ ▪ ▪
 ve
 0 1 2 3 4 5 6 ▪ ▪ ▪
Index
 ni
 1.2.2 Representation of Linear Arrays in Memory
 A linear array is a list of finite numbers of elements stored in the memory. In a
 linear array, we can store only homogeneous data elements. Elements of the array
 form a sequence or linear list, that can have the same type of data.
 U
 Each element of the array is referred by an index set. The total number of
 elements in the array list, is the length of an array. We can access these elements with
 the help of the index set. For example, consider an array of employee names with the
 index set from 0 to 7, which contains 8 elements as shown in fig:
 ity
0 1 2 3 4 5 6 7
 Now, if we want to retrieve the name ‘Alex’ from the given array, we can do so by
 m
 calling “employees [3]”. It gives the element stored in that location, that is ‘Alex’, and so
 on.
 We can calculate the length, or a total number of elements, of a linear array (LA),
 by the given formula:
 )A
Length (LA)=UB-LB+1
 Here, UB refers to the upper bound, the largest index set of the given array list.
 LB refers to the lower bound, smallest index set of the given array list.
 For example, we have an array of employees, in which lower bound is 153 and
 the upper bound is 234, so we can calculate the total number of elements in the list, by
(c
234-153+1=82
 ity
 We can process each element of an array with the help of an index set. The array
 elements are stored in contiguous (i.e. one after the other) memory locations. All the
 array elements must be of one particular data types like either int or, float or, char or,
 double etc. or they can be of any user-defined data types like structures and unions.
 Example:
 rs
 /*Array traversal*/
#include <stdio.h>
int main()
 ve
 int arr[5],i;
for(i=0;i<5;i++){
scanf(“%d”,&arr[i]);
 printf(“\n”); ni
 U
 }
for(i=0;i<5;i++){
return 0;
 }
 Output:
 m
arr[0] = 10
 arr[0] = 20
 )A
arr[0] = 30
arr[0] = 40
arr[0] = 50
 Array insertion, of an element at the end of the list, is quite simple. We can do
 so by providing the unallocated space to the new element. On the other hand, if we
 need to insert an element in the middle of an array, lots of internal shifting is required to
 Notes insert the new element. i.e., half of the elements must be moved downward, to the new
 ity
 location, to enter the new element.
 Similarly, deletion of the element from the end of the array, is quite simple. But, if
 we need to delete an element from the middle of the array, then on average, half of the
 elements must be moved upward, to fill the blank space, after deleting the element from
 the specified location.
 rs
 1.2.5 Single Dimensional Arrays
 An array is a collection of elements of one specific type in a horizontal fashion.
 The array in contention here is that of the one-dimensional array in C programming.
 ve
 Anything having one-dimension means that there is only one parameter to deal
 with. In regular terms, it is the length of something. Similarly, as far as an array is
 concerned, one dimension means it has only one value per location or index.
 As you can see in the example given above, firstly, you need to declare the
 elements that you want to be in the specified array. Secondly, the location of each
 ity
 element needs to particularize as well, since that is where the elements will be stored
 respectively.
data_type array_name[array_size];
 Here is the general form to initialize values to one dimensional array in C: data_
 m
Example:
#include<stdio.h>
int main()
int i;
 return 0;
 Notes
 ity
 }
Output:
 rs
 Elements of One dimensional array is: 3
 ve
 1.2.6 Two Dimensional Arrays
 An array keeps track of multiple pieces of information in linear order, a one-
 dimensional list. However, the data associated with certain systems (a digital image,
 a board game, etc.) lives in two dimensions. To visualize this data, we need a multi-
 dimensional data structure, that is, a multi-dimensional array. A two-dimensional array
 ni
 is really nothing more than an array of arrays (a three-dimensional array is an array
 of arrays of arrays). Think of your dinner. You could have a one-dimensional list of
 everything you eat: (lettuce, tomatoes, steak, mashed potatoes, cake, ice cream) Or
 you could have a two-dimensional list of three courses, each containing two things you
 U
 eat: (lettuce, tomatoes) and (steak, mashed potatoes) and (cake, ice cream)
 In the case of an array, our old-fashioned one-dimensional array looks like this: int[]
 myArray = {0,1,2,3};
{3, 2, 1, 0},
 {3, 5, 6, 1},
 )A
 {3, 8, 3, 4} };
 Example:
#include<stdio.h>
 int main(){
(c
int a=0,b=0;
int arr[4][3]={{1,2,3},{2,3,4},{3,4,5},{4,5,6}};
//traversing 2D array
 for(a=0;a<4;a++){
 Notes
 ity
 for(b=0;b<3;b++){
}j
 rs
 return 0;
 }
 Output:
arr[0] [0] = 1
 ve
 arr[0] [1] = 2
arr[0] [2] = 3
arr[1] [0] = 2
arr[1] [1] = 3
arr[1] [2] = 4
 arr[2] [0] = 3
 ni
 U
 arr[2] [1] = 4
arr[2] [2] = 5
arr[3] [0] = 4
 arr[3] [1] = 5
 ity
arr[3] [2] = 6
 multidimensional arrays. For example, x is a two-dimensional (2d) array. The array can
 hold 12 elements. You can think the array as a table with 3 rows and each row has 4
 columns.
 ity
 to represent dimensions 3 and higher.
 Example:
/*Multi-dimensional array*/
#include<stdio.h>
 rs
 int main()
int a, b, c;
 ve
 int arr[3][3][3]=
{1, 2, 3},
 },
 {4, 5, 6},
 {7, 8, 9}
 ni
 U
 {
},
	},
 )A
};
for(a=0;a<3;a++)
	for(b=0;b<3;b++)
(c
for(c=0;c<3;c++)
 {
 Notes
 ity
 printf(“%d\t”,arr[a][b][c]);
printf(“\n”);
 rs
	printf(“\n”);
return 0;
 ve
 }
 Output:
3D Array Elements:
1 2 3
 7
 5
 8
 6
 9
 ni
 U
 11 12 13
14 15 16
 17 18 19
 ity
21 22 23
24 25 26
 27 28 29
 m
 does not limit the number of dimensions in an Array. Traversing, searching, insertion,
 deletion, sorting are different functions associated with array.
 In an Array, the search operation is used to find a particular data item or element in.
 We can perform searching in an unsorted array with the help of traversal of the Array. Notes
 ity
 The linear traversal from the first element to the last element can be used to search if a
 given number is present in an Array and can also be used to find its position if present.
 rs
 #include <stdio.h>
int main()
 ve
 int arr[MAX_SIZE];
int size;
int i, j, temp;
scanf(“%d”, &arr[i]);
temp = arr[i];
 arr[i] = arr[j];
 Notes
 ity
 arr[j] = temp;
 rs
 /* Print the sorted array */
 ve
 for(i=0; i<size; i++)
printf(“%d\t”, arr[i]);
 }
 return 0;
 Output:
 ni
 U
 Enter size of array: 5
 Unit-1.3: Strings
 Notes
 ity
 1.3.1 Character String in C
 In C programming, a string is a sequence of characters terminated with a null
 character \0.
 rs
 When the compiler encounters a sequence of characters enclosed in the double
 quotation marks, it appends a null character \0 at the end by default.
c s t r i n g \0
 ve
 Here is how you can declare strings:
char s[5];
a b c d \0
 Arrays and strings are second-class citizens in C; they do not support the
 assignment operator once it is declared.
 m
 ●● strcpy : strcpy copies a string, including the null character terminator from
 the source string to the destination. This function returns a pointer to the
 destination string.
(c
 ●● strcmp : Two strings are compred with this function. If the first string is greater
 Notes than the second, it returns a number greater than zero. If the second string is
 ity
 greater, it returns a number less than zero. If the strings are equal, it returns 0.
 ●● strlen : This function returns the length of a string, not counting the null
 character at the end. That is, it returns the character count of the string,
 without the terminator.
 We can use the scanf() function to read a string.
 rs
 The scanf() function reads the sequence of characters until it encounters
 whitespace (space, newline, tab, etc.).
 ve
 #include <stdio.h>
int main()
char name[20];
 scanf(“%s”, name);
 ni
 printf(“Your name is %s.”, name);
 U
 return 0;
 }
 Output:
 You can use the fgets() function to read a line of string. You can use puts()
 m
 to display the string. The puts() function is used to write a line or string to the output
 stream. It prints the passed string with a newline and returns an integer value.
 Example of fgets():
 )A
#include <stdio.h>
#define MAX 15
int main()
 char buf[MAX];
(c
 ity
 return 0;
 }
 Output:
 rs
 The string is: Learning C
 Example of puts():
#include<stdio.h>
int main()
 ve
 {
//string initialization
 ni
 char str2[10] = “Language”;
puts(str1);
 }
 Output:
 C
 ity
Language
 declaration methods produce similar results because each tells the compiler that an
 integer pointer is going to be received. Similarly, you can pass multi-dimensional arrays
 as formal parameters.
Example:
#include <stdio.h>
int main() {
 ity
 result = calculateSum(age);
return 0;
 rs
 float calculateSum(float age[]) {
int i;
 ve
 for( i = 0; i < 6; ++i) {
sum += age[i];
return sum;
Output:
 Result = 162.50
 ni
 U
 Example : Passing two-dimensional arrays
#include <stdio.h>
int main()
int num[2][2], a, b;
 printf(“Enter 4 numbers:\n”);
 m
 scanf(“%d”, &num[a][b]);
 )A
displayNumbers(num);
return 0;
int i, j;
 ity
 for (i = 0; i < 2; ++i) {
printf(“%d\t”, num[i][j]);
 rs
 printf(“\n”);
 ve
 Output:
Enter 4 numbers:
2345
 4
 3
 5
 ni
 U
 ity
 m
 )A
(c
 ity
 1.4.1 Implementing One Dimensional Array
 To implement an array, first we need to declare the data type and then declare
 array name and mention size of array.
 rs
 For example: float mark [5];
 Here, we declared an array (name of array is mark) of floating-point type and size
 is 5 i.e., it can hold 5 floating-point values. It is important to note that the size and type
 of an array cannot be changed once it is declared.
 ve
 A variable can be initialized in its declaration.
 ni
 separated with commas and enclosed within braces.
For example: int age [5] = {23, 56, 87, 92, 38};
 In this declaration, age [0] is initialized to 23, age [1] is initialized to 56, and so on.
 U
 There must be at least one initial value between braces. If too many initial values are
 specified, a syntax error will occur. If the number of initial values is less than the array
 size, the remaining array elements will be initialized to zero.
 ●● Storage: There are lesser non-zero elements than zeros and thus lesser
 memory can be used to store only those elements.
 m
 00304
 )A
00570
00000
02600
 zeroes in the matrix are of no use in most of the cases. So, instead of storing zeroes
 with non-zero elements, we only store non-zero elements. This means storing non-zero
 elements with triples- (Row, Column, value).
 Sparse Matrix Representations can be done in many ways following are two
 common representations: Notes
 ity
 ●● Array representation
 ●● Linked list representation
 rs
 #include<stdio.h>
int main()
 ve
 int i, j, rows, columns, a[10][10], Total = 0;
scanf(“%d”, &a[rows][columns]);
	} }
 ity
 {
 m
if(a[rows][columns] == 0)
 Total++; 
 )A
	}
 Amity Directorate of Distance & Online Education
 26 Data Structure Using C
	else
 Notes
 ity
	{
printf(“\n The Matrix that you entered is Not a Sparse Matrix “);
return 0;
 rs
 }
Output:
 ve
 Enter the Matrix Elements:
00304
00570
00000
02600
 ni
 The Matrix that you entered is a Sparse Matrix
 4. The number of items used by the dynamic array contents is its ______
 a) Physical size
 b)	Capacity
 Notes
 ity
 c) Logical size
 d) Random size
 5. Array is divided into two parts in ____________
 a) Hashed Array Tree
 b) Geometric Array
 rs
 c) Bounded-size dynamic array
 d) Sparse Array
 6. In which of the following cases dynamic arrays are not preferred?
 ve
 a) If the size of the array is unknown
 b) If the size of the array changes after few iterations
 c) If the memory reallocation takes more time i.e. expensive
 d) If the array holds less number of elements
 7.
 ni
 Which of the following is not the method to represent Sparse Matrix?
 a) Dictionary of Keys
 b) Linked List
 U
 c)	Array
 d)	Heap
 8. What will be the output of the following C code?
 #include <stdio.h>
 ity
 }
 void main()
 {
 int a[2][3] = {0};
 f(a);
(c
 a) 0 3 0 0 0 0
 Notes
 ity
 b) Junk 3 junk junk junk junk
 c) Compile time error
 d) All junk values
 9. What will strcmp() function do?
 a) compares the first n characters of the object
 rs
 b) compares the string
 c) undefined function
 d) copies the string
 ve
 10. Which of the following function is correct that finds the length of a string?
 a) int xstrlen(char *s)
 {
 int length=0;
 while(*s!=’\0’)
 { length++; s++; }
 return (length);
 ni
 U
 }
 b) int xstrlen(char s)
 {
 int length=0;
 ity
 while(*s!=’\0’)
 length++; s++;
 return (length);
 }
 m
 while(*s!=’\0’)
 length++;
 return (length);
 }
 d) int xstrlen(char *s)
(c
 {
 int length=0;
 while(*s!=’\0’)
 Notes
 ity
 s++;
 return (length);
 }
Answer key:
 rs
 1. c, 2. a, 3. b, 4. c, 5. c, 6. d, 7. d, 8. a, 9. b, 10. a
 ve
 ni
 U
 ity
 m
 )A
(c
 ity
 Structure:
 rs
 2.1.2 Array Representation of Stack
 2.1.3 Operations Associated with Stacks- Push & Pop
 2.1.4 Polish expressions
 2.1.5 Conversion of infix to postfix
 ve
 2.1.6 Infix to Prefix (and vice versa),
 2.1.7 Application of stacks recursion
 2.1.8 Polish expression and their compilation
 2.1.9 Conversion of infix expression to prefix and postfix expression
 Unit-2.1: Stack
 Notes
 ity
 2.1.1 Definition
 Stack is a linear data structure which follows a particular order in which the
 operations are performed. The order may be LIFO(Last In First Out) or FILO(First In
 Last Out).
 rs
 Push
 ve
 Top
 Stack is a linear data structure which follows a particular order in which the
 operations are performed. The order may be LIFO (Last in First Out) or FILO (First In
 Last Out).
 ●●
 ni
 Mainly the following three basic operations are performed in the stack:
 Push: Adds an item in the stack. If the stack is full, then it is said to be an
 Overflow condition.
 U
 ●● Pop: Removes an item from the stack. The items are popped in the reversed
 order in which they are pushed. If the stack is empty, then it is said to be an
 Underflow condition.
 ●● Peek or Top: Returns top element of stack.
 ●● isEmpty: Returns true if stack is empty, else false.
 ity
 Adding an element into the top of the stack is referred to as push operation. Push
 operation involves following two steps.
 1. Increment the variable Top so that it can now refer to the next memory location.
 )A
(0) (1) (2) (3) (4) (5) (6) (7) (8) (9)
Notes
 ity
 Array
 12 Top
 Elements of stack to
 12 [12, 08, 21, 33, 18, 40]
 be added in the array
 12
 12 (0) (1) (2) (3) (4) (5) (6) (7) (8) (9)
 12
 12
 Stack
 Memory that will be occupied
 by the stack elements
 rs
 2.1.3 Operations Associated with Stacks- Push & Pop
 A stack is a simple last-in, first-out (LIFO) data structure. That is, the last data
 ve
 element stored in a stack is the first data element retrieved from the stack. The common
 analogy is a stack of plates in a cafeteria: when you go through the line, you pop the top
 plate off the stack; the dish washer (stepping away from reality a bit), pushes a single
 clean plate on top of the stack. So a stack supports two basic operations: push and
 pop. Some stacks also provide additional operations: size (the number of data elements
 currently on the stack) and peek (look at the top element without removing it).
 Operation
 ni
 Based on these operations, the snapshots shown in Figure 3 illustrate the
 appearance of a stack as data (characters) are stored in or pushed on to it.
 Picture Execution
 U
 Stack is empty 3
 2
 1
 0 ← sp = 0
 ity
st
st
 0 A
 st
st
 The push operation illustrated. Each call to the push function (left column)
 pushes a data element on to the stack. The main instruction in the push function is Notes
 ity
 st [sp++] = data, where “data” is the function argument. The middle column abstractly
 illustrates how the stack (the array and the stack pointer) appear after each call to the
 push function. The right column breaks the behaviour of the push function in to two
 steps.
Similarly, the data (characters) stored in a stack can be retrieved from or popped
 rs
 off it.
 data = pop(); 3 sp = 3 - 1;
 return sp[2];
 ve
 2 C ← sp = 2
 1 B
 0 A
 st
data = pop(); 3 sp = 2 - 1;
 ni
 2 C return sp[2];
 1 B ← sp = 1
 0 A
 st
 U
 data = pop(); 3 sp = 1 - 1;
 2 C return sp[2];
 1 B
 0 A ← sp = 0
 st
 ity
 ●● Infix form
 ●● Prefix form
 ●● Postfix form
 )A
3. - (unary negation)
2. */
 1. + - (subtraction)
 Notes
 ity
 Thus, high priority corresponds to high number in the table.
Step 2) If the token is an operand, do not stack it. Pass it to the output.
 -- Pop the stack until you find a symbol of lower priority number than the current
 one. An incoming left parenthesis will be considered to have higher priority than any
 rs
 other symbol. A left parenthesis on the stack will not be removed unless an incoming
 right parenthesis is found.
 ve
 --Stack the current symbol.
 -- If a right parenthesis is the current symbol, pop the stack down to (and
 including) the first left parenthesis. Write all the symbols except the left parenthesis to
 the output (i.e. write the operators to the output).
-- After the last token is read, pop the remainder of the stack and write any symbol
 Move
 ni
 (except left parenthesis) to output.
2 * * A
 3 ( (* A
 ity
4 B (* AB
5 + +(* AB
6 C +(* ABC
7 ) * ABC+
 8 * * ABC+*
 m
9 D * ABC+*D
 10 empty
 )A
 Step 2. Scan A from right to left and repeat step 3 to 6 for each element of A until
 the STACK is empty.
 a. Repeatedly pop from STACK and add to B, each operator (on the top of STACK)
 which has same or higher precedence than the operator. Notes
 ity
 b. Add operator to STACK.
 Step 6. If left parenthesis is encountered then
 a. Repeatedly pop from the STACK and add to B (each operator on top of stack
 until a left parenthesis is encountered)
 rs
 b. Remove the left parenthesis.
 Step 7. Exit
Expression = (A+B^C)*D+E^5
 ve
 Step 1. Reverse the infix expression.
5^E+D*)C^B+A(
5^E+D*(C^B+A)
A+(B*C-(D/E-F)*G)*H
 E+D*(C^B+A) ^ 5 Push
 ity
+D*(C^B+A) ^ 5E Push
 ity
 “Recursion” is technique of solving any problem by calling same function again
 and again until some breaking (base) condition where recursion stops, and it starts
 calculating the solution from there on. By using stack, many programming languages
 implement recursion. When a function calls another function, the value of all variables
 need to be saved, hence, when the called function returns, the values are exactly as
 they were left. We know when a recursive function calls itself, it is a series of nested
 rs
 functions. It may not have any local variables, but always have a return address and the
 stack facilitates this. To store and restore the recursive function and arguments, stack is
 used.
 ve
 int fact(int n){
if(n == 0){
return 1;
 }
 ni
 return (n * fact(n-1)); //function fact() is calling itself
 U
 2.1.8 Polish Expression and Their Compilation
 Notation is the way to write arithmetic expression. The name comes from the
 Polish mathematician/logician Lukasiewicz, who introduced it. There are 3 different
 ways to write an algebraic expressions:
 ity
 ●● Infix form
 ●● Prefix form
 ●● Postfix form
 a×b × ab ab ×
 m
 a+b×c +a × bc abc × +
 (a + b) × c × + abc ab + c ×
 Infix form
 In infix form, the operators are used in between operands. Though it is easy for
 human to read and understand this form easily but the same is not true for computing
 device.
(c
For examples
(3 * 7)
 ((1 + 3) * 2)
 Notes
 ity
 ((1 + 3) * ( 2 - 3))
 rs
 understanding, just think of an infix notation, (a+b) and if the same expression we want
 to write in prefix notation then it would be like +ab.
 ve
 (* 3 7) or simply * 3 7
(* ( + 1 3) 2) or simply * + 1 3 2
( * ( + 1 3) ( - 2 3)) or simply * + 1 3 - 2 3
 ni
 In postfix form, as the name suggests, the operator is post fixed or lies after the two
 operands. For better understanding, just think of an infix notation, (a+b) and if the same
 expression we want to write in postfix form, then it would be like ab+
 U
 More examples:
(3 7 *) or simply 3 7 *
((1 3 + ) 2 *) or simply 1 3 + 2 *
 ((1 3 +) ( 2 3 -) * ) or simply 1 3 + 2 3 - *
 ity
 In this case, we have operator’s stack, output’s stack and one input string.
 m
 Operator’s stack works as FILO (First In Last Out). Output’s stack works as FIFO (First
 In First Out).
 ity
 ) ) -
) )) -
T )) T
- ))- T
 rs
 S ))- ST
( ) -ST
/ )/ -ST
 ve
 ) )/) -ST
R )/) R-ST
* )/)* R-ST
Q )/)* QR-ST
 ni
 ( )/ *QR-ST
+ )+ /*QR-ST
 P )+ P/*QR-ST
 U
 ( Empty +P/*QR-ST
 In this case, we use the stacks to convert infix to postfix. We have operator’s stack,
 output’s stack and one input string. Operator’s stack works as FILO (First In Last Out).
 Output’s stack works as FIFO (First In First Out).
 ●● If the character is opening round bracket ( ‘(‘ ), push it into operator’s stack.
 ●● If the character is closing round bracket ( ‘)’ ), pop out operators from
 operator’s stack until we find an opening bracket (‘(‘ ).
 Amity Directorate of Distance & Online Education
 Data Structure Using C 39
 ●● Now pop out all the remaining operators from the operator’s stack and push
 into output stack. Notes
 ity
 Infix expression: (A/(B-C)*D+E)
( ( -
A ( A
 rs
 / (/ A
( (/( A
B (/( AB
 ve
 - (/(- AB
C (/(- ABC
) (/ ABC-
* (* ABC-/
 E
 (*
(+
 (+
 ni
 ABC-/D
ABC-/D*
 ABC-/D*E
 U
 ) Empty ABC-/D*E+
 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:
 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.
 )A
 ity
 Shift ‘n-1’ disks from ‘B’ to ‘C’.
 3 Disk 1
A B C A B C
2 3 4
 rs
 A B C A B C A B C
5 6 7
 ve
 A B C A B C A B C
Example:
#include <stdio.h>
int num;
scanf(“%d”, &num);
 return 0;
 m
 {
 )A
if (num == 1)
 return;
(c
 printf(“\n Move disk %d from peg %c to peg %c”, num, frompeg, topeg);
 Notes
 ity
 towers(num - 1, auxpeg, topeg, frompeg);
Output:
 rs
 The sequence of moves involved in the Tower of Hanoi are :
 ve
 Move disk 1 from peg C to peg B
 ni
 U
 ity
 m
 )A
(c
 Unit-2.2: Queue
 Notes
 ity
 2.2.1 Definition
 Queue is an abstract data structure, somewhat like Stacks. Unlike stacks, a queue
 is open at both its ends. One end is always used to insert data (enqueue) and the other
 is used to remove data (dequeue). Queue follows First-In-First-Out methodology, i.e.,
 the data item stored first will be accessed first.
 rs
 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
 ve
 we remove the item the most recently added; in a queue, we remove the item the least
 recently added.
 Queue
 Insertion and Deletion
 happen on different ends
Enqueue
ni Rear
Queue
 Notes
 FRONT
 REAR -1 0 1 2 3 4
 ity
 empty queue
 -1 0 1 2 3 4
 1
 queue the first element
 rs
 -1 0 1 2 3 4
 1 2
 enqueue
 ve
 -1 0 1 2 3 4
 1 2 3 4 5
 enqueue
 -1 0 1 2 3 4
 2 3 4 5
 ni
 dequeue
 -1 0 1 2 3 4
 5
 dequeue the last element
 U
 -1 0 1 2 3 4
 5
 empty queue
 Enqueue Operation
 ●● check if the queue is full
 ●● for the first element, set the value of FRONT to 0
 ●● increase the REAR index by 1
 m
 Dequeue Operation
 ●● check if the queue is empty
 )A
 ●● peek() − Gets the element at the front of the queue without removing it.
 ●● isfull() − Checks if the queue is full.
 ity
 2.2.4 Priority Queue
 Priority Queue is an extension of queue with following properties.
 rs
 3. If two elements have the same priority, they are served according to their order
 in the queue.
 A typical priority queue supports following operations.
 ve
 getHighestPriority(): Returns the highest priority item.
 ni
 Element with the
 highest priority 9
 4
 5
 3
 Dequeue
 U
 2
 1
 Enqueue
 0
 )A
 9
 1 2
 3 5
 3 4 5 6
(c
 1 4 2 7
 Heapify the tree.
 0
 Notes
 ity
 9
 1 2
 3 7
 3 4 5 6
 rs
 1 4 2 5
 Algorithm for insertion of an element into priority queue (max-heap)
If there is no node,
 ve
 create a newNode.
insert the newNode at the end (last node from left to right.)
 9
 1 2
 ity
 3 7
 3 4 5 6
 1 4 2 5
 m
 9
 1 2
 5 7
 3 4 5 6
(c
 1 4 2 3
 Remove the last element.
 0
 Notes
 ity
 9
 1 2
 5 7
 3 4 5
 rs
 6
 1 4 2
 3
 Heapify the tree.
 ve
 0
 9
 1 2
 5 7
 3
1 ni 4
 4
 5
 2
 U
 Algorithm for deletion of an element in the priority queue (max-heap)
remove noteToBeDeleted
 1) CPU Scheduling
 m
#include <stdio.h>
#include <stdlib.h>
#define MAX 5
 void insert_by_priority(int);
(c
void delete_by_priority(int);
void create();
 void check(int);
 Notes
 ity
 void display_pqueue();
int pri_que[MAX];
void main()
 rs
 {
int n, ch;
 ve
 printf(“\n2 - Delete an element from queue”);
printf(“\n4 - Exit”);
create();
while (1)
switch (ch)
 {
 ity
case 1:
scanf(“%d”,&n);
 insert_by_priority(n);
 m
break;
case 2:
scanf(“%d”,&n);
delete_by_priority(n);
break;
case 3:
 display_pqueue();
(c
break;
case 4:
 exit(0);
 Notes
 ity
 default:
 rs
 }
void create()
 ve
 {
 return;
 ity
 front++;
 m
rear++;
pri_que[rear] = data;
 return;
 )A
else
check(data);
rear++;
 }
(c
 {
 Notes
 ity
 int i,j;
 rs
 {
 ve
 pri_que[j] = pri_que[j - 1];
pri_que[i] = data;
return;
 }
 }
 pri_que[i] = data;
 ni
 U
 }
int i;
 {
 m
return;
 }
 )A
if (data == pri_que[i])
 }
 Notes
 ity
 pri_que[i] = -99;
rear--;
if (rear == -1)
front = -1;
 rs
 return;
 ve
 printf(“\n%d Not found in queue to delete”, data);
void display_pqueue()
 ni
 if ((front == -1) && (rear == -1))
 {
 U
 printf(“\nQueue is empty”);
return;
 }
 ity
printf(“ %d “, pri_que[front]);
 }
 m
front = 0;
 Output:
 )A
4 - Exit
 ity
 Enter your choice: 1
25 10 5
 rs
 Enter your choice: 2
 ve
 25 5
 ni
 FIFO(First In First Out), but instead of ending the queue at the last position, it again
 starts from the first position after the last, hence making the queue behave like a
 circular data structure.
 In case of a circular queue, head pointer will always point to the front of the queue,
 U
 and tail pointer will always point to the end of the queue.
 Initially, the head and the tail pointers will be pointing to the same location, this
 would mean that the queue is empty.
 Head
 ity
Tail
 New data is always added to the location pointed by the tail pointer, and once the
 data is added, tail pointer is incremented to point to the next available location.
 )A
 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.
 Here, the circular increment is performed by modulo division with the queue size.
 That is,
 2.2.6 Deque
 Notes
 ity
 Deque or Double Ended Queue is a generalized version of Queue data structure
 that allows insert and delete at both ends.
Operations on Deque:
 rs
 insertLast(): Adds an item at the rear of Deque.
 ve
 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.
#include <stdio.h>
 #define size 5
 ni
 U
 void insertq(int[], int);
void deleteq(int[]);
 void display(int[]);
 ity
int front = - 1;
int rear = - 1;
int main()
 int n, ch;
 m
int queue[size];
 do
 )A
scanf(“%d”, &ch);
 switch (ch)
(c
case 1:
 ity
 scanf(“%d”, &n);
insertq(queue, n);
break;
case 2:
 rs
 deleteq(queue);
break;
case 3:
 ve
 display(queue);
break;
 {
 ni
 U
 if ((front == 0 && rear == size - 1) || (front == rear + 1))
 printf(“queue is full”);
 ity
return;
else if (rear == - 1)
 {
 m
rear++;
front++;
 }
 )A
rear = 0;
 else
(c
rear++;
 }
 Notes
 ity
 queue[rear] = item;
 rs
 int i;
printf(“\n”);
 ve
 {
printf(“%d “, queue[i]);
 ni
 for (i = 0; i <= rear; i++)
 printf(“%d “, queue[i]);
 U
 }
else
 {
 ity
printf(“%d “, queue[i]);
 }
 m
 if (front == - 1)
 )A
 {
(c
 front = - 1;
 Notes
 ity
 rear = - 1;
else
 rs
 printf(“\n %d deleted”, queue[front]);
front++;
 ve
 }
 d)	-18
 3. When the user tries to delete the element from the empty stack then the condition
 is said to be a ____
 a)	Underflow
 m
 b) Garbage collection
 c)	Overflow
 d) None of the above
 4. Entries in a stack are “ordered”. What is the meaning of this statement?
 )A
 5. If the size of the stack is 10 and we try to add the 11th element in the stack then
 the condition is known as___
 a) Underflow
 b) Garbage collection
 Notes
 ity
 c) Overflow
 d) None of the above
 6. Which one of the following is not the application of the stack data structure
 a) String reversal
 b)	Recursion
 rs
 c)	Backtracking
 d) Asynchronous data transfer
 7. Which data structure is mainly used for implementing the recursive algorithm?
 ve
 a)	Queue
 b)	Stack
 c) Binary tree
 d) Linked list
 8.
 ni
 Which data structure is required to convert the infix to prefix notation?
 a)	Stack
 b) Linked list
 U
 c) Binary tree
 d)	Queue
 9. Which of the following is the prefix form of A+B*C?
 a)	A+(BC*)
 ity
 b)	+AB*C
 c)	ABC+*
 d)	+A*BC
 10. Which of the following is not the correct statement for a stack data structure?
 m
 Answer key:
 1. c, 2. d, 3. a, 4. d, 5. c, 6. d, 7. b, 8. a, 9. d, 10. b
(c
 ity
 Structure:
 rs
 3.1.2 Traversing, Searching, Insertion, Deletion from linked list
 3.1.3 Garbage collection and compaction
 ve
 3.2.1 Introduction to doubly linked list
 3.2.2 Operations on doubly linked list
 ity
 3.1.1 Introduction and Representation of linked lists in Memory
 Linked list is a linear data structure. Linked list is defined as collection of objects
 called nodes and nodes are stored randomly in memory. A node contains two fields,
 one field contains data and the other field contains address of the node. The last node
 points to NULL. Unlike array here the list is not contiguous in memory. Empty node
 rs
 cannot be present here.
 Singly Linked is collection of ordered set of nodes. According to the need of the
 program, the number of nodes varies. Linked list components are not stored at a
 contiguous location. The elements are linked using pointers. Singly link list can traverse
 ve
 only in one direction.
Head
 A B C D NULL
 Data Next
 ni
 Fig 3.1 Singly link list
 In the above figure, the arrow represents the link and the data part contains values.
 A linked list is characterized by a pointer to the first node of the linked list. In the figure,
 U
 next defines the address of the next node. The first node is termed the head. If the
 linked list is empty, then the value of head is NULL.
 The list is not necessary to be contiguously present in the memory. The node
 can reside anyplace in the memory and linked together to make a list. This achieves
 ity
 optimized utilization of space. List size is limited to the memory size and does not
 require to be declared in advance. Empty node cannot be appear in the linked list. We
 can store values of primitive types or objects in the singly linked list. Data part of the
 node stores genuine information that is to be epitomized by the node while the link part
 of the node stores the address of its current successor.
 One way chain or singly linked list can be traversed only in one direction. In
 m
 other words, we can say that each node includes only next pointer, therefore we
 cannot traverse the list in the reverse direction. Let us take one example for better
 understanding. In below figure we can see a singly linked list which shows the marks
 obtained by the student in three subjects.
 )A
Head
23 34 90
 In the above figure, the arrow symbolizes the links which hold the address of next
(c
 node. The last node in the list is pinpointed by the null pointer which is present in the
 address part of the last node. We can have as many elements as possible we require,
 in the data part of the list.
 ity
 Operations on Singly Linked List:
Node Creation:
struct node
 rs
 int data;
};
 ve
 struct node *head, *ptr;
Insertion
 The insertion into a singly linked list can be performed at different positions. Based
 on the position of the new node being inserted, the insertion is categorized into the
 following categories.
 Insertion at beginning
 ni
 By this process we can insert any element at the beginning of the list. For doing
 U
 this, we need to make the new node as the head of the list.
Steps:
Example:
 newNode->data = 4;
 )A
newNode->next = head;
head = newNode;
 By this process, we can insert a node at the end of the list. The new node has to
 be added after the last node. Let us think of a link list like 10->20->30->40 and now we
(c
 want to add a new node 50 at the end of the list, so the list will become 10->20->30-
 >40->50. For doing this, we have to traverse the list till the end and we need to make
 change of next of last node to new node.
 Steps:
 Notes
 ity
 ●● Allocate memory for new node
 ●● Store data
 ●● Traverse to last node
 ●● Change next of last node to recently created node
Example:
 rs
 struct node *newNode;
newNode->data = 4;
 ve
 newNode->next = NULL;
while(temp->next != NULL){
temp = temp->next;
 temp->next = newNode; ni
 U
 This process contains insertion at the last of the linked list. The new node can be
 inserted as the only node in the list or it can be inserted as the last one. Different logics
 we have to implemented for each scenario.
 By this process, we can insert a node after a specific node in the list. We already
 ity
Steps:
newNode->data = 4;
 if(temp->next != NULL) {
(c
temp = temp->next;
} }
 newNode->next = temp->next;
 Notes
 ity
 temp->next = newNode;
Traversing
 rs
 Example:
ptr = head;
while (ptr!=NULL)
 ve
 {
Algorithm
 ●●
 ●●
 STEP 1: SET PTR = HEAD
 STEP 2: IF PTR = NULL
 WRITE “EMPTY LIST”
 ni
 U
 GOTO STEP 7
END OF IF
 ●● STEP 7: EXIT
 Example:
 m
#include<stdio.h>
#include<stdlib.h>
 void create(int);
 )A
void traverse();
struct node
 int data;
(c
};
 void main ()
 Notes
 ity
 {
int choice,item;
do
 rs
 printf(“\n1.Append List\n2.Traverse\n3.Exit\n4.Enter your choice\n”);
scanf(“%d”,&choice);
switch(choice)
 ve
 {
case 1:
scanf(“%d”,&item);
create(item);
break;
 case 2:
 ni
 U
 traverse();
break;
 case 3:
 ity
exit(0);
break;
default:
}while(choice != 3);
 }
 )A
if(ptr == NULL)
 {
(c
printf(“\nOVERFLOW\n”);
 else
 Notes
 ity
 {
ptr->data = item;
ptr->next = head;
head = ptr;
 rs
 printf(“\nNode inserted\n”);
 ve
 void traverse()
ptr = head;
if(ptr == NULL)
 printf(“Empty list..”);
 ni
 U
 }
else
 {
 ity
while (ptr!=NULL)
 printf(“\n%d”,ptr->data);
 m
 }
 )A
Output:
 1. Append List
 2. Traverse
 3. Exit
(c
 100
 Notes
 ity
 Node inserted
 1. Append List
 2. Traverse
 3. Exit
 4. Enter your choice
 rs
 1
200
 ve
 Node inserted
 1. Append List
 2. Traverse
 3. Exit
 4. Enter your choice
 1
Node inserted
 1. Append List
 ity
 2. Traverse
 3. Exit
 4. Enter your choice
 2
 m
300
 200
 )A
100
 1. Append List
 2. Traverse
 3. Exit
 4. Enter your choice
(c
Deletion
 Like insertion, the Deletion of a node from a singly linked list can be achieved at
 different positions. Based on the position of the node being deleted, the operation is Notes
 ity
 classified into the following categories.
Deletion at beginning
 By this process, deletion of a node from the beginning of the list can be done.
 This is the easiest operation among all. It just requires a few adjustments in the node
 pointers.
 rs
 ●● Point head to the second node
 head = head->next;
 ve
 By this process we can delete the last node of the list. The list can either be empty
 or full. Different logic is implemented for the different scenarios.
Steps:
 while(temp->next->next!=NULL){ ni
 U
 temp = temp->next;
temp->next = NULL;
 By this process we can delete a node after a specified node in the list. we require
 to skip the desired number of nodes to reach the node after which the node will be
 deleted. For doing so we need to traverse through the list.
 Steps:
 m
 if(temp->next!=NULL) {
 )A
temp = temp->next;
 temp->next = temp->next->next;
(c
Searching
 While searching, we need to match each element of the list with the given element.
 If the element is discovered on any of the location then location of that element is
 ity
 Example:
#include<stdio.h>
#include<stdlib.h>
struct node
 rs
 { int data;
};
 ve
 struct node *head;
void otherinsert();
void begin_delete();
void last_delete();
 void other_delete();
 ni
 U
 void display();
void search();
 void main ()
 ity
while(choice != 9)
scanf(“\n%d”,&choice);
switch(choice)
 case 1:
(c
begininsert();
break;
case 2:
 lastinsert();
 Notes
 ity
 break;
case 3:
otherinsert();
break;
 rs
 case 4:
begin_delete();
break;
 ve
 case 5:
last_delete();
break;
case 6:
other_delete();
break;
 case 7:
 ni
 U
 search();
break;
 case 8:
 ity
display();
break;
case 9:
 exit(0);
 m
break;
default:
} } }
void begininsert()
 int item;
(c
if(ptr == NULL)
 { printf(“\nOVERFLOW”);
 Notes
 ity
 }
else
{ printf(“\nEnter value\n”);
scanf(“%d”,&item);
 rs
 ptr->data = item;
ptr->next = head;
head = ptr;
 ve
 printf(“\nNode inserted”);
} }
void lastinsert()
 int item;
 ni
 ptr = (struct node*)malloc(sizeof(struct node));
 U
 if(ptr == NULL)
{ printf(“\nOVERFLOW”);
 }
 ity
else
scanf(“%d”,&item);
 ptr->data = item;
 m
if(head == NULL)
 head = ptr;
 )A
printf(“\nNode inserted”);
else
 temp = head;
(c
 ity
 }
temp->next = ptr;
ptr->next = NULL;
printf(“\nNode inserted”);
 rs
 } } }
void otherinsert()
 ve
 int i,loc,item;
if(ptr == NULL)
 else
 printf(“\nOVERFLOW”);
 ni
 U
 {
 scanf(“%d”,&item);
 ity
ptr->data = item;
scanf(“\n%d”,&loc);
 temp=head;
 m
for(i=0;i<loc;i++)
 temp = temp->next;
 )A
if(temp == NULL)
{ printf(“\ncan’t insert\n”);
return;
} }
printf(“\nNode inserted”);
 }
 Notes
 ity
 }
void begin_delete()
 rs
 if(head == NULL)
printf(“\nList is empty.\n”);
 ve
 }
else
ptr = head;
head = ptr->next;
 free(ptr);
 ni
 printf(“\nNode deleted from the beginning.\n”);
 U
 }
 void last_delete()
 ity
if(head == NULL)
 {
 m
printf(“\nlist is empty”);
head = NULL;
free(head);
 }
(c
else
 ptr = head;
 Notes
 ity
 while(ptr->next != NULL)
ptr1 = ptr;
 rs
 }
ptr1->next = NULL;
free(ptr);
 ve
 printf(“\nDeleted Node from the last.\n”);
} }
void other_delete()
 \n”);
 int loc,i;
 ni
 printf(“\n Enter the location of the node after which you want to perform deletion
 U
 scanf(“%d”,&loc);
ptr=head;
for(i=0;i<loc;i++)
 {
 ity
ptr1 = ptr;
ptr = ptr->next;
if(ptr == NULL)
 {
 m
printf(“\nCan’t delete”);
return;
 } }
 )A
free(ptr);
 }
(c
void search()
 int item,i=0,flag;
 Notes
 ity
 ptr = head;
if(ptr == NULL)
printf(“\nEmpty List\n”);
 rs
 }
else
 ve
 printf(“\nEnter item which you want to search?\n”);
scanf(“%d”,&item);
while (ptr!=NULL)
if(ptr->data == item)
 {
 ni
 printf(“item found at location %d “,i+1);
 U
 flag=0;
 else
 ity
flag=1;
 i++;
 m
 if(flag==1)
 )A
} } }
void display()
 {
(c
 ptr = head;
 Notes
 ity
 if(ptr == NULL)
printf(“Nothing to print”);
 rs
 else
 ve
 while (ptr!=NULL)
printf(“\n%d”,ptr->data);
} } }
 ni
 After compiling the above program, the below output will be shown
 Output:
 U
 Choose one option from the following list
 1. Insert at beginning
 2. Insert at last
 3. Insert at any other location
 ity
 8. Display list
 9.	Exit
 Enter your choice:1
 )A
Enter value
10
Node inserted
 1. Insert at beginning
 2. Insert at last
 3. Insert at any other location
 ity
 5. Delete node from last
 6. Delete node after specified location
 7. Search for an element
 8. Display list
 9.	Exit
 rs
 Enter your choice:1
Enter value
20
 ve
 Node inserted
 1. Insert at beginning
 2. Insert at last
 ni
 3. Insert at any other location
 4. Delete node from beginning
 5. Delete node from last
 U
 6. Delete node after specified location
 7. Search for an element
 8. Display list
 ity
 9.	Exit
 Enter your choice:1
Enter value
30
 Node inserted
 m
 1. Insert at beginning
 2. Insert at last
 )A
 9.	Exit
 Notes
 ity
 Enter your choice:1
Enter value
40
Node inserted
 rs
 Choose one option from the following list
 1. Insert at beginning
 2. Insert at last
 3. Insert at any other location
 ve
 4. Delete node from beginning
 5. Delete node from last
 6. Delete node after specified location
 7. Search for an element
 8. Display list
 9.	Exit
 Enter your choice:8
 ni
 U
 The list is:
40
 30
 ity
20
10
 1. Insert at beginning
 m
 2. Insert at last
 3. Insert at any other location
 4. Delete node from beginning
 )A
Enter value:
 60
 Amity Directorate of Distance & Online Education
 76 Data Structure Using C
 Node inserted
 Notes
 ity
 Choose one option from the following list
 1. Insert at beginning
 2. Insert at last
 3. Insert at any other location
 4. Delete node from beginning
 rs
 5. Delete node from last
 6. Delete node after specified location
 7. Search for an element
 ve
 8. Display list
 9.	Exit
 Enter your choice:8
Enter value
40
30
 20
 ni
 U
 10
50
 1. Insert at beginning
 2. Insert at last
 3. Insert at any other location
 4. Delete node from beginning
 m
 9.	Exit
 Enter your choice:4
 1. Insert at beginning
 2. Insert at last
 ity
 4. Delete node from beginning
 5. Delete node from last
 6. Delete node after specified location
 7. Search for an element
 8. Display list
 rs
 9.	Exit
 Enter your choice:8
 ve
 30
20
10
50
 1. Insert at beginning
 2. Insert at last
 ni
 U
 3. Insert at any other location
 4. Delete node from beginning
 5. Delete node from last
 ity
 When a node is deleted, some memory space becomes reusable. This memory
 space should be obtainable for future use. One way to do this is to instantly insert the
 free space into availability list. But this method may be time exhausting for the operating
(c
 through all the lists and tags all those cells which are currently being utilized. In the
 Notes second step, the OS goes through all the lists again and collects untagged space and
 ity
 adds this collected space to availability list. The garbage collection may happen when
 small amount of free space is left in the system or no free space is left in the system or
 when CPU is idle and has time to do the garbage collection.
 Garbage collector is the magic component that makes the illusion of infinite
 memory possible. It typically comprises of two semi-independent components known as
 rs
 mutator and collector.
Mutator
 Usually, all components of a language runtime that are accountable for executing
 application code, allocating/de-allocating new objects, and managing execution
 ve
 contexts get considered as the mutators. Most acceptably large programs have more
 than one mutator threads. Precise number of mutator threads is generally irrelevant to
 the garbage collection approaches.
Collector
The collector executes the garbage collection code. It realizes the garbage (read:
 ni
 unreachable) objects and reclaims their storage. In concurrent GCs, there may be
 more than one collector threads. Exact number of collectors is mostly inappropriate
 to the approaches that we are going to discuss. Most GCs suggest control over the
 behaviours of collectors through configuration settings.
 U
 ity
 m
 )A
(c
 ity
 3.2.1 Introduction to Doubly Linked List
 An extra pointer has been added to implement a Doubly Linked List, usually termed
 as previous pointer, together with next pointer and data which are there in singly linked
 list.
 rs
 Head
 Next Next Next Next
 NULL
 NULL A B C D
 Prev Prev Prev Prev
 ve
 Below is the process of creating node in Doubly Link List.
struct Node {
int data;
 }; ni
 struct Node* next; // Pointer to next node in Doubly Link List
 to be deleted is given.
 3. We can swiftly insert a new node before a given node.
 In singly linked list, to delete a node, pointer to the previous node is needed. To
 get this previous node, the list has to be traversed. In Doubly Link List, we can get the
 earlier node using previous pointer itself.
 m
 The operations of doubly link list includes insertion, deletion and display
 operations. Node can be added in different ways.
(c
 The new node is all the time added before the head of the given Linked List. And
 recently added node becomes the new head of Doubly Link List.
 Head
 Notes Next Next Next Next
 NULL
 ity
 NULL A B C D
 Prev Prev Prev Prev
 Next
 E
 NULL
 Prev
 rs
 For example if the given Linked List is 20->10->1->5->2 and we include an item 4
 at the front, then the Linked List becomes 4->20->10->1->5->2. We need to call push()
 function which adds at the front of the list. The push() must receive a pointer to the
 head pointer, because push must change the head pointer to point to the new node
 ve
 Steps:
 1. allocate node
 2. insert 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
 Insertion of a node after a specified node
 ni
 U
 By this way the new node can be inserted after a specified node.
 Head
 Next Next Next Next
 NULL
 NULL A B C D
 Prev Prev Prev Prev
 ity
Next Prev
 E
 Prev Next
 Steps:
 m
 When we insert a node, the new node is always added after the last node. We
 need to traverse the list in order to change the nest of last node to new node.
 Notes
 Head
 Next Next Next Next
 ity
 NULL
 NULL A B C D
 Prev Prev Prev Prev
 Prev Next
 NULL
 E
 rs
 Steps
 Let the pointer to this given node be next_node and the data of the new node to be
 added as new_data.
1. Check if the next_node is NULL or not. If it’s NULL, return from the function
 ve
 because any new node cannot be added before a NULL
 2. Allocate memory for the new node, let it be called new_node
 3. Set new_node->data = new_data
 4. Set the previous pointer of this new_node as the previous node of the next_
 ni
 node, new_node->prev = next_node->prev
 5. Set the previous pointer of the next_node as the new_node, next_node->prev
 = new_node
 6. Set the next pointer of this new_node as the next_node, new_node->next =
 U
 next_node;
 7. If the previous node of the new_node is not NULL, then set the next pointer of
 this previous node as new_node, new_node->prev->next = new_node
 8. Else, if the prev of new_node is NULL, it will be the new head node. So, make
 ity
 (*head_ref) = new_node.
 Deletion
 Deletion can be done at three places. Deletion at beginning, deletion at middle and
 deletion at end. All the cases can be done in two steps if the pointer of the node to be
 deleted and the head pointer is known.
 m
Steps:
 1. If we want to delete the first node then we need to make the second node as
 head node.
 )A
 2. If a node is deleted then connect the next node and previous node of the deleted
 node.
 Let us understand the deletion process with the help of few pictures.
 Next
 Null
 pointer
 Start
 2 45 3 1
(c
pointer
 Previous
 pointer
 ity
 Null
 Start
 pointer 45 3 1
 Previous
 pointer
 rs
 After deletion of middle node:
Null
 Start
 45 1
 ve
 pointer
 Start
 pointer
 ni Null
 45 Null
 U
 Fig 3.10 After last node deletion
Searching
 While searching, we need to compare each node with the given node and if found
 we need to return the location of the item in the list, if not found then null has to be
 ity
returned.
Traversing
 Traversing simply means visiting each node in order to perform some specific
 operation.
 Example:
 m
#include<stdio.h>
 #include<stdlib.h>
 )A
struct node
 int data;
(c
};
 void beginninginsert();
 Notes
 ity
 void lastinsert();
void insertionother();
void deletion_beginning();
void deletion_last();
 rs
 void deletion_specified();
void display();
void search();
 ve
 void main ()
while(choice != 9)
 ni
 printf(“\nChoose one option from the following list:”);
 scanf(“\n%d”,&choice);
 ity
switch(choice)
case 1:
 beginninginsert();
 m
break;
case 2:
 lastinsert();
 )A
break;
case 3:
insertionother();
 break;
(c
case 4:
deletion_beginning();
break;
 case 5:
 Notes
 ity
 deletion_last();
break;
case 6:
deletion_specified();
 rs
 break;
case 7:
search();
 ve
 break;
case 8:
display();
break;
case 9:
exit(0);
 break;
 ni
 U
 default:
 } } }
 ity
void beginninginsert()
 int item;
 m
if(ptr == NULL)
 {
 )A
printf(“\nOVERFLOW”);
else
scanf(“%d”,&item);
if(head==NULL)
 {
 Notes
 ity
 ptr->next = NULL;
ptr->prev=NULL;
ptr->data=item;
head=ptr;
 rs
 }
else
 ve
 ptr->data=item;
ptr->prev=NULL;
ptr->next = head;
head->prev=ptr;
 }
 head=ptr;
 printf(“\nNode inserted\n”);
 ni
 U
 }}
void lastinsert()
 {
 ity
int item;
 if(ptr == NULL)
 m
printf(“\nOVERFLOW”);
 }
 )A
else
printf(“\nEnter value:”);
scanf(“%d”,&item);
 ptr->data=item;
(c
if(head == NULL)
 ptr->next = NULL;
 Notes
 ity
 ptr->prev = NULL;
head = ptr;
else
 rs
 temp = head;
while(temp->next!=NULL)
 ve
 temp = temp->next;
temp->next = ptr;
 ni
 ptr ->prev=temp;
ptr->next = NULL;
 } }
 U
 printf(“\nNode inserted\n”);
void insertionother()
 {
 ity
int item,loc,i;
 if(ptr == NULL)
 m
printf(“\n OVERFLOW”);
 }
 )A
else
temp=head;
scanf(“%d”,&loc);
for(i=0;i<loc;i++)
 temp = temp->next;
 Notes
 ity
 if(temp == NULL)
return;
} }
 rs
 printf(“Enter value:”);
scanf(“%d”,&item);
ptr->data = item;
 ve
 ptr->next = temp->next;
temp->next = ptr;
 ni
 temp->next->prev=ptr;
printf(“\nNode inserted\n”);
 } }
 U
 void deletion_beginning()
 if(head == NULL)
 ity
printf(“\n UNDERFLOW”);
head = NULL;
 free(head);
 )A
printf(“\nNode deleted\n”);
else
 {
(c
ptr = head;
 free(ptr);
 Notes
 ity
 printf(“\nNode deleted\n”);
} }
void deletion_last()
 rs
 if(head == NULL)
printf(“\n UNDERFLOW”);
 ve
 }
 ni
 head = NULL;
free(head);
 printf(“\nNode deleted\n”);
 U
 }
else
 ptr = head;
 ity
if(ptr->next != NULL)
 }
 m
free(ptr);
 printf(“\nNode deleted\n”);
 )A
} }
void deletion_specified()
int val;
printf(“\n Enter the data after which the node is to be deleted : “);
scanf(“%d”, &val);
 ptr = head;
 Notes
 ity
 while(ptr -> data != val)
printf(“\nCan’t delete\n”);
 rs
 }
 ve
 ptr ->next = NULL;
else
 ni
 {
free(temp);
printf(“\nNode deleted\n”);
 } }
 ity
void display()
ptr = head;
while(ptr != NULL)
 {
 )A
printf(“%d\n”,ptr->data);
ptr=ptr->next;
} }
 void search()
(c
int item,i=0,flag;
 ptr = head;
 Notes
 ity
 if(ptr == NULL)
printf(“\nEmpty List\n”);
else
 rs
 {
scanf(“%d”,&item);
 ve
 while (ptr!=NULL)
if(ptr->data == item)
 ni
 {
 flag=0;
 U
 break;
else
 {
 ity
flag=1;
i++;
if(flag==1)
 {
 )A
Output:
 1. Insert in beginning
(c
 2. Insert at last
 3. Insert at any random location
 4. Delete from Beginning
 ity
 6. Delete the node after the given data
 7.	Search
 8.	Display
 9.	Exit
 Enter your choice: 1
 rs
 Enter Item value: 1
Node inserted
 ve
 1. Insert in beginning
 2. Insert at last
 3. Insert at any random location
 4. Delete from Beginning
 5. Delete from last
 6. Delete the node after the given data
 7.	Search
 ni
 U
 8.	Display
 9.	Exit
 Enter your choice: 1
 ity
Node inserted
 1. Insert in beginning
 2. Insert at last
 m
Node inserted
 ity
 1. Insert in beginning
 2. Insert at last
 3. Insert at any random location
 4. Delete from Beginning
 5. Delete from last
 rs
 6. Delete the node after the given data
 7.	Search
 8.	Display
 ve
 9.	Exit
 Enter your choice: 8
 1
 ni
 Choose one option from the following list :
 U
 1. Insert in beginning
 2. Insert at last
 3. Insert at any random location
 ity
 9.	Exit
 Enter your choice: 2
 Enter value: 89
 )A
Node inserted
 1. Insert in beginning
 2. Insert at last
(c
 ity
 7.	Search
 8.	Display
 9.	Exit
 Enter your choice: 4
Node deleted
 rs
 Choose one option from the following list:
 1. Insert in beginning
 2. Insert at last
 ve
 3. Insert at any random location
 4. Delete from Beginning
 5. Delete from last
 6. Delete the node after the given data
 7.	Search
 8.	Display
 9.	Exit
 ni
 U
 Enter your choice: 8
 1
 ity
89
 1. Insert in beginning
 2. Insert at last
 3. Insert at any random location
 m
 7.	Search
 8.	Display
 9.	Exit
 Enter your choice: 9
(c
 ity
 3.3.1 Introduction to Circular Linked List
 Circular linked list is a linked list where all nodes are connected to form a circle
 i.e. the last node is connected to the first node. There is no NULL at the end. A circular
 linked list can be a singly circular linked list or doubly circular linked list. To understand
 the complete traversal we need to reach the first node again.
 rs
 Head
 2 5 7 8 10
 ve
 cll
 ni
 1. Any node can be a starting point. We can traverse the whole list by starting from any
 point. We just need to stop when the first visited node is visited again.
 2. Useful for implementation of queue. Unlike this implementation, we don’t need to
 U
 maintain two pointers for front and rear if we use circular linked list. We can maintain
 a pointer to the last inserted node and front can always be obtained as next of last.
 3. Circular lists are useful in applications to repeatedly go around the list. For example,
 when multiple applications are running on a PC, it is common for the operating
 system to put the running applications on a list and then to cycle through them,
 ity
 giving each of them a slice of time to execute, and then making them wait while the
 CPU is given to another application. It is convenient for the operating system to use
 a circular list so that when it reaches the end of the list it can cycle around to the front
 of the list.
 In a circular Singly linked list, the last node of the list contains a pointer to the first
 node of the list. We can have circular singly linked list as well as circular doubly linked
 list.
 )A
 We traverse a circular singly linked list until we reach the same node where we
 started. The circular singly liked list has no beginning and no ending. There is no null
 value present in the next part of any of the nodes.
Head
 ity
 circular list is being stored in the memory. The start or head of the list is pointing to the
 element with the index 1 and containing 13 marks in the data part and 4 in the next part.
 Which means that it is linked with the node that is being stored at 4th index of the list.
 However, due to the fact that we are considering circular linked list in the memory
 therefore the last node of the list contains the address of the first node of the list.
 rs
 start
 1
 Data Data
 1 13 4
 ve
 2
 3
 4 15 6
 5
 6 19 8
 7
 8 57
Insertion
Insertion at beginning
 There are two scenario in which a node can be inserted in circular singly linked
 ity
 list at beginning. Either the node will be inserted in an empty list or the node is to be
 inserted in an already filled list.
 Head
 temp
 old link
 m
 new link
 old link
 Firstly, allocate the memory space for the new node by using the malloc method of
 C language.
(c
 In the first scenario, the condition head == NULL will be true. Since, the list in
 Notes which, we are inserting the node is a circular singly linked list, therefore the only node of
 ity
 the list (which is just inserted into the list) will point to itself only. We also need to make
 the head pointer point to this node. This will be done by using the following statements.
If (head == NULL)
 rs
 head = ptr;
 ve
 In the second scenario, the condition head == NULL will become false which
 means that the list contains at least one node. In this case, we need to traverse the
 list in order to reach the last node of the list. This will be done by using the following
 statement.
temp = head;
 temp = temp->next;
 ni
 while(temp->next != head)
 At the end of the loop, the pointer temp would point to the last node of the list.
 U
 Since, in a circular singly linked list, the last node of the list contains a pointer to the
 first node of the list. Therefore, we need to make the next pointer of the last node point
 to the head node of the list and the new node which is being inserted into the list will
 be the new head node of the list therefore the next pointer of temp will point to the new
 node ptr. Which will be done by using temp -> next = ptr;
 ity
Algorithm
 Go to step 11
 m
[End of if]
 ity
 Insertion at the end
Steps:
 rs
 2. make node->next = last->next
 3. last-> next = node
 4. last = node
 ve
 Last
 Node T
 6 8 10
 ni
 U
 Steps:
 Last
 Node T
 12
 m
6 8 10
Deletion
 Deletion can be done in two ways. Deletion at the beginning and deletion at the
 end.
Steps:
 1. Define two pointers curr and prev if the node is not empty and initialize the
(c
 3. If the node is found, check if it is the only node in the list. If yes, set head = NULL
 Notes and free(curr).
 ity
 4. If the list has more than one node, check if it is the first node of the list ( curr ==
 head). If yes, then move prev until it reaches the last node. After prev reaches
 the last node, set head = head -> next and prev -> next = head. Delete curr.
 5. If curr is not the first node, check if it is the last node in the list (curr -> next ==
 head).
 rs
 6. If curr is the last node. Set prev -> next = head and delete the node curr using
 free(curr).
 7. If the node to be deleted is neither the first node nor the last node, then set prev
 -> next = temp -> next and delete curr.
 ve
 Searching
 We need to compare each element of the node with the given node and return the
 location at which the node is present otherwise return null.
Traverse
specific operation.
 Example:
 ni
 Traversing means visiting each and every element of the list to perform some
 U
 #include<stdio.h>
#include<stdlib.h>
struct node
 {
 ity
int data;
};
void begindelete();
void lastdelete();
void random_delete();
void display();
 void search();
(c
void main ()
 ity
 while(choice != 7)
 rs
 printf(“\nEnter your choice:\n”);
scanf(“\n%d”,&choice);
switch(choice)
 ve
 {
case 1:
begininsert();
 ni
 break;
case 2:
 lastinsert();
 U
 break;
case 3:
begindelete();
 break;
 ity
case 4:
lastdelete();
break;
 case 5:
 m
search();
break;
 case 6:
 )A
display();
break;
case 7:
 exit(0);
(c
break;
default:
 ity
 }
void begininsert()
 rs
 {
int item;
 ve
 ptr = (struct node *)malloc(sizeof(struct node));
if(ptr == NULL)
printf(“\nOVERFLOW”);
else
 {
 ni
 U
 printf(“\nEnter the node value:”);
scanf(“%d”,&item);
if(head == NULL)
head = ptr;
else
 {
 )A
temp = head;
while(temp->next != head)
temp = temp->next;
ptr->next = head;
head = ptr;
 printf(“\nNode inserted\n”);
 Notes
 ity
 }
void lastinsert()
 rs
 struct node *ptr,*temp;
int item;
 ve
 if(ptr == NULL)
printf(“\nOVERFLOW\n”);
else
 printf(“\nEnter Data:”);
 ni
 U
 scanf(“%d”,&item);
ptr->data = item;
 if(head == NULL)
 ity
head = ptr;
 }
 m
else
 temp = head;
 )A
 printf(“\nNode inserted\n”);
 Notes
 ity
 }
void begindelete()
 rs
 struct node *ptr;
if(head == NULL)
 ve
 printf(“\nUNDERFLOW”);
head = NULL;
 free(head);
 ni
 printf(“\nNode deleted\n”);
 U
 }
else
 { ptr = head;
 ity
ptr->next = head->next;
 free(head);
 m
head = ptr->next;
printf(“\nNode deleted\n”);
 }
 )A
void lastdelete()
 if(head==NULL)
(c
printf(“\nUNDERFLOW”);
 }
 Notes
 ity
 else if (head ->next == head)
head = NULL;
free(head);
 rs
 printf(“\nNode deleted\n”);
else
 ve
 {
ptr = head;
 }
 preptr=ptr;
 ptr = ptr->next;
 ni
 U
 preptr->next = ptr -> next;
free(ptr);
 printf(“\nNode deleted\n”);
 ity
void search()
 {
 m
int item,i=0,flag=1;
 ptr = head;
 )A
if(ptr == NULL)
printf(“\nEmpty List\n”);
 else
(c
 scanf(“%d”,&item);
 Notes
 ity
 if(head ->data == item)
flag=0;
 rs
 }
else
 ve
 while (ptr->next != head)
if(ptr->data == item)
flag=0;
 break;
 ni
 printf(“Item found at location %d “,i+1);
 U
 }
else
 {
 ity
flag=1;
i++;
 if(flag != 0)
 )A
 }
(c
void display()
 ity
 ptr=head;
if(head == NULL)
printf(“\nNothing to display.”);
 rs
 }
else
 ve
 printf(“\n The list is : \n”);
 }
 ity
Output:
 1. Insert in beginning
 2. Insert at end
 3. Delete from beginning
 4. Delete from end
 )A
Node inserted
 1. Insert in beginning
 Notes
 ity
 2. Insert at end
 3. Delete from beginning
 4. Delete from end
 5. Search for an element
 6.	Display
 rs
 7.	Exit
 Enter your choice: 1
 ve
 Node inserted
 1. Insert in beginning
 2. Insert at end
 3. Delete from beginning
 4. Delete from end
 5. Search for an element
 ni
 U
 6.	Display
 7.	Exit
 Enter your choice: 1
 ity
Node inserted
 1. Insert in beginning
 2. Insert at end
 m
 6.	Display
 7.	Exit
 Enter your choice: 4
 Node deleted
(c
 1. Insert in beginning
 2. Insert at end
 Amity Directorate of Distance & Online Education
 Data Structure Using C 107
 ity
 4. Delete from end
 5. Search for an element
 6.	Display
 7.	Exit
 Enter your choice: 5
 rs
 Enter item which you want to search
20
 ve
 Choose one option from the following list:
 1. Insert in beginning
 2. Insert at end
 3. Delete from beginning
 4. Delete from end
 5. Search for an element
 6.	Display
 ni
 U
 7.	Exit
 Enter your choice: 7
 ity
 m
 )A
(c
 ity
 A generalized list, A. is a finite sequence of elements. (b.c)): a list of length two; its
 first element is the atom a. and its second element is the linear list (b,c). (3) B = (A.A. ())
 a list of length three whose first two elements are the list A. and the third element is the
 null list. A generalized linked list encompasses structures or elements with everyone
 containing its own pointer. It’s generalized if the list can have any deletions, insertions,
 and similar inserted effectively into it.
 rs
 A generalized list L is a finite sequence of n elements (n ≥ 0). The element ei is
 either an atom (single element) or another generalized list. The elements ei that are
 not atoms, they will be sub-list of L. Suppose L is ((A, B, C), ((D, E), F), G). Here L has
 three elements sub-list (A, B, C), sub-list ((D, E), F), and atom G. Again sub-list ((D, E),
 ve
 F) has two elements one sub-list (D, E) and atom F.
 ni
 U
 ity
 m
 )A
(c
 ity
 3.5.1 Applications of Linked List-Polynomial Representation Using
 Linked list and Basic Operation
 To represent a polynomial of any degree we can use the linked list. If a single
 rs
 variable is used, the information field node contains two parts. One coefficient of
 variable and the other for degree of variable. A polynomial can be represented
 in an array or in a linked list by simply storing the coefficient and exponent of each
 term. However, for any polynomial operation , such as addition or multiplication of
 polynomials , you will find that the linked list representation is more easier to deal with.
 ve
 It would be very easy to represent the polynomial using a linked list structure, where
 each node can hold information pertaining to a single term of the polynomial. Each
 node will need to store the variable x, the exponent and the coefficient for each term.
 It often does not matter whether the polynomial is in x or y. This information may not
 be very crucial for the intended operations on the polynomial. Thus we need to define
 a node structure to hold two integers, exp and cof. Compare this representation with
 ni
 storing the same polynomial using an array structure. In the array we have to have keep
 a slot for each exponent of x, thus if we have a polynomial of order 50 but containing
 just 6 terms, then a large number of entries will be zero in the array. You will also see
 that it would be also easy to manipulate a pair of polynomials if they are represented
 U
 using linked lists.
Example:
ROOT
3 3 -4 2 2 1 -9 0
 In the above example, the external pointer ROOT point to the first node of the
 m
 linked list. The first node of the linked list contains the data of the variable with highest
 degree. First node points to the next node with lower degree of variable. When we need
 to do operations such as addition or subtraction then representation of a polynomial
 using linked list is beneficial.
 )A
Example:
Input:
Output:
5x2-1x1-3x0
 Input:
 Amity Directorate of Distance & Online Education
 110 Data Structure Using C
 ity
 2nd number = 5x^1 - 5x^0
Output:
 rs
 List 1 5 2 4 1 2 0 NULL
List 2 5 1 5 0 NULL
Resultant List
 ve
 5 2 9 1 7 0 NULL
 NODE Address of
 STRUCTURE Coefficient Power
 next node
Example:
#include <stdio.h>
 #include <stdlib.h> ni
 U
 #include <string.h>
struct node
 int cof;
 ity
int exp;
};
int i, n;
if (scanf(“%d”, &n) != 1)
 ity
 {
if (ptr == 0)
 rs
 printf(“enter the coefficient and exponent respectively: “);
 ve
 ptr->link = NULL;
q = insert(ptr, q);
 }
 return q;
 if (p == NULL)
 ity
p = ptr;
else
 display(“insert: p = “, p);
 m
 {
 )A
ptr->link = p;
p = ptr;
else
 {
(c
temp = p;
 ity
 temp = temp->link;
b = temp->link;
temp->link = ptr;
 rs
 ptr->link = b;
 ve
 return p;
 temp = ptr;
 ni
 U
 printf(“%s: “, tag);
 {
 ity
temp = temp->link;
pad = “ + “;
 }
 m
putchar(‘\n’);
 int main(void)
 )A
p1 = create(p1);
p2 = create(p2);
display(“p1”, p1);
 display(“p2”, p2);
 Notes
 ity
 return 0;
 rs
 fprintf(stderr, “%s\n”, tag);
exit(1);
 ve
 3.5.2 Stack and Queue Implementation Using Linked List
 Implement a stack applying single linked list concept. all the single linked list
 operations operate based on Stack operations LIFO(last in first out) and with the help
 of that knowledge we are going to implement a stack using single linked list. By means
 of single linked lists means what we are storing the information in the form of nodes
 ni
 and we need to follow the stack rules and we need to implement using single linked list
 nodes so what are the rules we need to follow in the implementation of a stack a simple
 rule that is last in first out and all the operations we should perform so with the help of a
 top variable only with the help of top variables are how to insert the elements let’s see
 U
 A stack can be simply implemented through the linked list. In stack Implementation,
 a stack includes a top pointer which is “head” of the stack where pushing and popping
 items occurs at the head of the list. first node has null in link field and second node link
 have first node address in link field and so on and last node address in “top” pointer.
 ity
 The main advantage of using linked list over an array is that it is feasible to
 implements a stack that can shrink or grow as much as needed. In using array will put
 a limitation to the maximum capacity of the array which can lead to stack overflow. Here
 each new node will be dynamically allocated, so, overflow is not possible.
 Stack Operations:
 m
 1. push() : Insert the element into linked list nothing but which is the top node of
 Stack.
 2. pop() : Return top element from the Stack and move the top pointer to the
 second node of linked list or Stack.
 )A
#include <stdio.h>
 int MAXSIZE = 8;
(c
int stack[8];
 int isempty() {
 Notes
 ity
 if(top == -1)
return 1;
else
return 0;
 rs
 }
int isfull() {
if(top == MAXSIZE)
 ve
 return 1;
else
return 0;
int peek() {
 }
 return stack[top];
 ni
 U
 int pop() {
int data;
 if(!isempty()) {
 ity
data = stack[top];
top = top - 1;
return data;
 } else {
 m
 }
 )A
if(!isfull()) {
top = top + 1;
stack[top] = data;
 } else {
(c
 }
 Notes
 ity
 int main() {
push(3);
push(5);
 rs
 push(9);
push(1);
push(12);
 ve
 push(15);
printf(“Elements: \n”);
while(!isempty()) {
 printf(“%d\n”,data);
 ni
 U
 }
return 0;
If we compile and run the above program, it will produce the following result:
 Output:
 m
Elements:
 15
 )A
12
 3
(c
 In a linked queue, every single node of the queue comprises of two parts i.e. data
 Notes part and the link part. Each element of the queue points to its immediate next element
 ity
 in the memory.
 In the linked queue, there are two pointers preserved in the memory i.e. front
 pointer and rear pointer. The front pointer contains the address of the starting element
 of the queue while the rear pointer comprises the address of the last element of the
 queue.
 rs
 Insertion and deletions are completed at rear and front end respectively. If front and
 rear both are NULL, it signifies that the queue is empty. The linked representation of
 queue is shown in the following figure.
 ve
 9 1 7 4
front rear
 There are two basic operations which can be employed on the linked queues.
 The operations are Insertion and Deletion.The insert operation appends the queue by
the queue.
 ni
 adding an element to the end of the queue. The new element will be the last element of
 Firstly, allocate the memory for the new node ptr by using the following statement.
 U
 1. Ptr = (struct node *) malloc (sizeof(struct node));
 we insert element into an empty queue. In this case, the condition front = NULL
 becomes true. Now, the new element will be included as the only element of the queue
 and the subsequent pointer of front and rear pointer both, will point to NULL.
 ity
if(front == NULL)
front = ptr;
 rear = ptr;
 m
Algorithm
 ELSE
 Amity Directorate of Distance & Online Education
 Data Structure Using C 117
 ity
 SET REAR = PTR
[END OF IF]
 ●● Step 4: END
 Deletion
 rs
 Deletion operation eliminates the element that is first inserted among all the queue
 elements. Initially it is required to check either the list is empty or not. The condition
 front == NULL becomes true if the list is empty, in this case, we simply write underflow
 on the console and make exit.
 ve
 Else, we will delete the element that is pointed by the pointer front. For this
 purpose, copy the node pointed by the front pointer into the pointer ptr. Now, shift the
 front pointer, point to its next node and free the node pointed by the node ptr. This is
 done by using the following statements.
 ni
 ptr = front;
 free(ptr);
 U
 Algorithm
 Go to Step 5
 ity
[END OF IF]
 ●● Step 5: END
 )A
 Assignment I
 Use the following Node definition for all problems:
(c
struct Node
 Item data;
 Notes
 ity
 Node *link;
 1. Write a function to concatenate two linked lists. Given lists l1 = (2, 3, 1) and l2 = (4,
 5), after return from concatenate(l1,l2) the list l1 should be changed to be l1 = (2, 3,
 1, 4, 5). Your function should not change l2 and should not directly link nodes from l1
 rs
 to l2 (i.e. the nodes inserted into l1 should be copies of the nodes from l2.)
 void concatenate(Node*& h1, Node* h2 );
 ve
 // Postcondition: A copy of list h2 is concatenated (added to the end)
 ni
 2. Write a function to insert a number into a sorted linked list. Assume the list is sorted
 from smallest to largest value. After insertion, the list should still be sorted. Given the
 list l1 = (3, 17, 18, 27) and the value 20, on return l1 be the list (3, 17, 18, 20, 27).
 U
 void insertInOrder(Node*& head_ptr, int value);
 3. Write a function to return the median value in a sorted linked list. If the length i of the
 list is odd, then the median is the ceiling(i/2) member. For example, given the list (1,
 2, 2, 5, 7, 9, 11) as input, your function should return the value 5. If the length of the
 m
 list is even, then the median is the mean of the i/2 and (i/2)+1 members. Thus, the
 median of the sorted list (2, 4, 8, 9) is (4+8)/2. Finally, define the median of an empty
 list to be 0.
 FILL IN RETURN TYPE listMedian ---- FILL IN ARGUMENTS -------------------
 )A
 4. Write a function to reverse the nodes in a linked list. Your function should have time
 complexity O(n), where n is the length of the list. You should create no new nodes.
 void reverse(Node*& head_ptr);
(c
 ity
 // order.
 rs
 #include <stdio.h>
#include <stdlib.h>
 ve
 // A Linked List Node
struct Node
int data;
};
while (ptr)
 ptr = ptr->next;
 m
printf(“NULL\n”);
 }
 )A
// Helper function to insert a new node at the beginning of the linked list
 newNode->data = data;
(c
newNode->next = *head;
*head = newNode;
 }
 Notes
 ity
 // Reverses a given linked list by changing its `.next` pointers and
 rs
 struct Node* previous = NULL; // the previous pointer
 ve
 while (current != NULL)
 previous = current;
 ni
 current->next = previous; // fix the current node
 U
 current = next;
*head = previous;
int main(void)
 {
 m
// input keys
int keys[] = { 1, 2, 3, 4, 5, 6 };
 int n = sizeof(keys)/sizeof(keys[0]);
 )A
push(&head, keys[i]);
 }
(c
reverse(&head);
printList(head);
 return 0;
 Notes
 ity
 }
 Questions
 1. In a circular linked list
 a) Components are all linked together in some sequential manner.
 rs
 b) There is no beginning and no end.
 c) Components are arranged hierarchically.
 d) Forward and backward traversal within the list is permitted.
 2. Which of the following operations is performed more efficiently by doubly linked list
 ve
 than by singly linked list?
 a) Deleting a node whose location in given
 b) Searching of an unsorted list for a given item
 c) Inverting a node after the node with given location
 3.
 d) Traversing a list to process each node
 ni
 A linear collection of data elements where the linear node is given by means of
 pointer is called?
 U
 a) linked list
 b) node list
 c) primitive list
 d) None of these
 ity
 d) Binary search
 5. Which of these is an application of linked lists?
 a) To implement file systems
 )A
 b) Two pointer
 c) Three pointer
 d)	None
 ity
 a) To implement file systems
 b) For separate chaining in hash-tables
 c) To implement non-binary trees
 d) Random Access of elements
 8. A linear collection of data element given by mean of pointer is called
 rs
 a)	Queue
 b) Linked list
 c)	Graph
 ve
 d)	Stack
 9. Which of the following operation is performed more efficiently in doubly linked list?
 a) Searching a node at given position
 b) Inserting a node at given position
 d) None of these
 ni
 c) Deleting node at given position
 Answer key:
 1. b, 2. a, 3. a, 4. d, 5. d, 6. b, 7. d, 8. b, 9. c, 10. d
 m
 )A
(c
 ity
 Structure:
 rs
 4.1.2 Basic Terminology
 ve
 4.2.2 Expression Evaluation
 4.2.3 Complete Binary trees
 4.2.4 Extended Binary Trees
 4.2.5 Traversing Binary Trees
 ni
 4.2.6 Searching, Insertion and Deletion in Binary Search Trees
 Unit-4.4: Graph
 ity
 4.4.1 Introduction
 4.4.2 Graph Theory Terminology
 4.4.3 Sequential Representation of Graph (Adjacency and Path Matrix)
 4.4.4 Warshall Algorithms
 m
 ity
 4.1.1 Introduction to Trees
 Tree is a hierarchical data structure which stores the information naturally in the
 form of ladder style. Tree is one of the most effective and advanced data structures. It is
 a non-linear data structure compared to arrays, linked lists, stack and queue. It signifies
 the nodes connected by edges.
 rs
 Root A
 Subtree Edge
 B C
 Siblings
 ve
 Child
 Node
 Leaf
 D E F Node G
 ni
 The above figure represents structure of a tree. Tree has 2 subtrees. A is a parent
 of B and C. B is called a child of A and also parent of D, E, F. Tree is a collection of
 elements called Nodes, where each node can have arbitrary number of children.
 U
 4.1.2 Basic Terminology
 Field Description
 Root
 it. It does not have a parent.
Height of Tree Height of tree represents the height of its root node.
 Depth of a node represents the number of edges from the tree’s root
 Depth of Node
 node to the node.
 Degree of
 Degree of a node represents a number of children of a node.
 Node
(c
 ity
 4.2.1 Binary Trees and Their Representation
 Binary Tree is a unique data structure used for data storage. Binary tree has at
 most 2 children. Hence the name binary tree. The topmost node is called root and the
 nodes that are under the root node are called its children. The node directly above
 another node is called as parent.
 rs
 Binary Tree is a unique data structure used for data storage reasons . A tree whose
 elements have at most 2 children is called a binary tree. Since each element in a binary
 tree can have only 2 children, we typically name them the left and right child.
 ve
 Root
A Level 0
B C Level 1
Child Node H
 Sub-tree
 I J
 Leaf Node
 ni Level 3
 U
 Fig4.2 : Binary tree
 1.	Data
 ity
27
 14 35
 )A
10 19 31 42
 The basic operations that can be completed on a binary search tree data structure,
 are the following:
 ity
 Example:
#include<stdlib.h>
#include<stdio.h>
struct bin_tree {
 rs
 int data;
};
 ve
 typedef struct bin_tree node;
 ni
 node *temp = NULL;
if(!(*tree))
 {
 U
 temp = (node *)malloc(sizeof(node));
temp->data = val;
 *tree = temp;
 ity
return;
 {
 m
insert(&(*tree)->left, val);
insert(&(*tree)->right, val);
 }
(c
 if (tree)
 Notes
 ity
 {
printf(“%d\n”,tree->data);
print_preorder(tree->left);
print_preorder(tree->right);
 rs
 }
 ve
 {
if (tree)
print_inorder(tree->left);
printf(“%d\n”,tree->data);
print_inorder(tree->right);
 }
 ni
 U
 }
 {
 ity
if (tree)
print_postorder(tree->left);
 print_postorder(tree->right);
 m
printf(“%d\n”,tree->data);
 }
 )A
if (tree)
 deltree(tree->left);
(c
deltree(tree->right);
free(tree);
 }
 Notes
 ity
 }
if(!(*tree))
 rs
 {
return NULL;
 ve
 if(val < (*tree)->data)
search(&((*tree)->left), val);
 search(&((*tree)->right), val);
 ni
 U
 }
 {
 ity
return *tree;
 void main()
 m
node *root;
 node *tmp;
 )A
root = NULL;
insert(&root, 9);
insert(&root, 4);
 insert(&root, 15);
(c
insert(&root, 6);
insert(&root, 12);
 insert(&root, 17);
 Notes
 ity
 insert(&root, 2);
print_preorder(root);
 rs
 printf(“In Order Display\n”);
print_inorder(root);
 ve
 print_postorder(root);
if (tmp) {
else
 ni
 U
 }
 deltree(root); }
 ity
Output:
 4
 m
 15
 )A
12
17
In Order Display
 4
(c
 12
 Notes
 ity
 15
17
 rs
 6
12
 ve
 17
15
Searched node=4
 ni
 Evaluate an expression represented by a String. The expression can contain
 parentheses, you can assume parentheses are well-matched. For simplicity, you can
 U
 assume only binary operations allowed are +, -, *, and /. Arithmetic Expressions can be
 written in one of three forms:
Infix Notation: Operators are written between the operands on, e.g. 3+4.
 2 3
(c
4 5 6
 ity
 Select the first element of the list to be the root node. (no. of elements on level-I: 1)
1 1 12 9 5 6 10
Put the second element as a left child of the root node and the third element as the
 rs
 right child. (no. of elements on level-II: 2)
 1
 1 12 9 5 6 10
 ve
 12 9
 Put the next two elements as children of the left node of the second level. Again, put the
 next two elements as children of the right node of the second level (no. of elements on
 level-III: 4) elements).
 ni
 Keep repeating until you reach the last element.
 1
 U
 12 9 1 12 9 5 6 10
 5 6 10
 ity
Example:
#include <stdbool.h>
 #include <stdio.h>
 m
#include <stdlib.h>
struct Node {
 int key;
 )A
};
// Node creation
node->key = k;
 return node;
 Notes
 ity
 }
if (root == NULL)
 rs
 return (0);
 ve
 // Check if the tree is a complete binary tree
if (root == NULL)
return true;
 return false;
 ni
 U
 return (checkComplete(root->left, 2 * index + 1, numberNodes) &&
 checkComplete(root->right, 2 * index + 2, numberNodes));
 int main() {
 ity
root = newNode(1);
root->left = newNode(2);
 root->right = newNode(3);
 m
root->left->left = newNode(4);
root->left->right = newNode(5);
 root->right->left = newNode(6);
 )A
int index = 0;
else
 }
 Notes
 ity
 4.2.4 Extended Binary trees
 Extended binary tree is a type of binary tree in which all the null sub tree of the
 original tree are replaced with special nodes called external nodes whereas other nodes
 are called internal nodes
 rs
 1
2 3
5 4
 ve
 Fig 4.4 : Extended Binary tree
 Here the circles represent the internal nodes and the boxes represent the external
 nodes.
 ni
 1. The nodes from the original tree are internal nodes and the special nodes are
 external nodes.
 U
 2. All external nodes are leaf nodes and the internal nodes are non-leaf nodes.
 3. Every internal node has exactly two children and every external node is a leaf.
 It displays the result which is a complete binary tree
 Below is an example of making an extended binary tree in C++ by making all the
 ity
 every node in the tree exactly once is called an enumeration of the tree’s nodes. Some
 applications do not require that the nodes be visited in any particular order as long as
 each node is visited precisely once. For other applications, nodes must be visited in an
 order that preserves some relationship.
 )A
 Tree traversal is the process of visiting each node in the tree exactly once. Visiting
 each node in a graph should be done in a systematic manner. If search result in a visit
 to all the vertices, it is called a traversal. There are basically three traversal techniques
 for a binary tree that are,
 1. Pre-order traversal
(c
 2. In-order traversal
 3. Post-order traversal
 1) Pre-order traversal
 Notes
 ity
 To traverse a binary tree in pre-order, following operations are carried out:
 rs
 2) Inorder traversal
 To traverse a binary tree in in-order traversal, following operations are carried out:
 ve
 b. Visit the root.
 c. Traverse the right most sub tree.
 3) Postorder traversal
 To traverse a binary tree in postorder traversal, following operations are carried out:
 ni
 a. Traverse the left sub tree of root.
 b. Traverse the right sub tree of root.
 c. Visit the root.
 U
 Example:
 Consider the below figure and let us understand the program of In-order, Pre-order
 and Post-order traversal.
 ity
2 3
 4 5
 m
#include <stdio.h>
 #include <stdlib.h>
 )A
/* A binary tree node has data, pointer to left child and a pointer to right child */
struct node
int data;
};
 /* function that allocates a new node with the given data and NULL left and right
 pointers. */ Notes
 ity
 struct node* newNode(int data)
malloc(sizeof(struct node));
 rs
 node->data = data;
node->left = NULL;
node->right = NULL;
 ve
 return(node);
 /* Given a binary tree, print its nodes according to the “bottom-up” post-order
 traversal. */
 if (node == NULL)
 ni
 U
 return;
postorder(node->left);
 postorder(node->right);
 ity
printf(“%d “, node->data);
if (node == NULL)
 return;
 )A
inorder(node->left);
printf(“%d “, node->data);
inorder(node->right);
 }
(c
if (node == NULL)
 return;
 Notes
 ity
 printf(“%d “, node->data);
preorder(node->left);
preorder(node->right);
 rs
 int main()
 ve
 root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
 preorder(root);
 ni
 printf(“\nPre-order traversal of binary tree is: “);
 postorder(root);
 ity
getchar();
return 0;
 Output:
 m
 The value of the key of the left sub-tree is less than the value of its parent (root)
 node’s key.
(c
 The value of the key of the right sub-tree is greater than or equal to the value of its
 parent (root) node’s key.
 Search Operation
 Notes
 ity
 Whenever an element is to be searched, start searching from the root node. Then if
 the data is less than the key value, search for the element in the left subtree. Otherwise,
 search for the element in the right subtree. Follow the same algorithm for each node.
Algorithm:
 rs
 struct node *current = root;
while(current->data != data){
 ve
 if(current != NULL) {
printf(“%d “,current->data);
current = current->leftChild;
 else {
 ni
 U
 current = current->rightChild;
 //not found
 ity
if(current == NULL){
return NULL;
 }
 m
return current;
 }
 )A
Insert Operation
 Deletion
 Notes
 ity
 Delete function is used to delete the specified node from a binary search tree.
 However, we must delete a node from a binary search tree in such a way, that the
 property of binary search tree doesn’t violate. There are three situations of deleting a
 node from binary search tree.
 It is the simplest case, in this case, replace the leaf node with the NULL and simple
 free the allocated space.
 rs
 In the following image, we are deleting the node 85, since the node is a leaf node,
 therefore the node will be replaced with NULL and allocated space will be freed.
 ve
 50 and free the node 50
 Delete
 25 75 25 75
 node 85
 12 30 60 85 12 30 60 85
 Delete node
 52 70 52 70
 In this case, replace the node with its child and delete the child node, which now
 contains the value which is to be deleted. Simply replace it with the NULL and free the
 U
 allocated space.
 In the following image, the node 12 is to be deleted. It has only one child. The node
 will be replaced with its child node and the replaced node 12 (which is now leaf node)
 will simply be deleted.
 ity
 Delete 25 75 25 75
 node 12
 12 30 60 12 30 60
 m
 52 70 52 70
 6 12
 Delete node
Algorithm
 1. Define Node which has three attributes namely: data, left and right where left
 represents the left child of the node and right represents the right child of the
 node.
 2. When a node is created, data will pass to the data attribute of the node and both
(c
 4. insert() will insert the new value into a binary search tree:
 Notes
 ity
 It checks whether root is null, which means tree is empty. New node will become
 root node of tree.
 a. If tree is not empty, it will compare value of new node with root node. If
 value of new node is greater than root, new node will be inserted to right
 subtree. Else, it will be inserted in left subtree.
 5. deleteNode() will delete a particular node from the tree:
 rs
 a. If value of node to be deleted is less than root node, search node in left
 subtree. Else, search in right subtree.
 b. If node is found and it has no children, then set the node to null.
 ve
 c. If node has one child then, child node will take position of node.
 d. If node has two children then, find a minimum value node from its right
 subtree. This minimum value node will replace the current node.
 Example:
#include <stdio.h>
#include <stdlib.h>
 #include <stdbool.h> ni
 U
 struct node{
int data;
};
newNode->data= data;
 newNode->left = NULL;
 )A
newNode->right = NULL;
return newNode;
 if(root == NULL){
 Notes
 ity
 root = newNode;
return;
else {
 rs
 struct node *current = root, *parent = NULL;
while(true) {
parent = current;
 ve
 if(data < current->data) {
current = current->left;
if(current == NULL) {
parent->left = newNode;
 }
 }
 return;
 ni
 U
 else {
current = current->right;
 if(current == NULL) {
 ity
parent->right = newNode;
return;
} } } } }
if (root->left != NULL)
 return minNode(root->left);
 )A
else
return root;
//deleteNode() will delete the given node from the binary search tree
if(node == NULL){
return NULL;
 }
 Notes
 ity
 else {
 rs
 node->right = deleteNode(node->right, value);
else {
 ve
 node = NULL;
node = node->right;
 }
 node = node->left;
 ni
 U
 else {
 node->data = temp->data;
 ity
 return node;
 m
if(root == NULL){
printf(“Tree is empty\n”);
 return;
(c
else {
 if(node->left!= NULL)
 Notes
 ity
 inorder(node->left);
printf(“%d “, node->data);
if(node->right!= NULL)
inorder(node->right);
 rs
 }
int main()
 ve
 {
insert(5);
insert(3);
insert(7);
insert(6);
 insert(1);
 ni
 U
 insert(9);
inorder(root);
inorder(root);
inorder(root);
inorder(root);
 return 0;
 Notes
 ity
 }
Output:
135679
 rs
 Binary search tree after deleting node 9:
13567
 ve
 1567
167
 ni
 U
 ity
 m
 )A
(c
 ity
 4.3.1 General Trees
 General tree is a tree in which every node can have either zero or many child
 nodes. It cannot be empty. In general tree, there is no limitation on the degree of a
 node. The topmost node of a general tree is termed the root node. There are several
 subtrees in a general tree. The subtree of a general tree is unordered since the nodes
 rs
 of the general tree cannot be ordered according to specific criteria. In a general
 tree, each node has in-degree(number of parent nodes) one and maximum out-
 degree(number of child nodes) n.
 ve
 ni
 Fig 4.7 : General tree
 U
 4.3.2 AVL Tree
 AVL tree is a self-balancing binary search tree in which each node maintains extra
 information called a balance factor whose value is either -1, 0 or +1.
 ity
 Balance factor of a node in an AVL tree is the difference between the height of the
 left subtree and that of the right subtree of that node.
 The self balancing property of an avl tree is maintained by the balance factor. The
 m
 -1 -1
 9 53
 0 1 0
 8 21 61
 0
(c
11
 ity
 Rotating the subtrees in an AVL Tree
Left Rotate
In left-rotation, the arrangement of the nodes on the right is transformed into the
 rs
 arrangements on the left node.
Algorithm:
 ve
 Ρ
 X
 α
 Y
 β
 ni γ
 1. If y has a left subtree, assign x as the parent of the left subtree of y.
 Ρ
 U
 X
 α β Y
 ity
 γ
 2. If the parent of x is NULL, make y as the root of the tree.
 3. Else if x is the left child of p, make y as the left child of p.
 4. Else assign y as the right child of p.
 Ρ
 m
 X Y
 α β γ
 )A
 Y
 X γ
(c
 α β
 Right Rotate
 In left-rotation, the arrangement of the nodes on the left is transformed into the
 Notes arrangements on the right node.
 ity
 1. Let the initial tree be:
 Ρ
 rs
 X α
 γ β
 2. If x has a right subtree, assign y as the parent of the right subtree of x.
 Ρ
 ve
 Y
 X β α
 γ
 ni
 3. If the parent of y is NULL, make x as the root of the tree.
 4. Else if y is the right child of its parent p, make x as the right child of p.
 5. Else assign x as the left child of p.
 U
 Ρ
 X Y
 γ β α
 ity
 X
 γ Y
 m
β α
 We know that the binary tree nodes may have at most two children. But if they
 have only one children, or no children, the link part in the linked list representation
 remains null. Using threaded binary tree representation, we can reuse that empty links
 by making some threads.
 If one node has some vacant left or right child area, that will be used as thread.
 There are two types of threaded binary tree. The single threaded tree or fully threaded
(c
 binary tree. In single threaded mode, there are another two variations. Left threaded
 and right threaded.
 In the left threaded mode if some node has no left child, then the left pointer will
 point to its in-order predecessor, similarly in the right threaded mode if some node has Notes
 ity
 no right child, then the right pointer will point to its in-order successor.
 For fully threaded binary tree, each node has five fields. Three fields like normal
 binary tree node, another two fields to store Boolean value to denote whether link of
 that side is actual link or thread.
 Header
 rs
 56
23 89
20 30 85
12
 ve
 These are the examples of left and right threaded tree
 Header
56
23 89
 ni
 20 30 85
12
56
23 89
 20 30 85
 ity
12
 4.3.4 B Trees
 A B-tree is a tree data structure that keeps data sorted and allows searches,
 insertions, and deletions in logarithmic amortized time. Unlike self-balancing binary
 search trees, it is optimized for systems that read and write large blocks of data. It is
 m
 The set formulation of the B-tree rules: Every B-tree depends on a positive
 constant integer called MINIMUM, which is used to determine how many elements are
 held in a single node.
 ●● Rule 1: The root can have as few as one element (or even no elements if it
 also has no children); every other node has at least MINIMUM elements.
 ●● Rule 2: The maximum number of elements in a node is twice the value of
(c
 MINIMUM.
 ●● Rule 3: The elements of each B-tree node are stored in a partially filled array,
 sorted from the smallest element (at index 0) to the largest element (at the
 ity
 than the number of elements in the node.
 o Subtree 0, subtree 1, ...
 rs
 2. An element at index i is less than all the elements in subtree number i + 1
 of the node.
 ●● Rule 6: Every leaf in a B-tree has the same depth. Thus it ensures that a
 ve
 B-tree avoids the problem of a unbalanced tree.
93, 107
 ni
 Subtree 0 Subtree 1 Subtree 2
 6
 U
 2, 4 9
 1 3 5 7, 8 10
 ity
 MINIMUM = 1
 m
 )A
(c
 Unit-4.4: Graph
 Notes
 ity
 4.4.1 Introduction
 A Graph is a non-linear data structure containing of nodes and edges. The nodes
 are occasionally also mentioned to as vertices and the edges are lines or arcs that
 connect any two nodes in the graph.
 rs
 4.4.2 Graph Theory Terminology
 A Graph comprises of a finite set of vertices(or nodes) and set of Edges which
 connect a pair of nodes. A graph G consists of two sets
 ve
 ●● a finite, nonempty set of vertices V(G)
 ●● a finite, possible empty set of edges E(G)
 ●● G(V,E) represents a graph
 An undirected graph is one in which the pair of vertices in a edge is unordered, (v0,
 v1) = (v1,v0)
!= <v1,v0>
 0 1
 ni
 A directed graph is one in which each edge is a directed pair of vertices, <v0, v1>
 U
 Edge 2
 4 3
 Vertices
 ity
 In the above Graph, the set of vertices V = {0,1,2,3,4} and the set of edges E = {01,
 12, 23, 34, 04, 14, 13}.
 To represent networks Graphs are used. The networks may include paths in a city
 or telephone network or circuit network. Graphs are also utilized in social networking
 m
sites.
 ity
 as shown in the following image. Here AB can be represented as 1 at row 0,
 column 1, BC as 1 at row 1, column 2 and so on, keeping other combinations
 as 0.
 ●● Adjacency − Two node or vertices are adjacent if they are connected to
 each other through an edge. In the following example, B is adjacent to A, C is
 adjacent to B, and so on.
 rs
 ●● Path − Path represents a sequence of edges between the two vertices. In the
 following example, ABCD represents a path from A to D.
 ve
 0 A
1 B 4 E 5 F
 2 C
 ni 6 G
 U
 3 D
 Basic Operations
 ity
 Matrix)
 The following two are the most commonly used representations of a graph.
 1. Adjacency Matrix
 )A
 2. Adjacency List
 Let us take an undirected graph:
(c
0 1 Notes
 ity
 2
4 3
 rs
 1. Adjacency Matrix:
 Adjacency Matrix is a 2D array of size Vertex x Vertex.
 ve
 ●● The adjacency matrix of G is a two-dimensional n by n array, say adj_mat
 ●● If the edge (vi, vj) is in E(G), adj_mat[i][j]=1
 ●● If there is no such edge in E(G), adj_mat[i][j]=0
 ●● The adjacency matrix for an undirected graph is symmetric; the adjacency
 matrix for a digraph need not be symmetric.
 ni
 Adjacency Matrix is a 2D array of size Vertex x Vertex. Let the 2D array be adj_
 mat[][], a slot adj_mat[i][j] = 1 indicates that there is an edge from vertex i to vertex j.
 Adjacency matrix for undirected graph is always symmetric. Adjacency Matrix is also
 used to represent weighted graphs. If adj_mat[i][j] = w, then there is an edge from
 U
 vertex i to vertex j with weight w.
0 1 2 3 4
 0 0 1 0 0 1
 ity
1 1 0 1 1 1
2 0 1 0 1 0
3 0 1 1 0 1
 4 1 1 0 1 0
 m
 2. Adjacency List
 )A
 For this, an array of lists is used. The size of the array is equal to the number of
 vertices. Let the array be arr[] and arr[i] represents the list of vertices adjacent to the ith
 vertex. To represent a weighted graph, the same representation can also be used. The
 weights of edges can be represented as lists of pairs. Following is the adjacency list
 representation of the above graph.
(c
Notes 0 1 4 /
 ity
 1 0 4 2 3 /
 2 1 3 /
 3 1 4 2 /
 4 3 0 1 /
 rs
 Fig 4.12 : Adjacency list
#define MAX_VERTICES 50
 ve
 typedef struct node *node_pointer;
int vertex;
 };
 struct node *link;
 node_pointer graph[MAX_VERTICES]; ni
 U
 int n=0; /* vertices currently in use */
 Floyd-Warshall algorithm is used. The algorithm will generate a matrix, which will
 represent the minimum distance from any node to all other nodes in the graph.
Example:
 {INF, 0, 3, INF},
 m
 10 Notes
 (0) (3)
 ity
 5 1
(1) (2)
 rs
 3
 Fig 4.13 : Directed graph
 ve
 And graph[i][j] is INF (infinite) if there is no edge from vertex i to j.
Output:
0 5 8 9
INF
INF
 INF
 0
INF
 INF INF
 3
 0
 4
 0
 ni
 U
 Algorithm:
 We initialize the solution matrix same as the input graph matrix as a first step. Then
 we update the solution matrix by considering all vertices as an intermediate vertex.
 The idea is to one by one pick all vertices and updates all shortest paths which include
 ity
 the picked vertex as an intermediate vertex in the shortest path. When we pick vertex
 number k as an intermediate vertex, we already have considered vertices {0, 1, 2, ..
 k-1} as intermediate vertices. For every pair (i, j) of the source and destination vertices
 respectively, there are two possible cases.
 1. k is not an intermediate vertex in shortest path from i to j. We keep the value of dis[i]
 [j] as it is.
 m
 Notes A B C
 A B D
 ity
 B A D C
 C B E
 D A B E /
 D E
 E D C
 Undirected Graph Adjacency List
 rs
 For each node present in the graph which stores the node value and a pointer to
 the next adjacent node to the respective node, an adjacency list is maintained. If all the
 adjacent nodes are traversed then store the NULL in the pointer field of last node of
 the list. The sum of the lengths of adjacency lists is equal to the twice of the number of
 edges present in an undirected graph.
 ve
 Let us take the directed graph shown in the following figure and check the
 adjacency list representation of the graph. The sum of lengths of all the adjacency lists
 is equal to the number of edges present in the graph in case of a directed graph.
A A
 ni
 A B C
 B C D
 C E
 D A
 D E
 E D
 Directed Graph Adjacency List
 U
 Fig 4.15 : Adjacency list
 In the case of weighted directed graph, each node contains an extra field that is
 called the weight of the node. The adjacency list representation of a directed graph is
 shown in the following figure.
 ity
 5 2 A B 5
 A B C
 B C 2 D 8
 7 8 4 C E 4
 D A 7
 10
 D E
 E D 10
 Weighted Directed Graph Adjacency List
 m
 ●● Add/ Remove Vertex: This is the simplest operation in the graph. We can add
 a vertex to a graph. It need not be connected to any other vertex through an
 edge. When removing a vertex, we must remove all edges originating from
 and ending at the deleted vertex.
(c
 ity
 4.4.7 Traversing A Graph(DFS, BFS)
 DFS
 Depth First Search or DFS traverses the graph vertically. It starts with the root node
 or the first node of the graph and traverses all the child nodes before moving to the
 adjacent nodes.
 rs
 Example
 ve
 A
 A
 A
 A
 A A
BFS
 Traversal operation in the graph done by this. BFS horizontally traverses the graph
 which means that it traverses all the nodes at a single level before proceeding to the
 next level. The BFS algorithm starts at the top of the first node in the graph and then
 traverses all the adjacent nodes to it. Once all the adjacent nodes are traversed, the
 algorithm repeats the same procedure for child nodes.
 m
 If we traverse the above graph in BFS fashion then we will get as A -> B -> C -> D
 -> E -> F -> G. The algorithm starts from node A and traverses all its adjacent nodes
 B, C and D. It marks all the four nodes as visited. Once all the adjacent nodes of A are
 traversed, the algorithm moves to the first adjacent node of A and repeats the same
 )A
 procedure. In this case, the node is B, and the adjacent nodes to B are E and F. Next,
 the adjacent nodes to C are traversed. Once all the nodes are visited, the operation
 ends.
Example:
 #include <stdio.h>
(c
#include <stdlib.h>
 #define N 6
 Notes
 ity
 struct Graph {
};
 rs
 // to store adjacency list nodes of the graph
struct Node {
int dest;
 ve
 struct Node* next;
};
struct Edge {
 };
 int src, dest;
 ni
 // Function to create an adjacency list from specified edges
 U
 struct Graph* createGraph(struct Edge edges[], int n)
 unsigned i;
 ity
graph->head[i] = NULL;
 newNode->dest = dest;
 Notes
 ity
 // point new node to the current head
newNode->next = graph->head[src];
graph->head[src] = newNode;
 rs
 }
return graph;
 ve
 // Function to print adjacency list representation of a graph
int i;
 {
 ity
ptr = ptr->next;
 printf(“\n”);
 m
 int main(void)
 )A
{ 0, 1 }, { 1, 2 }, { 2, 0 }, { 2, 1 },
 { 3, 2 }, { 4, 5 }, { 5, 4 }
(c
};
 int n = sizeof(edges)/sizeof(edges[0]);
 Notes
 ity
 // construct a graph from the given edges
printGraph(graph);
 rs
 return 0;
Output:
 ve
 (0 -> 1)
(1 -> 2)
(2 -> 1) (2 -> 0)
(3 -> 2)
(4 -> 5)
 (5 -> 4)
 ni
 U
 ity
 m
 )A
(c
 ity
 4.5.1 Introduction
 When graph G is connected, a depth first or breadth first search starting at any
 vertex will visit all vertices in G. A spanning tree is any tree that consists solely of edges
 in G and that includes all the vertices.
 rs
 E(G): T (tree edges) + N (nontree edges)
 ve
 Either dfs or bfs can be used to create a spanning tree
 ●● When dfs is used, the resulting spanning tree is known as a depth first
 spanning tree
 ●● When bfs is used, the resulting spanning tree is known as a breadth first
 spanning tree
 ●●
 ni
 While adding a nontree edge into any spanning tree, this will create a cycle
 A spanning tree is a minimal subgraph, G’, of G such that V(G’)=V(G) and G’ is
 connected.
 U
 Any connected graph with n vertices must have
 By this definition, we can draw a conclusion that every connected and undirected
 Graph G has at least one spanning tree. A disconnected graph does not have any
 spanning tree, as it cannot be spanned to all its vertices.
 Graph G
 m
C B
Spanning Trees
 A A A
 )A
C B C B C B
 We now recognize that one graph can have more than one spanning tree.
 Following are a few properties of the spanning tree connected to graph G:
 ity
 vertices.
 ●● The spanning tree does not have any cycle (loops).
 ●● Eliminating one edge from the spanning tree will make the graph
 disconnected, i.e. the spanning tree is minimally connected.
 ●● Adding one edge to the spanning tree will create a circuit or loop, i.e. the
 rs
 spanning tree is maximally acyclic.
 Spanning tree is mostly used to find a minimum path to connect all nodes in a
 graph. Common application of spanning trees are −
 ve
 ●● Computer Network Routing Protocol
 ●● Cluster Analysis
 ni
 Prim’s algorithm is a Greedy algorithm. It begins with an empty spanning tree.
 The idea is to maintain two sets of vertices. The first set contains the vertices already
 contained in the MST, the other set contains the vertices not yet included. At every step,
 it considers all the edges that connect the two sets, and picks the minimum weight edge
 from these edges. After picking the edge, it moves the other endpoint of the edge to the
 U
 set containing MST.
 A group of edges that connects two set of vertices in a graph is called cut in
 graph theory. So, at every step of Prim’s algorithm, we discover a cut (of two sets, one
 contains the vertices already included in MST and other contains rest of the vertices),
 ity
 collect the minimum weight edge from the cut and include this vertex to MST Set (the
 set that contains already included vertices).
 The idea behind Prim’s algorithm is simple, a spanning tree implies all vertices
 must be connected. So the two disjoint subsets (discussed above) of vertices must be
 connected to make a Spanning Tree. And they must be connected with the minimum
 weight edge to make it a Minimum Spanning Tree.
 m
 Algorithm
 1. Create a set mstSet that keeps track of vertices already included in MST.
 2. Assign a key value to all vertices in the input graph. Initialize all key values as
 )A
 INFINITE. Assign key value as 0 for the first vertex so that it is picked first.
 3. While mstSet doesn’t include all vertices
 a) Pick a vertex u which is not there in mstSet and has minimum key value.
 b) Include u to mstSet.
 c) Update key value of all adjacent vertices of u. To update the key values, iterate
(c
 through all adjacent vertices. For every adjacent vertex v, if weight of edge u-v
 is less than the previous key value of v, update the key value as weight of u-v.
 The concept of using key values is to pick the minimum weight edge from cut.
 The key values are utilized only for vertices which are not yet included in MST, Notes
 ity
 the key value for these vertices indicate the minimum weight edges linking them
 to the set of vertices included in MST.
 8 7
 1 2 3
 4 2 9
 rs
 0 11 8 4 14 4
 8 7 6 10
 7 6 5
 1 2
 ve
 Fig 4.19 : MST
 The set mstSet is firstly empty and keys assigned to vertices are {0, INF, INF, INF,
 INF, INF, INF, INF} where INF indicates infinite. Now pick the vertex with the minimum
 key value. The vertex 0 is picked, include it in mstSet. So mstSet becomes {0}. After
 including to mstSet, update key values of adjacent vertices. Adjacent vertices of 0 are
 ni
 1 and 7. The key values of 1 and 7 are updated as 4 and 8. Following subgraph shows
 vertices and their key values, only the vertices with finite key values are shown. The
 vertices encompassed in MST are shown in green color.
 U
 4
 1
 0
 0
 ity
 8
 7
 Select the vertex with minimum key value and not already included in MST (not in
 mstSET). The vertex 1 is picked and added to mstSet. So mstSet now becomes {0, 1}.
 Update the key values of adjacent vertices of 1. The key value of vertex 2 becomes 8.
 m
 Pick the vertex with minimum key value and not even now included in MST (not in
 mstSET). We can either pick vertex 7 or vertex 2, let vertex 7 is picked. So mstSet now
 becomes {0, 1, 7}. Update the key values of adjacent vertices of 7. The key value of
 vertex 6 and 8 becomes finite (1 and 7 respectively).
 )A
 4 8
 1 2
 0 7
 0 8
(c
 7 6
 8 1
 Pick the vertex with minimum key value and not already included in MST (not
 Notes in mstSET). Vertex 6 is picked. So mstSet now becomes {0, 1, 7, 6}. Update the key
 ity
 values of adjacent vertices of 6. The key value of vertex 5 and 8 are updated.
 4 8
 1 2
 0 7
 0 8
 rs
 7 6 5
 8 1 2
 ve
 We replicate the above steps until mstSet contains all vertices of given graph.
 Finally, we get the following graph.
 4 4 7
 1 2 3
 ni
 0 9
 0 8 4
 2
 7 6 5
 8 1 2
 U
 Example:
#include <limits.h>
 #include <stdbool.h>
 ity
#include <stdio.h>
 // function to find the vertex with minimum key value, from the set of vertices not yet
 included in MST
 m
 return min_index;
(c
 {
 Notes
 ity
 int i;
printf(“Edge \tWeight\n”);
 rs
 }
 /*function to construct and print MST for a graph represented using adjacency
 matrix representation */
 ve
 {
 ni
 int key[V], v;
 bool mstSet[V];
 U
 for ( i = 0; i < V; i++)
 /*always include first 1st vertex in MST.Make key 0 so that this vertex is picked as
 first vertex. */
 ity
key[0] = 0;
parent[0] = -1;
/*pick the minimum key vertex from the set of vertices not yet included in MST */
mstSet[u] = true;
 /*Update key value and parent index of the adjacent vertices of the picked vertex.
 Consider only those vertices which are not yet included in MST */
 printMST(parent, graph);
 Notes
 ity
 }
void main()
int graph[V][V] = { { 0, 2, 0, 6, 0 },
 rs
 { 2, 0, 3, 8, 5 },
{ 0, 3, 0, 0, 7 },
{ 6, 8, 0, 0, 9 },
 ve
 { 0, 5, 7, 9, 0 } };
primMST(graph);
Output:.
Edge
0-1 2
 1-2 3
 Weight
 ni
 U
 0-3 6
1-4 5
Steps:
4. Since G is connected and has n>0 vertices, exactly n-1 edges will be selected
 Example
 )A
 4 3 3
 4
 4
 2 2 3
 Algorithm
(c
 This algorithm will create spanning tree with minimum weight from a given
 weighted graph.
 1.	Begin
 Notes
 ity
 2. Create the edge list of given graph, with their weights.
 3. Sort the edge list according to their weights in ascending order.
 4. Draw all the nodes to create skeleton for spanning tree.
 5. Pick up the edge at the top of the edge list (i.e. edge with minimum weight).
 6. Remove this edge from the edge list.
 rs
 7. Connect the vertices in the skeleton with given edge. If by connecting the
 vertices, a cycle is created in the skeleton, then discard this edge.
 8. Repeat steps 5 to 7, until n-1 edges are added or list of edges is over.
 ve
 9.	Return
 c)	Length
 d)	Width
 3. What is a full binary tree?
 a) Each node has exactly zero or two children
 m
 ity
 a) Hierarchical structure
 b) Faster search
 c) Router algorithms
 d) Undo/Redo operations in a notepad
 6. Which of the following is incorrect with respect to binary trees?
 rs
 a) Let T be a binary tree. For every k ≥ 0, there are no more than 2k nodes in
 level k
 b) Let T be a binary tree with λ levels. Then T has no more than 2λ – 1 nodes
 ve
 c) Let T be a binary tree with N nodes. Then the number of levels is at least
 ceil(log (N + 1))
 d) Let T be a binary tree with N nodes. Then the number of levels is at least
 floor(log (N + 1))
 7. Construct a binary search tree by using postorder sequence given below.
 Postorder: 2, 4, 3, 7, 9, 8, 5.
 1
 5
 ni
 8
 U
 2 4 7 9
 a)
 5
 ity
3 8
 2 4 7 9
 b) 
 5
 m
3 9
 2 4 7 8
 c) 
 )A
3 7
 2 4 8 9
 d) 
(c
 8. Construct a binary tree using inorder and level order traversal given below.
 Inorder Traversal: 3, 4, 2, 1, 5, 8, 9
 Level Order Traversal: 1, 4, 5, 9, 8, 2, 3
 1
 Notes
 ity
 4 5
 9 8 2 3
 a)
 rs
 5 4
 9 8 2 3
 b)
 ve
 1
4 5
 8 9 2 3
 c)
 4
 1
 5 ni
 U
 8 9 3 2
 d)
 9. What is an AVL tree?
 a) a tree which is balanced and is a height balanced tree
 ity
 Answer key:
 1. b, 2. a, 3. a, 4. c, 5. d, 6. d, 7. b, 8. a, 9. a, 10. b
(c
 ity
 Structure:
 rs
 5.1.2 Bubble Sort
 5.1.3 Selection Sort
 5.1.4 Quick Sort
 5.1.5 Merge Sort
 ve
 5.1.6 Heap Sort
 5.1.7 Partition Exchange Sort
 5.1.8 Shell Sort
 5.1.9 Sorting on Different Keys
 5.1.10 External Sorting
 ni
 Unit-5.2: Searching Techniques
 5.2.1 Linear Search
 U
 5.2.2 Binary search
 5.2.3	Hashing
 5.2.4 Hash Functions
 ity
 ity
 5.1.1 Insertion Sort
 Sorting describes organizing data in a particular format. Sorting algorithm stipulates
 the way to arrange data in a certain order. Most widespread orders are in numerical or
 lexicographical order. A Sorting Algorithm is applied to rearrange a given array or list
 elements allowing to a comparison operator on the elements.
 rs
 Insertion sort is a uncomplicated sorting algorithm that operates similar to the way
 you sort playing cards in your hands. The array is virtually separated into a sorted and
 an unsorted part. Values from the unsorted part are picked and placed at the proper
 position in the sorted part.
 ve
 Algorithm
 ni
 2. Compare the current element or key to its predecessor.
 3. If the key element is lesser than its predecessor, compare it to the elements
 before. Move the greater elements one position up to make space for the
 swapped element.
 U
 Example:
Let us loop for i = 1 (second element of the array) to 4 (last element of the array)
i = 2. 13 will remain at its position as all elements in A[0..I-1] are smaller than 13
 i = 3. 5 will move to the beginning and all other elements from 11 to 13 will move
 m
 i = 4. 6 will move to position after 5, and elements from 11 to 13 will move one
 )A
5, 6, 11, 12, 13
Example:
 #include <stdio.h>
(c
int main()
 ity
 printf(“Enter number of elements: \n”);
scanf(“%d”, &n);
 rs
 scanf(“%d”, &array[c]);
t = array[c];
 ve
 for (d = c - 1 ; d >= 0; d--) {
if (array[d] > t) {
array[d+1] = array[d];
flag = 1;
else
 break;
 ni
 U
 }
if (flag)
 array[d+1] = t;
 ity
 printf(“%d\n”, array[c]);
 m
return 0;
 }
 )A
Output:
Enter 5 integers:
 12534
(c
 2
 Notes
 ity
 3
 rs
 Bubble Sort is the plainest sorting algorithm that operates by constantly swapping
 the adjacent elements if they are in wrong order.
Example:
 ve
 First pass:
 ni
 ( 1 4 5 2 8 ) –> ( 1 4 2 5 8 ), Swap since 5 > 2
 ( 1 4 2 5 8 ) –> ( 1 4 2 5 8 ), Now, since these elements are already in order (8 > 5),
 algorithm does not swap them.
 Second Pass:
 U
 ( 1 4 2 5 8 ) –> ( 1 4 2 5 8 )
 ( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
 ity
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
 Now, the array is already sorted, but our algorithm does not know if it is completed.
 The algorithm needs one whole pass without any swap to know it is sorted.
 Third Pass:
 m
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
 ( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
 )A
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
Example:
#include <stdio.h>
 int main()
(c
 ity
 scanf(“%d”, &n);
scanf(“%d”, &array[c]);
 rs
 for (c = 0 ; c < n - 1; c++)
 ve
 {
swap = array[d];
 }
 array[d] = array[d+1];
 array[d+1] = swap;
 ni
 U
 }
printf(“%d\n”, array[c]);
return 0;
 }
 m
Output:
 5
 )A
Enter 5 integers
20 30 50 40 70
20
 30
(c
40
50
 70
 Notes
 ity
 5.1.3 Selection Sort
 The selection sort algorithm arranges an array by continually finding the minimum
 element (considering ascending order) from unsorted part and placing it at the
 beginning. The algorithm holds two subarrays in a given array.
 rs
 2. Remaining subarray which is unsorted.
 In every iteration of selection sort, the least element (considering ascending order)
 from the unsorted subarray is selected and moved to the sorted subarray.
 ve
 Explanations of the above steps:
arr[] = 64 25 12 22 11
11 25 12 22 64
11 12 22 25 64
 11 12 22 25 64
 m
Example:
 #include <stdio.h>
 )A
int main()
scanf(“%d”, &n);
 scanf(“%d”, &array[c]);
 Notes
 ity
 for (c = 0; c < (n - 1); c++) // finding minimum element (n-1) times
position = c;
 rs
 {
position = d;
 ve
 }
if (position != c)
t = array[c];
 }
 array[position] = t;
 ni
 array[c] = array[position];
 U
 }
printf(“%d\n”, array[c]);
return 0;
 Output:
 m
 Enter 5 integers
 )A
94126
 4
(c
 ity
 QuickSort is a Divide and Conquer algorithm. It chooses an element as pivot and
 partitions the given array around the picked pivot. There are many distinct versions of
 quickSort that pick pivot in different ways.
 rs
 3. Pick a random element as pivot.
 4. Pick median as pivot.
 The key process in quickSort is partition(). Target of partitions is, given an array
 and an element x of array as pivot, put x at its correct position in sorted array and put all
 ve
 smaller elements (smaller than x) before x, and put all greater elements (greater than x)
 after x. All this should be done in linear time.
 {
 ni
 U
 /* pi is partitioning index, arr[pi] is now
at right place */
 }
 m
 Partition around
 70 (Last element)
 )A
Example:
 /* C implementation of QuickSort */
 Notes
 ity
 #include <stdio.h>
#include <stdbool.h>
#define MAX 7
 rs
 void printline(int count) {
int i;
 ve
 printf(“=”);
printf(“=\n”);
void display() {
int i;
 printf(“[“);
 ni
 U
 
printf(“%d “,intArray[i]);
printf(“]\n”);
 }
 m
 intArray[num1] = intArray[num2];
 )A
intArray[num2] = temp;
while(true) {
 //do nothing
 Notes
 ity
 }
//do nothing
 rs
 if(leftPointer >= rightPointer) {
break;
} else {
 ve
 printf(“ item swapped :%d,%d\n”, intArray[leftPointer],intArray[rightPointer]);
swap(leftPointer,rightPointer);
swap(leftPointer,right);
return leftPointer;
 }
 ity
if(right-left <= 0) {
return;
 } else {
 m
 quickSort(left,partitionPoint-1);
 )A
quickSort(partitionPoint+1,right);
int main() {
display();
printline(50);
 quickSort(0,MAX-1);
 Notes
 ity
 printf(“Output Array: “);
display();
printline(50);
 rs
 If we compile and run the above program, it will produce the following result :
Output:
Input Array: [4 6 3 2 1 9 7 ]
 ve
 pivot swapped :9,7
Updated Array: [4 6 3 2 1 7 9 ]
Updated Array: [1 6 3 2 4 7 9 ]
 Updated Array: [1 2 3 4 6 7 9 ]
 ni
 U
 pivot swapped :3,3
Updated Array: [1 2 3 4 6 7 9 ]
 Output Array: [1 2 3 4 6 7 9 ]
 ity
MergeSort(arr[], l, r)
 If r > l
 )A
 1. Find the middle point to divide the array into two halves:
 middle m = (l+r)/2
 Call merge(arr, l, m, r)
 Notes
 ity
 The following diagram from wikipedia shows the complete merge sort process for
 an example array {38, 27, 43, 3, 9, 82, 10}. If we take a closer look at the diagram, we
 can see that the array is recursively divided in two halves till the size becomes 1. Once
 the size becomes 1, the merge processes come into action and start merging arrays
 back till the complete array is merged.
 rs
 These numbers indicates
 the order in which 38 27 43 3 9 82 10
 steps are processed 1
 38 27 43 3 9 82 10
 2 12
 ve
 38 27 43 3 9 82 10
 3 7 13 17
 38 27 43 3 9 82 10
 4 5 8 9 14 15
 27 38 38 43 9 82 10
 6
 3 27
 11
 10
38 43 9
ni 16
 10
 19
 82
 18
 U
 3 9 10 27 38 43 82 20
 Example:
 ity
#include <stdio.h>
#define max 10
int a[11] = { 10, 14, 19, 26, 27, 31, 33, 35, 42, 44, 0 };
 int b[10];
 m
for(l1 = low, l2 = mid + 1, i = low; l1 <= mid && l2 <= high; i++) {
b[i] = a[l1++];
else
 b[i] = a[l2++];
(c
 b[i++] = a[l1++];
 Notes
 ity
 while(l2 <= high)
b[i++] = a[l2++];
a[i] = b[i];
 rs
 }
int mid;
 ve
 if(low < high) {
sort(low, mid);
sort(mid+1, high);
} else {
 return;
 ni
 U
 }
 int main() {
 ity
int i;
 printf(“%d “, a[i]);
 m
sort(0, max);
printf(“%d “, a[i]);
If we compile and run the above program, it will produce the following result :
Output
10 14 19 26 27 31 33 35 42 44 0
 0 10 14 19 26 27 31 33 35 42 44
 Notes
 ity
 5.1.6 Heap sort
 Heap sort is a comparison-based sorting procedure based on Binary Heap data
 structure. It is analogous to selection sort where we first find the maximum element
 and place the maximum element at the end. We replicate the same process for the
 remaining elements. Let us first define a Complete Binary Tree. A complete binary tree
 rs
 is a binary tree in which every level, except possibly the last, is completely filled, and
 all nodes are as far left as possible. A Binary Heap is a Complete Binary Tree where
 items are stored in a special order such that value in a parent node is larger (or smaller)
 than the values in its two children nodes. The previous is called as max heap and the
 concluding is called min-heap. The heap can be exemplified by a binary tree or array.
 ve
 Heap Sort Algorithm for sorting in increasing order:
 ni
 3. Repeat step 2 while size of heap is greater than 1.
 Heapify procedure can be applied to a node only if its children nodes are heapified.
 So the heapification must be performed in the bottom-up order.
 U
 Lets understand with the help of an example:
 4(0)
 ity
/ \
10(1) 3(2)
/ \
 5(3) 1(4)
 m
The numbers in bracket represent the indices in the array representation of data.
 4(0)
 )A
/ \
10(1) 3(2)
/ \
 5(3) 1(4)
(c
10(0)
 / \
 Amity Directorate of Distance & Online Education
 182 Data Structure Using C
 5(1) 3(2)
 Notes
 ity
 / \
4(3) 1(4)
 rs
 Example:
#include<stdio.h>
 ve
 int temp;
int largest = i;
 largest = right;
 ity
if (largest != i)
temp = arr[i];
 arr[i]= arr[largest];
 m
arr[largest] = temp;
 }
 )A
int i;
 {
 Notes
 ity
 temp = arr[0];
arr[0]= arr[i];
arr[i] = temp;
heapify(arr, i, 0);
 rs
 }
void main()
 ve
 {
int i;
heapSort(arr, size);
 Output:
 ity
 2
 m
 3
 )A
10
23
 100
(c
 array into subarrays, while in case of merge sort, all the genuine work occurs during
 Notes merging the subarrays. In case of quick sort, the blend step does utterly nothing. It is
 ity
 similarly called partition-exchange sort. This algorithm splits the list into three main
 parts:
 rs
 Pivot element can be any element from the array, it can be the first element, the
 last element or any random element. In this tutorial, we will take the rightmost element
 or the last element as pivot.
 ve
 For example: In the array {52, 37, 63, 14, 17, 8, 6, 25}, we take 25 as pivot. So
 after the first pass, the list will be changed like this:
{6 8 17 14 25 63 37 52}
 Hence after the first pass, pivot will be set at its position, with all the elements
 smaller to it on its left and all the elements larger than to its right. Now 6 8 17 14 and
 ni
 63 37 52 are considered as two separate sunarrays, and same recursive logic will be
 applied on them, and we will keep doing this until the complete array is sorted.
 and all the elements greater than the pivot will be on the right side of it.
 3. And the pivot element will be at its final sorted position.
 4. The elements to the left and right, may not be sorted.
 5. Then we pick subarrays, elements on the left of pivot and elements on the
 right of pivot, and we perform partitioning on them by choosing a pivot in the
 m
 subarrays.
 Let’s consider an array with values {9, 7, 5, 11, 12, 2, 14, 3, 10, 6}
 Below, we have a pictorial representation of how quick sort will sort the given
 )A
 array.
(c
 p r
 0 1 2 3 4 5 6 7 8 9 Notes
 ity
 9 7 5 11 12 2 14 3 10 6
 p q r
 0 1 2 3 4 5 6 7 8 9
5 2 3 6 12 7 14 9 10 11
 rs
 p q r p q r
 0 1 2 3 4 5 6 7 8 9
2 3 5 6 7 9 10 11 14 12
 ve
 p, r p, r p q, r 8
 0 1 2 3 4 5 6 7 8 9
2 3 5 6 7 9 10 11 12 14
p q, r p, r
 ni
 0 1 2 3 4 5 6 7 8 9
2 3 5 6 7 9 10 11 12 14
 p, r
 U
 0 1 2 3 4 5 6 7 8 9
2 3 5 6 7 9 10 11 12 14
 Example:
 ity
#include <stdio.h>
 int main()
 m
int i;
 int arr[10]={90,23,101,45,65,28,67,89,34,29};
 )A
quickSort(arr, 0, 9);
for(i=0;i<10;i++)
 {
 Notes
 ity
 int left, right, temp, loc, flag;
right = end;
flag = 0;
while(flag != 1)
 rs
 {
right--;
 ve
 if(loc==right)
flag =1;
else if(a[loc]>a[right])
 ni
 {
temp = a[loc];
 a[loc] = a[right];
 U
 a[right] = temp;
loc = right;
 if(flag!=1)
 ity
left++;
 if(loc==left)
 m
flag =1;
 {
 )A
temp = a[loc];
a[loc] = a[left];
a[left] = temp;
 loc = left;
(c
 return loc;
 Notes
 ity
 }
int loc;
if(beg<end)
 rs
 {
 ve
 quickSort(a, loc+1, end);
 ni
 Output:
 23 28 29 34 45 65 67 89 90 101
 U
 5.1.8 Shell Sort
 Shell sort is a highly useful sorting algorithm and is established on insertion sort
 algorithm. This algorithm precludes large shifts as in case of insertion sort, if the smaller
 value is to the far right and has to be moved to the far left.
 ity
Knuth’s Formula
h=h*3+1
 Let us consider the subsequent example to come up with an idea of how shell sort
 m
 works. We take over the same array we have used in our previous examples. For our
 example and ease of understanding, we take the period of 4. Make a virtual sub-list of
 all values located at the interval of 4 positions. Here these values are {35, 14}, {33, 19},
 {42, 27} and {10, 44}
 )A
35 33 42 10 14 19 27 44
35 14
33 19
 42 27
(c
10 44
 We compare values in each sub-list and swap them (if necessary) in the original
 Notes array. After this step, the new array should look like this.
 ity
 14 19 27 10 35 33 42 44
 Then, we take interval of 1 and this gap generates two sub-lists - {14, 27, 35, 42},
 {19, 10, 33, 44}
 rs
 14 19 27 10 35 33 42 44
 ve
 14 27 35 42
19 10 33 44
 We compare and swap the values, if required, in the original array. After this step,
 the array should look like this
 14
 ni
 19 27 10 35 33 42 44
 U
 Ultimately, we sort the remainder of the array using interval of value 1. Shell sort
 uses insertion sort to sort the array. Following is the step-by-step depiction
 14
 14 19
 19 27
 27 10
 10 35
 35 33
 33 42
 42 44
 44
 ity
 14
 14 19
 19 27
 27 10
 10 35
 35 33
 33 42
 42 44
 44
 14
 14 19
 19 27
 27 10
 10 35
 35 33
 33 42
 42 44
 44
 14
 14 19
 19 27
 27 10
 10 35
 35 33
 33 42
 42 44
 44
 m
 14
 14 19
 19 10
 10 27
 27 35
 35 33
 33 42
 42 44
 44
 14
 14 10
 10 19
 19 27
 27 35
 35 33
 33 42
 42 44
 44
 10
 10 14
 14 19
 19 27
 27 35
 35 33
 33 42
 42 44
 44
 )A
 10
 10 14
 14 19
 19 27
 27 35
 35 33
 33 42
 42 44
 44
 10
 10 14
 14 19
 19 27
 27 35
 35 33
 33 42
 42 44
 44
 10
 10 14
 14 19
 19 27
 27 35
 35 33
 33 42
 42 44
 44
(c
We see that it obliged only four swaps to sort the rest of the array.
Algorithm:
 ity
 Step 2 − Divide the list into smaller sub-list of equal interval h
 rs
 Sorting keys indicate the criteria used to execute the sort. The psort operator
 permits to set a primary sorting key and multiple secondary sorting keys.
 The psort operator manipulates the sorting keys to determine the sorting order of a
 data set. The sort operator first sorts the records by the primary sorting key. If multiple
 ve
 records have the same primary key value, the psort operator then sorts these records
 by any secondary keys.
 You must define a single primary sorting key for the psort operator. You might
 optionally define as many secondary keys as required by your job. Note, however, that
 each record field can be used only once as a sorting key. Therefore, the total number
 { {
 fName iName age fName iName age fName iName age
 Mary
 Bob
 Davis
 Jones
 41
 42
 Mary
 Bob
 Davis
 Jones
 41
 42
 Paul
 Mary
 Smith
 Davis
 34
 41
 {
 Jane
 Paul
 Smith
 Smith
 42
 34
 Jane
 Paul
 Smith
 Smith
 34
 42 { Bob
 Jane { Jones
 Smith
 42
 42
 This figure also indicates the results of three sorts using different combinations of
 sorting keys. In this figure, the lName field represents a string field and the age field
 represents an integer. By default, the psort operator applies a case-sensitive algorithm
 for sorting. This implies that uppercase strings be found before lowercase strings in a
 )A
 sorted data set. You can utilize an option to the psort operator to select case-insensitive
 sorting. You can use the member function APT_PartitionSortOperator::setKey() to
 override this default, to perform case-insensitive sorting on string fields.
 ity
 To handle massive amounts of data, External sorting algorithm is used. It is a kind
 of sorting algorithm as the name suggests. After sorting when the date do not fit into the
 main memory then they must reside in external memory. This sorting technique uses
 hybrid sort-merge strategy. In this process, small chunk of data which can be fit into
 main memory are read, sorted and written to a temporary file. Later in merge phase, the
 sorted sub-files are combined into a single larger file.
 rs
 External merge sort algorithm is one of the example of external sorting which sorts
 chunks that can fit in RAM and then merges the sorted chunks together. For this, we
 need to first divide the file into runs such that the size of run is small enough to fit into
 main memory. Then using merge sort, sort each run in the main memory. Later we need
 to merge the resulting runs together into bigger runs, until the file is sorted. To learn
 ve
 external sort algorithm we need to first understand Merge sort (for sorting individual
 runs) and Merge K sorted array ( for merging sorted runs).
Inputs:
 ni
 output_file : Name of output file, output.txt
 b 13 d 30
 c 34 c 34
 c 32 e 18
 b 15 g 23 d 5
 e 19
 e 17 d 22
 r 17 d 32
 d 22 a 13
 d 22 e 15
 m 2
 d 8
 m
 m 4 g 23
 r 12
 p 3 d 22 m 3
 d a 13 m 4 p 6
 6
 p 3
 a 15 d 8 r 15
 r 17
 )A
 initial p 1 sorted
 relation runs output
 runs
 create merge merge
 runs pass-1 pass-2
 Stage 1: First we need to create a number of sorted runs and need to sort each
(c
 of them. In this stage, we perform the sorting operation on the disk blocks. After
 completing the steps of Stage 1, proceed to Stage 2.
 Steps:
 Amity Directorate of Distance & Online Education
 Data Structure Using C 191
 i = 0;
 Notes
 ity
 repeat
read either M blocks or the rest of the relation having a smaller size;
 rs
 i =i+1;
 Stage 2: In Stage 2, we need to merge the runs. Let us think the total number
 of runs as N which is less than M. Here, we can allocate one block to each run and
 ve
 still have some extra space to hold one block of output. We perform the operation as
 follows:
Steps:
repeat
 ni
 select the first tuple among all buffer blocks (where selection is made in sorted
 order);
 U
 write the tuple to the output, and then delete it from the buffer block;
 After completing Stage 2, we will get a sorted output. The output file is then
 buffered for minimizing the disk-write operations. As this algorithm merges N runs, that’s
 why it is known as an N-way merge.
 m
 )A
(c
 ity
 5.2.1 Linear Search
 Searching is an procedure or a technique that discovers the place of a given
 element or value in the list. Any search is believed to be successful or unsuccessful
 depending upon whether the element that is being searched is found or not.
 rs
 This is the easiest method for searching. In this technique of searching,
 the element to be uncovered 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 0th element and remains
 until the element is found from the list or the element whose value is greater than
 ve
 (assuming the list is sorted in ascending order), the value being searched is achieved.
 It is a simple algorithm that searches for a certain item inside a list. It operates
 looping on each element O(n) unless and until a match occurs or the end of the array is
 achieved.
 ni
 ●● algorithm Seqnl_Search(list, item)
 ●● Pre: list != ;
 ●● Post: return the index of the item if found, otherwise: 1
 ●● index <- fi
 U
 ●● while index < list.Cnt and list[index] != item //cnt: counter variable
 ●● index <- index + 1
 ●● end while
 ●● if index < list.Cnt and list[index] = item
 ity
 ●● return index
 ●● end if
 ●● return: 1
 ●● end Seqnl_Search
 Example:
 m
#include<stdio.h>
int main()
 {
 )A
int a[20],i,x,n;
scanf(“%d”,&n);
for(i=0;i<n;++i)
scanf(“%d”,&a[i]);
 ity
 scanf(“%d”,&x);
for(i=0;i<n;++i)
if(a[i]==x)
break;
 rs
 if(i<n)
else
 ve
 printf(“Element not found”);
return 0;
 ni
 Binary search is a very fast and efficient searching technique. It requires the list
 to be in sorted order. In this method, to search an element you can compare it with the
 present element at the center of the list. If it matches, then the search is successful
 otherwise the list is divided into two halves: one from the 0th element to the middle
 U
 element which is the center element (first half) another from the center element to
 the last element (which is the 2nd half) where all values are greater than the center
 element.
 The searching mechanism proceeds from either of the two halves depending upon
 ity
 whether the target element is greater or smaller than the central element. If the element
 is smaller than the central element, then searching is done in the first half, otherwise
 searching is done in the second half.
Algorithm
 ●● Set L to 0 and R to n: 1
 ●● if L > R, then Binary_Search terminates as unsuccessful
 ●● else
 ●● Set m (the position in the mid element) to the floor of (L + R) / 2
 )A
#include <stdio.h>
 int main()
 Notes
 ity
 {
scanf(“%d”, &n);
 rs
 printf(“Enter %d integers\n”, n);
scanf(“%d”, &array[c]);
 ve
 printf(“Enter value to find\n”);
scanf(“%d”, &search);
first = 0;
last = n - 1;
middle = (first+last)/2;
break;
else
 last = middle - 1;
 m
return 0;
Output:
Enter 5 integers
 12345
 Notes
 ity
 Enter value to find
1 found at location 1.
5.2.3 Hashing
 rs
 Hashing is an essential Data Structure which is designed to use a particular
 function called the Hash function which is used to map a given value with a particular
 key for swifter access of elements. The efficiency of mapping depends of the
 effectiveness of the hash function used. Hash table or hash map is a data structure
 ve
 utilized to store key-value pairs. It is a collection of items stored to make it effortless to
 find them later. It utilizes a hash function to calculate an index into an array of buckets
 or slots from which the anticipated value can be discovered. It is an array of list where
 each list is recognized as bucket. It comprises value based on the key. Hash table is
 employed to implement the map interface and extends Dictionary class. Hash table is
 synchronized and encompasses only unique elements.
Features :
 ●●
 ni
 Hashing is the process of mapping enormous amount of data item to smaller
 table with the help of hashing function.
 U
 ●● Hashing is also known as Hashing Algorithm or Message Digest Function.
 ●● It is a method to convert a range of key values into a range of indexes of an
 array.
 ●● It is used to facilitate the next level searching method when matched with the
 linear or binary search.
 ity
 ●● Hashing allows to update and retrieve any data entry in a constant time O(1).
 ●● Constant time O(1) indicates the operation does not depend on the size of the
 data.
 ●● Hashing is utilized with a database to enable items to be retrieved more
 quickly.
 m
 Insert: Move to the bucket corresponds to the above calculated hash index and
 )A
 Delete: To delete a node from hash table, calculate the hash index for the key,
 move to the bucket corresponds to the calculated hash index, search the list in the
 current bucket to find and remove the node with the given key (if found).
(c
 ity
 Keys arrive in the Order (15, 11, 27, 8)
 0
 1 15 8
 2
 3
 rs
 4 11
 5
 6 27
 ve
 Fig 5.6 Hash table
Example:
 ni
 #include<stdio.h>
#include<stdlib.h>
 #include<conio.h>
 U
 /* Node for storing an item in a Linked List */
struct node
 int key;
 ity
int value;
};
struct arrayitem
};
int max = 10;// Determines the maximum capacity of Hash Table array
 ity
 {
 rs
 void remove_element(int key);
void rehash();
void init_array();
 ve
 void insert(int key, int value)
float n = 0.0;
 item->key = key;
 ity
item->value = value;
item->next = NULL;
if (list == NULL)
 {
 m
 array[index].head = item;
 )A
array[index].tail = item;
size++;
else
 {
(c
 if (find_index == -1)
 Notes
 ity
 {
array[index].tail->next = item;
array[index].tail = item;
 rs
 size++;
else
 ve
 {
element->value = value;
 }
 ni
 n = (1.0 * size) / max;
 U
 if (n >= 0.75)
 {
 ity
//rehashing
printf(“going to rehash\n”);
rehash();
	}
 m
void rehash()
 {
 )A
int i = 0, n = max;
size = 0;
 max = 2 * max;
(c
init_array();
 ity
 {
if (list == NULL)
 rs
 {
continue;
 ve
 }
else
/* Presence of Linked List at i, keep moving and accessing the Linked List item until
 ni
 the end, Get one key and value at a time and add it to new Hash Table array.*/
 {
 U
 insert(list->key, list->value);
list = list->next;
} } }
 temp = NULL;
 ity
 {
 m
int retval = 0;
if (temp->key == key)
 return retval;
(c
temp = temp->next;
 retval++;
 Notes
 ity
 }
return -1;
 rs
 struct node* get_element(struct node *list, int find_index)
int i = 0;
 ve
 struct node *temp = list;
while (i != find_index)
temp = temp->next;
i++;
 return temp;
 ni
 U
 }
 if (list == NULL)
 m
 }
 )A
else
if (find_index == -1)
 {
(c
 else
 Notes
 ity
 {
if (temp->key == key)
 rs
 array[index].head = temp->next;
return;
 ve
 }
temp = temp->next;
if (array[index].tail == temp->next)
 {
 ni
 U
 temp->next = NULL;
array[index].tail = temp;
 }
 ity
else
temp->next = temp->next->next;
 }
 m
} } }
void display()
int i = 0;
 {
(c
if (temp == NULL)
 {
 Notes
 ity
 printf(“array[%d] has no elements\n”, i);
else
 rs
 {
 ve
 {
temp = temp->next;
printf(“\n”);
 }
 ni
 U
 }
 void init_array()
 ity
int i = 0;
 {
 m
array[i].head = NULL;
array[i].tail = NULL;
	}
 )A
int size_of_array()
 return size;
(c
void main()
 {
 Notes
 ity
 int choice, key, value, n, c;
clrscr();
init_array();
 rs
 do {
 ve
 Please enter your choice -: “);
scanf(“%d”, &choice);
switch(choice)
case 1:
insert(key, value);
 break;
 ity
case 2:
scanf(“%d”, &key);
 remove_element(key);
 m
break;
case 3:
 n = size_of_array();
 )A
break;
case 4:
 display();
(c
break;
default:
printf(“Wrong Input\n”);
 }
 Notes
 ity
 printf(“\nDo you want to continue-:(press 1 for yes)\t”);
scanf(“%d”, &c);
}while(c == 1);
getch();
 rs
 }
 ve
 ●● This function takes a key and maps it to a value of a certain length which is
 called a Hash value or Hash.
 ●● Hash value symbolizes the original string of characters, but it is normally
 lesser than the original.
 ●● It transfers the digital signature and then both hash value and signature are
 ●●
 ni
 sent to the receiver. Receiver utilizes the same hash function to generate the
 hash value and then compares it to that received with the message.
 If the hash values are same, the message is communicated without errors.
 U
 5.2.4 Collision Resolution Technique
 The hash function is utilized to compute the index of the array. The hash value
 is used to store the key in the hash table, as an index. The hash function can return
 the identical hash value for two or more keys. When two or more keys are provided
 the same hash value, it is called a collision. To handle this collision, we use collision
 ity
resolution techniques.
 Linear Probing
 )A
Quadratic Probing
Double Hashing
 In this technique, a linked list is produced from the slot in which collision has
 occurred, after which the new key is injected into the linked list. This linked list of slots Notes
 ity
 looks like a chain, so it is termed separate chaining. It is applied more when we do not
 know how many keys to insert or delete.
Time complexity
 rs
 b. Its worst-case complexity for deletion is o(n).
 Advantages of separate chaining
 a. It is simple to implement.
 b. The hash table never fills full, so we can add additional elements to the chain.
 ve
 c. It is less sensitive to the function of the hashing.
 Disadvantages of separate chaining
 a. Linear probing
 b. Quadratic probing
 c. Double hashing
 Linear probing
 m
 In this, when the collision occurs, we perform a linear probe for the next slot, and
 this probing is performed until an empty slot is found. In linear probing, the worst time to
 search for an element is O(table size). The linear probing gives the best performance of
 the cache but its problem is clustering. The main advantage of this technique is that it
 can be easily calculated.
 )A
 In this, when the collision occurs, we probe for i2th slot in ith iteration, and this
 probing is accomplished until an empty slot is discovered. The cache performance in
 quadratic probing is lower than the linear probing. Quadratic probing also diminishes
 ity
 Double hashing
 In this, you utilize another hash function, and probe for (i * hash 2(x)) in the ith
 iteration. It requires longer to determine two hash functions. The double probing
 provides the very poor the cache performance, but there has no clustering problem in it.
 rs
 0 1 2 3 4 5 6 7 8 9
 ve
 The above figure shows the hash table with the size of n = 10. Each position of
 the hash table is called as Slot. In the above hash table, there are n slots in the table,
 names = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}. Slot 0, slot 1, slot 2 and so on. Hash table contains
 no items, so every slot is empty.
As we know the mapping between an item and the slot where item belongs in
 ni
 the hash table is termed the hash function. The hash function receives any item in the
 collection and returns an integer in the range of slot names between 0 to n-1.
 Suppose we have integer items {26, 70, 18, 31, 54, 93}. One common method of
 U
 determining a hash key is the division method of hashing and the formula is Hash Key =
 Key Value % Number of Slots in the Table
 Division method or reminder method takes an item and separates it by the table
 size and returns the remainder as its hash value.
 ity
26 26 % 10 = 6 6
70 70 % 10 = 0 0
18 18 % 10 = 8 8
 31 31 % 10 = 1 1
 m
54 54 % 10 = 4 4
 93 93 % 10 = 3 3
 )A
0 1 2 3 4 5 6 7 8 9
70 31 93 54 26 18
 After computing the hash values, we can insert each item into the hash table at the
 designated position as shown in the above figure. In the hash table, 6 of the 10 slots
(c
 are inhabited, it is described to as the load factor and denoted by, λ = No. of items /
 table size. For example , λ = 6/10. Notes
 ity
 It is easy to search for an item using hash function where it computes the slot
 name for the item and then checks the hash table to see if it is appear. Constant
 amount of time O(1) is required to compute the hash value and index of the hash table
 at that location.
 rs
 Linear Probing
 ●● Take the above example, if we insert next item 40 in our collection, it would have
 a hash value of 0 (40 % 10 = 0). But 70 also had a hash value of 0, it becomes a
 problem. This problem is called as Collision or Clash. Collision creates a problem
 for hashing technique.
 ve
 ●● Linear probing is utilized for resolving the collisions in hash table, data structures
 for maintaining a collection of key-value pairs.
 ●● Linear probing was developed by Gene Amdahl, Elaine M. McGraw and Arthur
 Samuel in 1954 and analyzed by Donald Knuth in 1963.
 ●●
 ●●
 dictionary problem.
 ni
 It is a component of open addressing scheme for using a hash table to resolve the
 The simplest method is called Linear Probing. Formula to compute linear probing
 is:
 U
 P = (1 + P) % (MOD) Table_size
For example,
 0 1 2 3 4 5 6 7 8 9
 ity
70 31 93 54 26 18
 If we insert next item 40 in our collection, it would have a hash value of 0 (40 % 10
 = 0). But 70 also had a hash value of 0, it becomes a problem.
P = H(40)
44 % 10 = 0
P= (P + 1) % table-size
0 + 1 % 10 = 1
 But, position 1 is occupied by 31, so we look elsewhere for a position to store 40.
(c
Notes 0 1 2 3 4 5 6 7 8 9
 ity
 70 31 40 93 54 26 18
 rs
 a) Item is somewhere in the middle of the array
 b) Item is not in the array at all
 c) Item is the last element in the array
 ve
 d) Item is the last element in the array or item is not there at all
 2. If the number of records to be sorted is small, then …… sorting can be efficient.
 a)	Merge
 b) Heap
 3.
 c) Selection
 d) Bubble
 ni
 The complexity of the sorting algorithm measures the …… as a function of the
 U
 number n of items to be sorter.
 a) average time
 b) running time
 c) average-case complexity
 ity
 d) case-complexity
 4. Which of the following is not a limitation of binary search algorithm?
 a) must use a sorted array
 b) requirement of sorted array is expensive when a lot of insertion and deletions
 are needed
 m
 ity
 c) sorted linear array
 d) pointer array
 7. Sorting algorithm can be characterized as
 a) Simple algorithm which require the order of n2 comparisons to sort n items.
 b) Sophisticated algorithms that require the O(nlog2n) comparisons to sort items.
 rs
 c) Both of the above
 d) None of the above
 8. ………. is putting an element in the appropriate place in a sorted list yields a larger
 ve
 sorted order list.
 a) Insertion
 b) Extraction
 c) Selection
 ni
 d) Distribution
 9. Which of the following sorting algorithm is of priority queue sorting type?
 a) Bubble sort
 U
 b) Insertion sort
 c) Merge sort
 d) Selection sort
 10. Partition and exchange sort is ……..
 ity
 a) quick sort
 b) tree sort
 c) heap sort
 d) bubble sort
 m
 Answer key:
 1. d, 2. c, 3. b, 4. d, 5. a, 6. a, 7. c, 8. a, 9. d, 10. a
 )A
 Assignment :
 Using the hash function ‘key mod 7’, insert the following sequence of keys in the
 hash table- 50, 700, 76, 85, 92, 73 and 101
Step-01:
 ity
 ●● So, draw an empty hash table consisting of 7 buckets as
 0
 1
 2
 rs
 3
 4
 5
 6
 ve
 Step-02:
 ni
 So, key 50 will be inserted in bucket-1 of the hash table as-
 0
 1 50
 U
 2
 3
 4
 5
 ity
 6
 Step-03:
 0 700
 1 50
 2
 )A
 3
 4
 5
 6
 Step-04:
0 700 Notes
 ity
 1 50
 2
 3
 4
 5
 6 76
 rs
 Step-05:
 ve
 ●● Bucket of the hash table to which key 85 maps = 85 mod 7 = 1.
 ●● Since bucket-1 is already occupied, so collision occurs.
 ●● To handle the collision, linear probing technique keeps probing linearly until an
 empty bucket is found.
 ●● The first empty bucket is bucket-2.
 ●●
 0
 1
 700
 50
 ni
 So, key 85 will be inserted in bucket-2 of the hash table as-
 U
 2 85
 3 92
 4
 5
 6 76
 ity
Step-06:
Notes 0 700
 ity
 1 50
 2 85
 3 92
 4 73
 5
 6 76
 rs
 Step-07:
 ve
 ●● Bucket of the hash table to which key 73 maps = 73 mod 7 = 3.
 ●● Since bucket-3 is already occupied, so collision occurs.
 ●● To handle the collision, linear probing technique keeps probing linearly until an
 empty bucket is found.
 ●● The first empty bucket is bucket-4.
 ●●
 ni
 So, key 73 will be inserted in bucket-4 of the hash table as-
 0
 1
 700
 50
 U
 2 85
 3 92
 4 73
 5 101
 6 76
 ity
Step-08:
 ●● Bucket of the hash table to which key 101 maps = 101 mod 7 = 3.
 m
 ●● So, key 101 will be inserted in bucket-5 of the hash table as-
(c