* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Download Prim`s Algorithm
Survey
Document related concepts
Transcript
UNIT – I Data Structure: Data may be organized in the logical and mathematical model of a particular organization of data is called a “Data Structure”. The choice of a particular data model depends on two considerations: 1. It must be rich enough in structure to mirror the actual relationships of the data in the real world. 2. The structure should be simple enough that one can effectively process the data when necessary. In other words data structure is a collection of data elements whose organization is characterized by assessing operations that are used to store and retrieve the individual data elements. Abstract data type: An abstract data type can be defined as a data type whose properties are specified independently of any particular implementation. The data structures are classified in the following two categories: Linear data structure Nonlinear data structure 1. Linear data structure: In the linear data structures processing of data items are possible in linear fashion i.e. data can be processed sequentially. Linear data structures include the following types of data structures: Array Stack Queues Linked List 1.) Arrays: The simplest type of data structure is a linear or one-dimensional array. By a linear array, we mean a list of finite number ‘n’ of similar data elements referenced respectively by a set of ‘n’ consecutive numbers, usually 1,2,3,4,……..,n. if we choose the name A for the array, then the elements of A are denoted by subscript notation – A1, A2, A3,………..An Or by parenthesis notation – A(1), A(2), A(3),……….A(n) Or by bracket notation – A[1], A[2], A[3],……….A[n] The number k in A[k] is called a subscript and A[k] is called a subscripted variable or array variable. Linear arrays are called one-dimensional arrays because each element in such an array is referenced by one subscript. A two-dimensional array is a collection of similar data elements where each element is referenced by two subscripts. Such arrays are called matrices in mathematics and tables in business applications. 2.) Stack: A stack also known as Last-in-First-out system that is a linear list in which insertions and deletions can take place only at one end, called the top of stack. Stack is just like a container of CDs in which CDs are put one on another. 3.) Queue: A queue also called a First-in-First-out (FIFO) system that is a linear list in which deletions can take place only at one end of the list called the front of the list and insertions can take place only at other end of the list called the rear of the list. 4.) Linked List: A linked list is a linear collection of data elements called nodes, where the linear order is given by means pointers. That is, each node is divided into two parts – the first Page 1 part contains the information of the element and the second part called the link field or next pointer field contains the address of the next node in the list. 2. Non-Linear data structure: A data structure in which insertion and deletion is not possible in a linear fashion is called data structure. Non-Linear data structures include the following types of data structures: Tree Graph 1.) Tree: Data are arranged in hierarchical manner between various elements. The data structure which reflects this relationship is called a rooted tree graph or simply a tree. 2.) Graph: Data sometimes contain a relationship between pairs of elements which is not necessarily hierarchical in nature. The data structure which reflects this type of relationship is called a graph. Data structure operations: The data appearing in our data structures are processed by certain operations. The following operations are: 1. Traversing: Accessing each record exactly once so that certain item in the record may be processed like display it, compare with another value etc. 2. Searching: Finding the location of the record with a given key value or finding the locations of all records which satisfy one or more conditions. 3. Insertion: This operation adds a new record to the structure at the given location or any other value that already exists. 4. Deletion: This operation can remove a record from the structure by giving the location or value. 5. Sorting: This operation rearranges the records in some logical order that is either ascending or descending order. 6. Merging: This operation can merge the two different data structures or records of files into a single data structure or file. 7. Update: Modifying the values of existing record by searching the record and manipulate them. Arrays: - An array is a derived data type which holds the set of values of the similar data type. An array is a collection of values or an array is a collection of similar type of variables. An array provides a convenient structure for representing data; it is classified as one of the data structures in C. An array is a sequenced collection of related data items that share a common name. The array occupies the contiguous memory block to store large volume of data. Array based on static memory allocation concept i.e. an array is a fixed size collection of elements that cannot vary at run time. There are three types of array: One-dimensional array Two-dimensional array Multi-dimensional array Page 2 One-dimensional array: A list of items can be given one variable name using only one subscript and such a variable is called a single-subscripted variable or a one-dimensional array. The starting element of the array is 0th position and last element is the size-1 position. The values are stored in array in contiguous order. An array is based on static memory location. Declaration of One-Dimensional array: Like any other variable, arrays must be declared before they are used. The general form of array declaration is: Syntax - datatype variable-name[size]; The datatype specifies the type of element that will be contained in the array and the size indicates the maximum number of elements that can be stored in the array variable. e.g. int x[10]; float y[20]; Memory Representation of One-Dimensional array: Array allocates a contiguous block of memory space that is starts from 0th index. e.g. - int x[10]; 0 1 2 3 4 5 6 7 8 9 Initialization of One-Dimensional array: After an array is declared, its elements must be initialized; otherwise they will contain garbage value. An array can be initialized at either of the following stages: At compile time At run time 1. Compile time initialization: - We can initialize the elements of array as the ordinary variables when they are declared. Syntax datatype variable-name[size] = { list of values }; The values are separated by commas. e.g. int a[10] = {34, 65, 12, 23, 43, 68, 52, 81, 33, 10}; If we don’t specify all values as their size then the remaining elements are initialized to zero. e.g. int a[10] = {34, 65, 12, 43, 10}; The size may be omitted. In such cases, compiler allocates enough space for all initialized elements. e.g. int a[ ] = {34, 65, 12, 23, 43, 68, 52, 81, 33, 10}; Page 3 2. Run time initialization: - An array can be explicitly initialized at run time. e.g. int a[10]; a[0] = 34; a[1] = 65; a[2] = 12; a[3] = 23 a[4] = 52; Accessing elements of One-Dimensional Array: The array can be accessed by individual elements specified by element number as a constant or variable. Syntax - variable[element no] e.g. - int a[10]; a[0] = 34; a[1] = 65; scanf(“%d”,&a[0]); scanf(“%d”,&a[1]); printf(“%d %d”,a[0], a[1]); for(i = 0; i < 10; i++) printf(“\n %d”, a[i]); Operations on One Dimensional Array: Traversing Insertion Deletion Searching Find Maximum and Minimum Sorting Traversing One Dimensional Array: Traverse means access each element from start to end of one dimensional array. Algorithm – Traverse(Arr, n) Description – Arr is an array of n elements and n is a natural number that represents the upper bound of array. Begin For i = 0 TO n-1 Step 1 Display Arr[i] [End of For statement] End Page 4 Example – Write a program to calculate sum and average of an integer array of 10 numbers. #include<stdio.h> #include<conio.h> void main( ) { int a[10], i, sum = 0; float avg; clrscr( ); printf(“Enter the numbers - ”); for(i = 0; i < 10; i++) scanf(“%d”, &a[i]); for(i = 0; i < 10; i++) { printf(“\n %d”, a[i]); sum = sum + a[i]; } avg = (float) sum/10; printf(“\n Sum is = %d”, sum); printf(“\n Average is = %f”, avg); getch( ); } Insertion in One Dimensional Array: The One Dimensional array is a contiguous memory block and values are stored in sequence. If we want to insert a new element at the given position then first traverse the all right elements after the given position and then assign a new value at the given position. Algorithm – Insert(Arr, n, Pos, val) Description – Arr is an array of n elements and n is a natural number that represents the upper bound of array. Pos is the position where we want to insert and the val is new value that is to inserted. Begin For i = n-1 TO Pos-1 Step -1 Arr[i+1] = Arr[i] [End of For statement] Arr[Pos-1] = val End Example – Write a program to insert a new element in an array at given position. #include<stdio.h> #include<conio.h> void main( ) { int a[20], i, n, pos, val; void insert(int [], int, int, int); Page 5 clrscr( ); printf(“How many numbers entered in an array - ”); scanf(“%d”, &n); printf(“Enter the numbers - ”); for(i = 0; i < n; i++) scanf(“%d”, &a[i]); printf(“\n Array Before Insertion…….”); for(i = 0; i < n; i++) printf(“\n %d”, a[i]); printf(“Enter the position where u want to insert a value - ”); scanf(“%d”, &pos); printf(“Enter the new value - ”); scanf(“%d”, &val); insert(a, n, pos, val); n++; printf(“\n Array After Insertion…….”); for(i = 0; i < n; i++) printf(“\n %d”, a[i]); getch( ); } void insert(int arr[], int n, int pos, int val) { int i; for(i = n-1; i >= pos-1; i--) { arr[i+1] = arr[i]; } arr[pos-1] = val; } Deletion from One Dimensional Array: Deleting an element from the end of an array is simple but deleting an element from some other position is difficult and requires moving all the elements up-word to fill-up the gap into the array. Algorithm – Delete(A, n, Pos) Begin For i = Pos-1 TO n-1 Step 1 A[i] = A[i+1] [End of For statement] n=n–1 End Page 6 Example – Write a program to delete an element in an array from given position. #include<stdio.h> #include<conio.h> void main( ) { int a[20], i, n, pos; void del(int [], int, int); clrscr( ); printf(“How many numbers entered in an array - ”); scanf(“%d”, &n); printf(“Enter the numbers - ”); for(i = 0; i < n; i++) scanf(“%d”, &a[i]); printf(“\n Array Before Deletion…….”); for(i = 0; i < n; i++) printf(“\n %d”, a[i]); printf(“Enter the position from where u want to delete a value - ”); scanf(“%d”, &pos); del(a, n, pos); n--; printf(“\n Array After Deletion…….”); for(i = 0; i < n; i++) printf(“\n %d”, a[i]); getch( ); } void del(int arr[], int n, int pos) { int i; for(i = pos-1; i < n; i++) { arr[i] = arr[i+1]; } } Searching elements from One Dimensional Array: Searching refers to an operation of finding the location of the searching data in an array and output some message if data does not exist in the array. The search is said to be successful if data appears in the array else it is called unsuccessful. There are two methods of searching an element in an array: Linear Search Binary Search Page 7 1. Linear Search: This is the simplest technique to find out an element in an unsorted list. The element can be start finding from first element to last element. If the element is finding on the particular position, then process that position and if it is not found then display a message. Algorithm – LinearSearch(A, n, s) Begin For i = 0 TO n-1 Step 1 If s = A[i] Then Return i [End of if statement] [End of For statement] Return -1 End Example – Write a program to search an element in an array using linear search method. #include<stdio.h> #include<conio.h> void main( ) { int a[20], i, n, s, flag; int linearsearch(int [], int, int); clrscr( ); printf(“How many numbers entered in an array - ”); scanf(“%d”, &n); printf(“Enter the numbers - ”); for(i = 0; i < n; i++) scanf(“%d”, &a[i]); printf(“Enter the value to be searched - ”); scanf(“%d”, &s); flag = linearsearch(a, n, s); if(flag = = -1) printf(“Value not found”); else printf(“Value found on position = %d”, flag+1); getch( ); } int linearsearch(int arr[], int n, int s) { int i; for(i = 0; i < n; i++) { if(s = = arr[i]) return i; Page 8 } return -1; } 2. Binary Search: In this searching method, first we required the array element is in ascending order then we can obtain the element. We define positions low on 0 and high on n-1 element and then determine the middle position and compare the searching number from middle value. If the value matches then display their position but if not then either the first or second half of the array can be selected for next comparison. This process continues until a match is found or there are no values left. Algorithm – BinarySearch(A, n, s) Begin [Initialize] low = 0, high = n-1 While low<=high do Mid = (low + high) / 2 If s = A[mid] Then Return mid Else if s < A[mid] Then high = mid – 1 Else low = mid + 1 [End of if statement] [End of while statement] Return -1 End Example – Write a program to search an element in an array using binary search method. #include<stdio.h> #include<conio.h> void main( ) { int a[20], i, j, n, s, flag, t; int binarysearch(int [], int, int); clrscr( ); printf(“How many numbers entered in an array - ”); scanf(“%d”, &n); for(i = 0; i < n; i++) { printf(“Enter the number - ”); scanf(“%d”, &a[i]); } Page 9 // Process for sorting for(i = 0; i < n; i++) { for(j = 0; j < n-i-1; j++) { if(a[j] > a[j+1]) { t = a[j]; a[j] = a[j+1]; a[j+1] = t; } } } printf(“Enter the value to be searched - ”); scanf(“%d”, &s); flag = binarysearch(a, n, s); if(flag = = -1) printf(“Value not found”); else printf(“Value found on position = %d”, flag+1); getch( ); } int binarysearch(int arr[], int n, int s) { int low, high, mid; low = 0; high = n-1; while(low<=high) { mid = (low + high)/2; if(s = = arr[mid]) return mid; else if(s < arr[mid]) high = mid - 1; else low = mid + 1; } return -1; } Find Maximum/Minimum from One Dimensional array: To find the maximum/minimum value from one dimensional array, we consider the 0th element as maximum/minimum number and then compare each element of array from 1 to n-1 with maximum/minimum value. If any other number is maximum/minimum number then Page 10 change the maximum/minimum value. This process continues till the last element. The maximum/minimum value will be produces as output. Algorithm – Maximum(Arr, n) Description – Arr is an array of n elements and n is a natural number that represents the upper bound of array. Begin max = Arr[0] For i = 1 TO n-1 Step 1 If Arr[i] > max Then max = Arr[i] [End of if statement] [End of For statement] Return max End Example – Write a program to search the maximum from an array. #include<stdio.h> #include<conio.h> void main( ) { int a[20], i, n, max; int maximum(int [], int); clrscr( ); printf(“How many numbers entered in an array - ”); scanf(“%d”, &n); printf(“Enter the numbers - ”); for(i = 0; i < n; i++) scanf(“%d”, &a[i]); max = maximum(a, n); printf(“Maximum Value is = %d”, max); getch( ); } int maximum(int arr[], int n) { int max, i; max = arr[0]; for(i = 1; i < n; i++) { if(arr[i] > max) max = arr[i]; } return max; } Page 11 Algorithm – Minimum(Arr, n) Description – Arr is an array of n elements and n is a natural number that represents the upper bound of array. Begin min = Arr[0] For i = 1 TO n-1 Step 1 If Arr[i] < min Then min = Arr[i] [End of if statement] [End of For statement] Return min End Example – Write a program to search the minimum from an array. #include<stdio.h> #include<conio.h> void main( ) { int a[20], i, n, min; int maximum(int [], int); clrscr( ); printf(“How many numbers entered in an array - ”); scanf(“%d”, &n); printf(“Enter the numbers - ”); for(i = 0; i < n; i++) scanf(“%d”, &a[i]); min = maximum(a, n); printf(“Minimum Value is = %d”, min); getch( ); } int minimum(int arr[], int n) { int min, i; min = arr[0]; for(i = 1; i < n; i++) { if(arr[i] > min) min = arr[i]; } return min; } Page 12 Sorting an array: Sorting is the process of arranging elements in the list according to their values in ascending and descending order. A sorted list is called an ordered list. Many sorting techniques are available. 1. Bubble Sort: It is very simple sorting method. However, this sorting technique is not efficient in comparison to other sorting technique. In bubble sort method, each element is compared with next element. If the current element is greater than second then interchange their values. This process continues when the list is not completely sorted. Algorithm – BubbleSort(Arr, n) Description – Arr is an array of n elements and n is a natural number that represents the upper bound of array. Begin For i = 0 TO n-1 Step 1 For j = 0 TO n-i-1 Step 1 If Arr[ j] > Arr[ j+1] Then t = Arr[ j] Arr[ j] = Arr[ j+1] Arr[ j+1] = t [End of if statement] [End of For statement] [End of For statement] End Example – Write a program to sort an array using bubble sort. #include<stdio.h> #include<conio.h> void main( ) { int a[20], i, n; void bubblesort(int [], int); clrscr( ); printf(“How many numbers entered in an array - ”); scanf(“%d”, &n); printf(“Enter the numbers - ”); for(i = 0; i < n; i++) scanf(“%d”, &a[i]); bubblesort(a, n); for(i = 0; i < n; i++) printf(“\n %d”, a[i]); getch( ); } Page 13 void bubblesort(int arr[], int n) { int i, j, t; for(i = 0; i < n; i++) { for( j = 0; j < n; j++) { if(arr[ j] > arr[ j+1]) { t = arr[ j]; arr[ j] = arr[ j+1]; arr[ j+1] = t; } } } } Two-Dimensional Arrays: In Two-dimensional arrays, two subscripts are used to reference an element of the array one for row elements and second for column elements. The two dimensional arrays is also known as matrix. Declaration of Two-Dimensional array: Like one dimensional arrays, two dimensional must be declared before they are used. The general form of declaration is: Syntax - datatype variable-name[row-size][column-size]; The datatype specifies the type of element that will be contained in the array and the row-size & column-size indicates the maximum number of rows and columns that can be stored in the array variable. e.g. int x[3][3]; float y[5][4]; Initialization of Two-Dimensional array: Like the one-dimensional arrays, two-dimensional array may be initialized by following their declaration with a list of initial values enclosed in braces. Syntax datatype variable-name[row-size][col-size] = { list of values }; The values are separated by commas. e.g. int a[3][3] = {34, 65, 12, 23, 43, 68, 52, 81, 33}; If we don’t specify all values as their size then the remaining elements are initialized to zero. e.g. int a[3][3] = {34, 65, 12, 43, 10}; Page 14 The row size may be omitted. In such cases, compiler allocates enough space for all initialized elements. e.g. int a[ ][3] = {34, 65, 12, 23, 43, 68, 52, 81, 33}; The initialization is done row by row. e.g. int a[ ][3] = { {34, 65, 12}, {23, 43, 68}, {52, 81, 33}}; Accessing elements of Two-Dimensional Array: The array can be accessed by individual elements specified by row element and column element number as a constant or variable. Syntax variable[row element no][column element no] e.g. - int a[3][3]; a[0][0] = 34; a[1][0] = 65; scanf(“%d”, &a[0][0]); scanf(“%d”, &a[0][1]); printf(“%d %d”, a[0][0], a[0][1]); Operations on Two Dimensional Array: Traversing Transpose of a Matrix Addition of Matrices Subtraction of Matrices Multiplication of Matrices Traversing Two Dimensional Array: Traverse means access each element from start to end of two dimensional arrays. Traversing of two dimensional arrays can be classified into two categories: Column major order Row major order. Algorithm – Traverse(Arr, n) Description – Arr is a two-dimensional array of n*n elements. Begin For i = 0 TO n-1 Step 1 For j = 0 TO n-1 Step 1 Display Arr[ i ][ j ] [End of For statement] [End of For statement] End Page 15 Example – Write a program to input and print a matrix. #include<stdio.h> #include<conio.h> void main( ) { int a[3][3], i, j; clrscr( ); printf(“Enter the numbers - ”); for(i = 0; i < 3; i++) for( j = 0; j < 3; j++) scanf(“%d”, &a[ i ][ j ]); for(i = 0; i < 3; i++) { for( j = 0; j < 3; j++) { printf(“%4d”, a[ i ][ j ]); } printf(“\n”); } getch( ); } Transpose of a Matrix: It is obtained by interchanging the rows with corresponding columns of a given matrix. The transpose of a matrix A is generally denoted by AT. if matrix A is an m x n then after transposing it we will get an n x m matrix AT. Algorithm – Tranpose(A, n) Description – Arr is a two-dimensional array of n*n elements. Begin For i = 0 TO n-1 Step 1 For j = 0 TO n-1 Step 1 Display A[ j ][ i ] [End of For statement] [End of For statement] End Example – Write a program to transpose the matrix. #include<stdio.h> #include<conio.h> void main( ) { int a[3][3], i, j; clrscr( ); Page 16 printf(“Enter the numbers - ”); for(i = 0; i < 3; i++) for( j = 0; j < 3; j++) scanf(“%d”, &a[ i ][ j ]); printf(“Transpose matrix…….\n”); for(i = 0; i < 3; i++) { for( j = 0; j < 3; j++) { printf(“%4d”, a[ j ][ i ]); } printf(“\n”); } getch( ); } Addition of Matrices: Let A and B are two matrices of the same order. Then their sum, A+B is defined as a matrix, each of which is summation of corresponding elements of A and B. Algorithm – Addition of Two Matrices Begin For i = 0 TO n-1 Step 1 For j = 0 TO n-1 Step 1 C[ i ][ j ] = A[ i ][ j ] + B[ i ][ j ] [End of For statement] [End of For statement] End Example – Write a program to addition of two matrices. #include<stdio.h> #include<conio.h> void main( ) { int a[3][3], b[3][3], c[3][3], i, j; clrscr( ); printf(“Enter the numbers in first matrix……….\n”); for(i = 0; i < 3; i++) for( j = 0; j < 3; j++) scanf(“%d”, &a[ i ][ j ]); printf(“Enter the numbers in second matrix……….\n”); for(i = 0; i < 3; i++) for( j = 0; j < 3; j++) scanf(“%d”, &b[ i ][ j ]); Page 17 printf(“Addition of two matrices…….\n”); for(i = 0; i < 3; i++) { for( j = 0; j < 3; j++) { c[ i ][ j ] = a[ i ][ j ] + b[ i ][ j ]; printf(“%4d”, c[ i ][ j ]); } printf(“\n”); } getch( ); } Subtraction of Matrices: Let A and B are two matrices of the same order. Then their subtraction, A-B is defined as a matrix, each of which is subtraction of corresponding elements of A and B. Algorithm – Subtraction of Two Matrices Begin For i = 0 TO n-1 Step 1 For j = 0 TO n-1 Step 1 C[ i ][ j ] = A[ i ][ j ] - B[ i ][ j ] [End of For statement] [End of For statement] End Multiplication of Matrices: Let A and B are two matrices of the same order. Then their multiplication, A*B is defined as a matrix, each of which is multiplication of each row from A matrix to each column of B matrix. Algorithm – Multiplication of Two Matrices Begin For i = 0 TO n-1 Step 1 For j = 0 TO n-1 Step 1 C[ i ][ j ] = 0 For k = 0 TO n-1 Step 1 C[ i ][ j ] = C[ i ][ j ] + A[ i ][ k ] * B[ k ][ j ] [End of For statement] [End of For statement] [End of For statement] End Page 18 Example – Write a program to multiplication of two matrices. #include<stdio.h> #include<conio.h> void main( ) { int a[3][3], b[3][3], c[3][3], i, j, k; clrscr( ); printf(“Enter the numbers in first matrix……….\n”); for(i = 0; i < 3; i++) for( j = 0; j < 3; j++) scanf(“%d”, &a[ i ][ j ]); printf(“Enter the numbers in second matrix……….\n”); for(i = 0; i < 3; i++) for( j = 0; j < 3; j++) scanf(“%d”, &b[ i ][ j ]); printf(“Multiplication of two matrices…….\n”); for(i = 0; i < 3; i++) { for( j = 0; j < 3; j++) { c[ i ][ j ] = 0; for( k = 0; k < 3; k++) { c[ i ][ j ] = c[ i ][ j ] + a[ i ][ k ] * b[ k ][ j ]; } printf(“%4d”, c[ i ][ j ]); } printf(“\n”); } getch( ); } Sparse Matrix: Matrices with a relatively high proportion of zero entries are called sparse matrices. Two general types of n-square sparse matrices: 1. Triangular matrix 2. Tri-diagonal matrix If all entries above the main diagonal are zero or equivalently where non-zero entries can only occur on or below the main diagonal is called a lower triangular matrix. If all entries below the main diagonal are zero or equivalently where non-zero entries can only occur on or above the main diagonal is called upper triangular matrix. If non-zero entries can only occur on the diagonal or on elements, immediately above or below the diagonal is called a tri-diagonal matrix. Page 19 Example 1 6 11 16 21 0 7 12 17 22 0 0 13 18 23 0 0 0 19 24 0 0 0 0 25 1 0 0 0 0 2 7 0 0 0 3 8 13 0 0 4 9 14 19 0 5 10 15 20 25 1 6 0 0 0 2 7 12 0 0 0 8 13 18 0 0 0 14 19 24 0 0 0 20 25 Lower Triangular Matrix Example - Upper Triangular Matrix Example - Tri-Diagonal Matrix Examples: - Develop a program to print the lower triangular and upper triangular matrix. #include<stdio.h> #include<conio.h> void main( ) { int a[3][3], i, j, ch; clrscr( ); printf(“Enter the numbers in matrix - ”); for(i = 0; i < 3; i++) for( j = 0; j < 3; j++) scanf("%d", &a[ i ][ j ]); printf("\n 1. Original Matrix"); printf("\n 2. Lower Triangular Matrix"); printf("\n 3. Upper Triangular Matrix"); printf("\n Enter the choice - "); scanf("%d", &ch); switch(ch) { case 1: printf("Original matrix.....\n"); for(i = 0; i < 3; i++) { for( j = 0; j < 3; j++) { printf("%4d", a[ i ][ j ]); } Page 20 printf("\n"); } break; case 2: printf("Lower Triangular Matrix....\n"); for(i = 0; i < 3; i++) { for( j = 0; j < 3; j++) { if( i >= j ) printf("%4d", a[ i ][ j ]); else printf("%4d", 0); } printf("\n"); } break; case 3: printf("Upper Triangular Matrix....\n"); for(i = 0; i < 3; i++) { for( j = 0; j < 3; j++) { if( i <= j ) printf("%4d", a[ i ][ j ]); else printf("%4d", 0); } printf("\n"); } break; } getch( ); } String or Array of Characters: A string is a sequence of characters that is a single data item. Any group of characters defined between double quotation marks is a string constant. Example - printf(“Hello world”); Declaring and initializing string variables: C does not support strings as a data type. However, it allows us to represent strings as character arrays. A string variable is also declared as an array of characters. Syntax char variable[size]; Page 21 Example - char x[20]; When the compiler assigns a character string to a character array, it automatically supplies a NULL (‘\0’) character at the end of the string. Therefore, the size should be equal to the maximum number of characters in the string plus one for ‘\0’ character. Like numeric arrays, character arrays may be initialized when they are declared. Example - char x[20]={‘R’, ’A’, ’K’, ’E’, ’S’, ’H’, ’ ’, ’K’, ’U’, ’M’, ’A’, ’R’}; OR char x[20]=“RAKESH KUMAR”; C also permits us to initialize a character array without specifying the number of elements. In such cases, the size of array will be determined automatically based on the number of elements initialized. Example - char x[ ]={‘R’, ’A’, ’K’, ’E’, ’S’, ’H’, ’ ’, ’K’, ’U’, ’M’, ’A’, ’R’}; OR char x[ ]=“RAKESH KUMAR”; Reading string using scanf or gets: The scanf( ) function can be used with ‘%s’ format specification to read a string. Example - char x[20]; scanf(“%s”, x); The problem with the ‘%s’ format character is that it terminates its input on first white spaces it finds. The scanf function automatically terminates the string that is read with a null character. We can also specify the field width using the form ‘%ws’ in the scanf( ) statement for reading a specified number of characters from the input string. Example - char x[10]; scanf(“%5s”, x); If you entered the string MANOHAR will be stored as: - M A N O H \0 0 1 2 3 4 5 6 7 8 9 We can read multiple words by using ‘%[^\n]’ character with scanf( ) function. We also use gets( ) instead of scanf( ) function. Example - char x[20]; scanf(“%[^\n]”, x); OR gets(x); Page 22 String Handling Functions: The C library supports a large number of string-handling functions that can be used to carry out many of the string manipulations. The string handling functions are contained in “string.h” header file. 1. strlen( ): - It calculates the length of string. Syntax - variable = strlen(string1); 2. strcpy( ): - It copies all characters of source string to destination string. Syntax - strcpy(destination-string, source-string); 3. strncpy( ): - It copies the given number of characters of source string to destination string. Syntax - strncpy(destination-string, source-string, no-of-character); 4. strrev( ): - It reverses the string in the given string variable. Syntax - strrev(string1); 5. strcat( ): - It concatenates two strings. Syntax - strcat(destination-string, source-string); 6. strncat( ): - It merge the given number of character of source string at the end of destination string. Syntax - strncat(destination-string, source-string, no-of-character); 7. strcmp( ): - This function compares two strings identified by the arguments and has a value 0 if they are equal. If the ascii character of first string is greater than second string then returns positive value and if the ascii character of first string is less than second string then returns negative value. Syntax strcmp(string1, string2); 8. strncmp( ): - This function compares the left-most n characters of first string to second string and returns 0 if they are equal. It returns positive value, if the sub string of first is greater than second string and it returns negative value, if the sub string of first is less than second string. Syntax - strncmp(string1, string2, no-of-character); 9. strcmpi( ): - This function also compares two strings identified by the arguments without case sensitivity. It returns 0 if they are equal. It returns positive value, if the Page 23 first string is greater than second string and it returns negative value, if the first string is less than second string. Syntax - strcmpi(string1, string2); 10. strstr( ): - It can be used to locate a sub string in a string. It will locate the first occurrence of the sub string. Syntax - strstr(string, sub-string); 11. strchr( ): - It can be used to locate a character in a string. It will locate the first occurrence of the character. Syntax - strchr(string, searching-character); 12. strrchr( ): - It can be used to locate the last occurrence of the character in the string. Syntax - strrchr(string, searching-character); 13. strupr( ): - It converts entire string into capital letters. Syntax - strupr(string); 14. strlwr( ): - It converts entire string into lower case letters. Syntax - strlwr(string); Examples: 1. Write a program to calculate the length of string using user-defined function. Ans.: #include<stdio.h> #include<conio.h> void main( ) { int length(char [ ]); char x[20]; int len; clrscr( ); printf(“Enter the string – “); scanf(“%[^\n]”, x); len = length(x); printf(“length of string = %d”, len); getch( ); } Page 24 int length(char a[ ]) { int len=0, i; for(i = 0; a[i] !=’\0’; i++) len++; return len; } 2. Write a program to copy one string to another using user-defined function. Ans.: #include<stdio.h> #include<conio.h> void main( ) { void copystr(char [ ], char [ ]); char x[20], y[20]; clrscr( ); printf(“Enter the string – “); scanf(“%[^\n]”, x); copystr(y, x); printf(“copied string = %s”, y); getch( ); } void copystr(char dest[ ], char src[ ]) { int i; for(i = 0; src[i] !=’\0’; i++) dest[i] = src[i]; dest[i] = ‘\0’; } Stack: A stack is a linear data structure in which data is inserted or deleted only at one end, called the top of stack. Data is stored and retrieved in LIFO manner. The most recently pushed element can be checked prior to performing a delete operation. This means, in particular that elements are removed from a stack in the reverse order of that in which they were inserted into the stack. Stacks are also known as Push down list. Application of stacks: 1. Processing of sub-routine calls and their return. 2. Implementation of recursion. 3. Converting an expression from one form to another form. E.g. - 2 + 3 Infix 23+ Postfix +23 Prefix 4. Evaluation of expression. Page 25 Operations on Stack: 1. Push elements in stack. Push(stack, top, val) which inserts the element val into the stack. 2. Pop elements from stack. Pop(stack, top) which removes the top element of stack and return the element. 3. Read top position element from the stack. Peep(stack, top) which returns the top element of stack. 4. Check whether the stack is empty or not. Isempty(stack, top) which returns true, if stack is empty otherwise returns false. 5. Check whether the stack is full or not. Isfull(stack, top) which returns true, if stack is full otherwise returns false. Implementation of Stack: To implement a stack, there are two common methods used: 1. Using Array 2. Using Linked List 1. Using Array Implementation: - The array implementation technique is very simple and easy to implement. But there is one problem that we need to declare the size of an array before start the operation. In this case, the actual number of elements in the stack at any time never gets too large. It is usually easy to declare the array to be large enough without wasting too much memory space. Associated with each stack there is a top of stack that is -1 for empty stack. Push operation: Push means to insert an item into the stack. In the push operation, first check if the stack is full then insert operation is not possible and if the stack has blank elements then insert the element. Algorithm - push(stack, top, val) Begin If top = SIZE – 1 then Display “Stack is full” Else top = top + 1 stack[top] = val [End of if statement] End Page 26 Pop operation: The pop operation deletes the topmost item from the stack. After removal of top most information, new value of the top pointer becomes the previous value of top of stack i.e. top = top – 1 and freed position is allocated to free space. Algorithm - pop(stack, top) Begin If top = – 1 then Display “Stack is empty” Else x = stack[top] top = top - 1 Return x [End of if statement] End Peep or Peek operation: The peep operation only gets the information stored at the top of stack. In this operation, top of stack never changes. Algorithm - peep(stack, top) Begin If top = – 1 then Display “Stack is empty” Else Return stack[top] [End of if statement] End Determine the stack is empty operation: The isempty operation determines the stack is empty or not. If stack is empty then return true otherwise false. Algorithm - isempty(stack, top) Begin If top = – 1 then Return 1 Else Return 0 [End of if statement] End Determine the stack is full operation: The isfull operation determines the stack is full or not. If stack is full then return true otherwise false. Page 27 Algorithm - isfull(stack, top) Begin If top = SIZE – 1 then Return 1 Else Return 0 [End of if statement] End Example – Develop a program to perform all the operations on stack. #include<stdio.h> #include<conio.h> #define SIZE 20 int stack[SIZE]; int top = -1; void push(int); int pop( ); int peep( ); int isempty( ); int isfull( ); void main( ) { int ch, x; clrscr( ); while(1) { printf(“\n 1. Push operation”); printf(“\n 2. Pop operation”); printf(“\n 3. Peep operation”); printf(“\n 4. Determine the stack is empty”); printf(“\n 5. Determine the stack is full”); printf(“\n Enter the choice (0 for exit) - ”); scanf(“%d”, &ch); switch(ch) { case 1: printf(“Enter the value – “); scanf(“%d”, &x); push(x); break; case 2: printf(“Deleted element is = %d”, pop( )); break; case 3: printf(“The top element is = %d”, peep( )); Page 28 break; case 4: if(isempty( )) printf(“Stack is empty”); else printf(“Stack is not empty”); break; case 5: if(isfull( )) printf(“Stack is full”); else printf(“Stack is not full”); break; case 0: exit(0); } getch( ); } } void push(int val) { if(top = = SIZE – 1) printf(“Stack is full”); else { top = top + 1; stack[top] = val; } } int pop( ) { int x; if(top = = – 1) { printf(“Stack is empty”); return -999; } else { x = stack[top]; top = top - 1; return x; } } int peep( ) Page 29 { if(top = = – 1) { printf(“Stack is empty”); return -999; } else return stack[top]; } int isempty( ) { if(top = = – 1) return 1; else return 0; } int isfull( ) { if(top = = SIZE – 1) return 1; else return 0; } Recursion: Recursion means the function call by itself. In the recursion, there is a condition defined to exit from the function. Example – Write algorithm and a program to calculate the factorial value of a number. Algorithm – Fact(n) Begin If n = 1 Then Return 1 Else Return n * Fact(n - 1) [End of if statement] End. #include<stdio.h> #include<conio.h> void main( ) { int n; float f; float factorial(int); Page 30 clrscr( ); printf(“Enter the number – “); scanf(“%d”, &n); f = factorial(n); printf(“Factorial value is = %f ”, f); getch( ); } float factorial(int n) { if(n = = 1) return 1; else return n * factorial(n-1); } Example – Write algorithm and develop a program to calculate the sum of digits of a number. Algorithm – Sumofdigit(n) Begin If n = 0 Then Return 0 Else Return n%10 + Sumofdigit(n / 10) [End of if statement] End. #include<stdio.h> #include<conio.h> void main( ) { int n, s; int sumofdigit(int); clrscr( ); printf(“Enter the number – “); scanf(“%d”, &n); s = sumofdigit(n); printf(“Sum of digits = %d ”, s); getch( ); } int sumofdigit(int n) { if(n = = 0) return 0; else return n%10 + sumofdigit(n / 10); } Page 31 Example – Write algorithm and develop a program to calculate the linear search of a number. Algorithm – Linearsearch(Arr, s, i, n) Begin If i < n Then If s = Arr[i] Then Return i + 1 Else Return Linearsearch(Arr, s, i +1, n) [End of if statement] Else Return -1 [End of if statement] End. #include<stdio.h> #include<conio.h> void main( ) { int a[10], n, i, s, flag; int linearsearch(int [ ], int, int, int); clrscr( ); printf(“How many numbers in an array – “); scanf(“%d”, &n); for(i = 0; i < n; i++) { printf(“Enter the number – “); scanf(“%d”, &a[i]); } printf(“Enter the number to be searched – “); scanf(“%d”, &s); flag = linearsearch(a, 0, n, s); if(flag = = -1) printf(“Value not found”); else printf(“Value found on position = %d”, flag); getch( ); } int linearsearch(int arr[], int i, int n, int s) { if(i = = n) return -1; else { if(s = = arr[i]) return (i + 1); Page 32 else return linearsearch(arr, i+1, n, s); } } Example – Develop a program to covert the decimal number into binary form using stack. #include<stdio.h> #include<conio.h> #define SIZE 20 int stack[SIZE]; int top = -1; void push(int); int pop( ); void main( ) { int x, r; clrscr( ); printf(“Enter the value – “); scanf(“%d”, &x); while(x ! = 0) { r = x % 2; push(r); x = x / 2; } while(top ! = -1) { printf(“%d”, pop( )); } getch( ); } void push(int val) { if(top = = SIZE – 1) printf(“Stack is full”); else { top = top + 1; stack[top] = val; } } int pop( ) { int x; if(top = = – 1) Page 33 { printf(“Stack is empty”); return -999; } else { x = stack[top]; top = top - 1; return x; } } Example – Develop a program to determine the string is palindrome or not. #include<stdio.h> #include<conio.h> #define SIZE 20 char stack[SIZE]; int top = -1; void push(char); char pop( ); void main( ) { char x[20]; int i, len = 0, flag = 0; clrscr( ); printf("Enter the string - "); scanf("%s", x); for(i = 0; x[i] != '\0' ; i++) len++; for(i = 0; i < len / 2 ; i++) { push(x[i]); } if(len%2 != 0) i++; while(top != -1) { if(x[i++] != pop( )) { flag = 1; break; } } if(flag = = 0) printf("String is palindrome"); Page 34 else printf("String is not palindrome"); getch( ); } void push(char val) { if(top = = SIZE - 1) printf("Stack is full"); else { top = top + 1; stack[top] = val; } } char pop( ) { int x; if(top = = - 1) { printf("Stack is empty"); return -999; } else { x = stack[top]; top = top - 1; return x; } } Polish Notation: This is the operation of written the expression where operators come before the operands i.e. variable or constant is called polish notation or prefix order of expression. Reverse Polish Notation: This is the operation of written the expression where operators come after the operands i.e. variable or constant is called reverse polish notation or postfix order of expression. Conversion from Infix to Postfix and Infix to Prefix expression: Infix a+b a+b*c a*b+c Prefix +ab +a*bc +*abc Postfix ab+ abc*+ ab*c+ Page 35 (a+b)*c (a+b)*(c-d) *+abc *+ab-cd ab+c* ab+cd-* Example – Develop a program to convert the infix to postfix expression. #include<stdio.h> #include<conio.h> #include<ctype.h> #define SIZE 20 char stack[SIZE]; int top=-1; void push(char); char pop( ); char peep( ); int priority(char); void main() { char x[20], y[20]; int i, j=0; clrscr( ); printf("enter the infix expression - "); gets(x); for(i = 0; x[i] !='\0'; i++) { if(isalnum(x[i])) y[j++] = x[i]; else if(x[i] = = '(' ) push(x[i]); else if(x[i] = = ')' ) { if(top != -1) { while(peep( ) != '(' ) y[ j++ ]=pop( ); } pop( ); } else if(x[i] = = '+' || x[i] = = '-' || x[i] = = '*' || x[i] = = '/' || x[i] = = '%') { if(top != -1) { if(priority(x[i])<=priority(peep( ))) y[ j++ ]=pop( ); } push(x[i]); } Page 36 } while(top != -1) y[j++]=pop( ); y[j] = '\0'; printf("postfix expression = %s", y); getch(); } void push(char val) { if(top = = SIZE-1) printf("stack is full"); else { top++; stack[top] = val; } } char pop( ) { char t; if(top = = -1) { printf("stack is empty"); return -999; } else { t=stack[top]; top--; return t; } } char peep( ) { if(top = = -1) { printf("stack is empty"); return -999; } else { return stack[top]; } } Page 37 int priority(char op) { switch(op) { case '(': return 0; case '+': case '-': return 1; case '%': return 2; case '*': case '/': return 3; } } Example – Develop a program to convert the infix to prefix expression. #include<stdio.h> #include<conio.h> #include<ctype.h> #define SIZE 20 char stack[SIZE]; int top=-1; void push(char); char pop( ); char peep( ); int priority(char); void main() { char x[20], y[20]; int i, j=0, l=0; clrscr( ); printf("enter the infix expression - "); gets(x); for(i = 0; x[i] !='\0'; i++) l++; for(i = l-1; i >= 0; i--) { if(isalnum(x[i])) y[j++] = x[i]; else if(x[i] = = ')' ) push(x[i]); else if(x[i] = = '(' ) { if(top != -1) { Page 38 while(peep( ) != ')' ) y[ j++ ]=pop( ); } pop( ); } else if(x[i] = = '+' || x[i] = = '-' || x[i] = = '*' || x[i] = = '/' || x[i] = = '%') { if(top != -1) { if(priority(x[i])<=priority(peep( ))) y[ j++ ]=pop( ); } push(x[i]); } } while(top != -1) y[j++]=pop( ); y[j] = '\0'; strrev(y); printf("prefix expression = %s", y); getch(); } void push(char val) { if(top = = SIZE-1) printf("stack is full"); else { top++; stack[top] = val; } } char pop( ) { char t; if(top = = -1) { printf("stack is empty"); return -999; } else { t=stack[top]; top--; Page 39 return t; } } char peep( ) { if(top = = -1) { printf("stack is empty"); return -999; } else { return stack[top]; } } int priority(char op) { switch(op) { case ')': return 0; case '+': case '-': return 1; case '%': return 2; case '*': case '/': return 3; } } Queue: A queue is a collection of linear data structure in which insertion of elements can take place only at one end called REAR and deletion of elements can take place only at other end called FRONT. This makes the queue a First-In-First-Out data structure. In a FIFO data structure, the first element added to the queue will be the first one to be removed. For example – A queue of people waiting at a ticket window or at bus stop, each new person who comes, takes his place at the end of line. The people in the front take the ticket first. Thus queue are also called FIFO structure. Implementation of Queue: Queue can be implemented in two ways: 1. Array or Static implementation 2. Linked list or Dynamic implementation. Page 40 Array or Static implementation: It uses array to create queue. Static implementation is the most widely used technique. But it is not efficient with respect to memory utilization because in static implementation, the size of queue has to be declared during program design. Now if there are few elements to be stored in the queue, some allocated memory will be wasted and we will not be able to decrease the size of array. If there are a large number of elements to be stored in the queue, then we will not be able to increase the size of array. Linked list or Dynamic implementation: It is done using linked list that uses pointers to implement the queue. The size of queue varies according to requirement. Representation of Queue: The representation of queue can be in various ways, sometimes through one-way list and sometimes through linear arrays. It is maintained as linear arrays with two pointer variables FRONT and REAR. FRONT: - It contains the location of the front element in the queue. REAR: - It contains the location of the last element in the queue. When the element is deleted from the queue the value of FRONT is increased by 1. FRONT = FRONT + 1 FRONT =1 REAR = 4 1 2 3 4 A B C D 5 6 7 8 9 6 7 8 9 Queue A is deleted from queue FRONT =2 REAR = 4 1 2 3 4 B C D 5 Queue When an element is added-up to the queue then the value of REAR is increased by 1. REAR = REAR + 1 1 2 3 4 5 6 7 8 9 FRONT =2 B C D REAR = 4 Queue E is added to queue FRONT =2 REAR = 5 1 2 3 4 5 B C D E 6 7 8 9 Operations on queue: 1. Insert an element in the queue: This operation is called Enqueue operation. When an element is added to queue, first it must check whether the queue is full or not. If queue is full, this Page 41 condition is called QUEUE OVERFLOW. If queue is not full, item should be added at the rear. After every insertion, the rear increments by one. When first item is added to queue, front must be set to zero. Algorithm – Insert an item in queue Begin If FRONT = 0 and REAR = SIZE – 1 Then Display “Queue Overflow” and return Else if FRONT = -1 Then FRONT = 0 REAR = 0 Else REAR = REAR + 1 [End of if statement] Q[REAR] = val [End of if statement] End 2. Delete an element from the queue: This operation is called Dequeue operation. When an element is removed from queue, it should first check whether the queue is empty or not. If queue is empty, this condition is called QUEUE UNDERFLOW. If the queue is not empty, then the element should be removed from the FRONT. After each deletion the FRONT should be incremented by 1. Algorithm – Delete an item from queue Begin If FRONT = -1 Then Display “Queue Underflow” and return Else val = Q[FRONT] if FRONT = REAR Then FRONT = -1 REAR = -1 Else FRONT = FRONT + 1 [End of if statement] Return(val) [End of if statement] End Page 42 3. Traverse the queue: When the queue is traversed, it should first check whether the queue is empty or not. If queue is empty, this condition is called QUEUE UNDERFLOW. If the queue is not empty, then access each element starting from FRONT to REAR. Algorithm – Traverse the queue Begin If FRONT = -1 Then Display “Queue Underflow” and return Else For i = FRONT to REAR Step 1 Display Queue[i] [End of for statement] [End of if statement] End 4. Determine the queue is full or not: This operation determines whether the queue is full or not. If FRONT is positioned on 0 and REAR on SIZE-1 then the queue is full, this condition is called QUEUE OVERFLOW. Otherwise not full. Algorithm – Determine the queue is full or not Begin If FRONT = 0 and REAR = SIZE – 1 Then Display “Queue Overflow” Else Display “Queue Not Overflow” [End of if statement] End 5. Determine the queue is empty: This operation determines whether the queue is empty or not. If the FRONT is positioned on -1 then the queue is empty, this condition is called QUEUE UNDERFLOW. Otherwise not empty. Algorithm – Determine the queue is empty or not Begin If FRONT = -1 Then Display “Queue Underflow” Else Display “Queue Not Underflow” [End of if statement] End Page 43 Example – Develop a program to perform all the operations on linear queue. #include<stdio.h> #include<conio.h> #define SIZE 20 int Q[SIZE]; int front = -1, rear = -1; void enqueue(int); int dequeue( ); void display( ); void isempty( ); void isfull( ); void main( ) { int ch, x; clrscr( ); while(1) { printf("\n Queue Operations"); printf("\n 1. Insert operation"); printf("\n 2. Delete operation"); printf("\n 3. Display the values"); printf("\n 4. Determine the queue is empty"); printf("\n 5. Determine the queue is full"); printf("\n Enter the choice (0 for exit) - "); scanf("%d", &ch); switch(ch) { case 1: printf("Enter the value - "); scanf("%d", &x); enqueue(x); break; case 2: printf("Deleted element is = %d", dequeue( )); break; case 3: display( ); break; case 4: isempty( ); break; case 5: isfull( ); break; case 0: Page 44 exit(0); } getch( ); } } void enqueue(int val) { if(front = = 0 && rear = = SIZE - 1) { printf("Queue Overflow"); return; } else if(front = = -1) front = rear = 0; else rear++; Q[rear] = val; } int dequeue( ) { int x; if(front = = - 1) printf("Queue Underflow"); else { x = Q[front]; if(front = = rear) front = rear = -1; else front++; return x; } } void display( ) { int i; if(front = = - 1) printf("Queue Underflow"); else { for(i = front; i <= rear; i++) printf("\n %d", Q[i]); } } Page 45 void isempty( ) { if(front = = - 1) printf("Queue Underflow"); else printf("Queue Not Underflow"); } void isfull( ) { if(front = = 0 && rear = = SIZE - 1) printf("Queue Overflow"); else printf("Queue Not Overflow"); } Circular Queue: An array ‘Queue’ that contains n elements in which Queue[0] comes after Queue[SIZE-1] in the array. When this technique is used to construct a queue then the queue is called Circular queue. In other words, a queue is called circular when the last element comes just before the first element. In a circular queue, when REAR = SIZE – 1, if we insert an element then this element is assigned to Queue[0]. That is instead of increasing REAR to REAR + 1, we reset REAR to 0. Similarly, if FRONT = SIZE – 1 and an element of the queue is deleted, we reset FRONT to 0 instead of FRONT + 1. When the element is removed if both are pointed on same position then the FRONT and REAR are assigned to -1 to indicate that the queue is empty. Insert an element in the queue (Enqueue): Algorithm – Insert an item in circular queue Begin If (FRONT = 0 and REAR = SIZE – 1) or (FRONT = REAR+1) Then Display “Queue Overflow” and return Else if FRONT = -1 Then FRONT = 0 REAR = 0 Else if REAR = SIZE – 1 Then REAR = 0 Else REAR = REAR + 1 [End of if statement] Queue[REAR] = val End Page 46 Delete an element from the queue (Dequeue): Algorithm – Delete an item from circular queue Begin If FRONT = -1 Then Display “Queue Underflow” and return Else val = Queue[FRONT] If FRONT = REAR Then FRONT = -1 REAR = -1 Else if FRONT = SIZE – 1 Then FRONT = 0 Else FRONT = FRONT + 1 [End of if statement] Return(val) [End of if statement] End Traverse the queue: Algorithm – Traverse the circular queue Begin If FRONT = -1 Then Display “Queue Underflow” and return Else if REAR >= FRONT Then For i = FRONT to REAR Step 1 Display Queue[i] [End of for statement] Else For i = FRONT to SIZE – 1 Step 1 Display Queue[i] [End of for statement] For i = 0 to REAR Step 1 Display Queue[i] [End of for statement] [End of if statement] End Example – Develop a program to perform all the operations on circular queue. #include<stdio.h> #include<conio.h> #define SIZE 20 int Q[SIZE]; Page 47 int front = -1, rear = -1; void enqueue(int); int dequeue( ); void display( ); void main( ) { int ch, x; clrscr( ); while(1) { printf("\n Circular Queue Operations"); printf("\n 1. Insert operation"); printf("\n 2. Delete operation"); printf("\n 3. Display the values"); printf("\n Enter the choice (0 for exit) - "); scanf("%d", &ch); switch(ch) { case 1: printf("Enter the value - "); scanf("%d", &x); enqueue(x); break; case 2: printf("Deleted element is = %d", dequeue( )); break; case 3: display( ); break; case 0: exit(0); } getch( ); } } void enqueue(int val) { if(front = = 0 && rear = = SIZE - 1) { printf("Queue Overflow"); return; } else if(front = = -1) front = rear = 0; Page 48 else if(rear = = SIZE - 1) rear = 0; else rear++; Q[rear] = val; } int dequeue( ) { int x; if(front = = - 1) printf("Queue Underflow"); else { x = Q[front]; if(front = = rear) front = rear = -1; else if(front = = SIZE - 1) front = 0; else front++; return x; } } void display( ) { int i; if(front = = - 1) printf("Queue Underflow"); else if(rear >= front) { for(i = front; i <= rear; i++) printf("\n %d", Q[i]); } else { for(i = front; i <= SIZE - 1; i++) printf("\n %d", Q[i]); for(i = 0; i <= rear; i++) printf("\n %d", Q[i]); } } Page 49 Deque (Double Ended Queue): It is a linear list in which insertion and deletions are possible at either front or rear end but not from the middle. Deque is known as Double Ended Queue. Deque is more superior representation of linear list. There are two forms of Deque: Input restricted deque Output restricted deque 1. Input restricted deque: - In this form of deque, insertion can possible only at rear end, but the deletion operation perform on both sides. 2. Output restricted deque: - In this form of deque, deletion can possible only at front end, but the insertion operation perform on both sides. Insert an element in the deque: Algorithm – Insert an item in deque Begin If FRONT = 0 and REAR = SIZE – 1 Then Display “Queue Overflow” and return Else If FRONT = - 1 Then FRONT = REAR = 0 Queue[REAR] = val Else If FRONT > 0 Then FRONT = FRONT – 1 Queue[FRONT] = val Else if REAR < SIZE – 1 Then REAR = REAR + 1 Queue[REAR] = val [End of if statement] End Delete an element from the deque: Algorithm – Delete an item from double ended queue Begin If FRONT = -1 Then Display “Queue Underflow” and return Else If FRONT > -1 Then val = Queue[FRONT] If FRONT = REAR Then FRONT = -1 REAR = -1 Else FRONT = FRONT + 1 [End of if statement] Else If REAR > -1 Then val = Queue[REAR] Page 50 If FRONT = REAR Then FRONT = -1 REAR = -1 Else REAR = REAR - 1 [End of if statement] [End of if statement] Return(val) End Example – Develop a program to perform all the operations on deque. #include<stdio.h> #include<conio.h> #define SIZE 20 int Q[SIZE]; int front = -1, rear = -1; void enqueue(int); int dequeue( ); void display( ); void main( ) { int ch, x; clrscr( ); while(1) { printf("\n Double Ended Queue Operations"); printf("\n 1. Insert operation"); printf("\n 2. Delete operation"); printf("\n 3. Display the values"); printf("\n Enter the choice (0 for exit) - "); scanf("%d", &ch); switch(ch) { case 1: printf("Enter the value - "); scanf("%d", &x); enqueue(x); break; case 2: printf("Deleted element is = %d", dequeue( )); break; case 3: display( ); break; Page 51 case 0: exit(0); } getch( ); } } void enqueue(int val) { if(front = = 0 && rear = = SIZE - 1) { printf("Queue Overflow"); return; } else if(front = = -1) { front = rear = 0; Q[rear] = val; } else if(front > 0) { front--; Q[front] = val; } else if(rear < SIZE - 1) { rear++; Q[rear] = val; } } int dequeue( ) { int x; if(front = = - 1) printf("Queue Underflow"); else if(front > -1) { x = Q[front]; if(front = = rear) front = rear = -1; else front++; } else if(rear > -1) { x = Q[rear]; Page 52 if(front = = rear) front = rear = -1; else rear--; } return x; } void display( ) { int i; if(front = = - 1) printf("Queue Underflow"); else { for(i = front; i <= rear; i++) printf("\n %d", Q[i]); } } Priority Queue: A priority queue is a collection of elements where the elements are processed according to their priorities. The order in which the elements will be inserted or deleted is decided is decided by the following rules: 1. An element of higher priority is processed before any element of lower priority. 2. Two elements with the same priority are processed according to the order in which they are added to the queue. Priority queues are used for implementing job scheduling in a time sharing operating system, where jobs with higher priorities are to be processed first. Implementation of queue using Linked list: When we implement the queue using an array, this data structure had the basic limitations of the array; that is the size cannot be increased or decreased, once it is declared. This difficulty is eliminated when we implement queue using linked lists. In case of linked queue we shall add elements to the queue at the end of the linked list, whereas, we shall delete elements from the beginning of the linked list. Example – struct Queue { int data; struct Queue *next; }*Front, *Rear; Each such queue contains an integer field and a pointer to the next queue element in the linked list. The pointer Front will use to delete the elements from beginning of the linked Page 53 list and the pointer Rear will use to add elements to the queue at the end of the linked list. When the list is empty, Front and Rear will contain NULL. Algorithm to insert an item in the queue: Algorithm – insert(val) Let Queue be a structure (node) having a ‘Data’ field and another field ‘Next’ address pointer which contains the address of next element is queue. The two global variables Front and Rear for implement the queue. Begin Temp = Create a node Temp [Data] = val Temp [Next] = NULL If Front = NULL Then Front = Rear = Temp Else Rear [Next] = Temp Rear = Temp [End of if statement] End Algorithm to delete an item from the queue: Algorithm – deletenode(val) Let Queue be a structure (node) having a ‘Data’ field and another field ‘Next’ address pointer which contains the address of next element is queue. The two global variables Front and Rear for implement the queue. Begin If Front = NULL Then Write “Queue Underflow” and Exit Else Ptr = Front val = Front [Data] Front = Front [Next] Free (Ptr) Return (val) [End of if statement] End Example – Write a program of Queue operations using linked list. #include<stdio.h> #include<conio.h> #include<alloc.h> struct Queue { int data; Page 54 struct Queue *next; }*front, *rear; typedef struct Queue Queue; void insert(int); int deletenode( ); void display( ); void main( ) { int ch, x; front = rear = NULL; clrscr( ); while(1) { printf("\n Queue Operations"); printf("\n 1. Insert operation"); printf("\n 2. Delete operation"); printf("\n 3. Display the values"); printf("\n Enter the choice (0 for exit) - "); scanf("%d", &ch); switch(ch) { case 1: printf("Enter the value - "); scanf("%d", &x); insert(x); break; case 2: x = deletenode( ); printf("Deleted element is = %d", x); break; case 3: display( ); break; case 0: exit(0); } getch( ); } } void insert(int val) { Queue *temp; temp = (Queue *)malloc(sizeof(Queue)); temp -> data = val; Page 55 temp -> next = NULL; if(front = = NULL) front = rear = temp; else { rear->next = temp; rear = temp; } } int deletenode( ) { Queue *ptr; int val; if(front = = NULL) printf("Queue Underflow"); else { ptr = front; val = front->data; front = front->next; free(ptr); return val; } } void display( ) { Queue *ptr; if(front = = NULL) printf("Queue Underflow"); else { for(ptr = front; ptr != NULL; ptr = ptr->next) printf("%d -> ", ptr->data); } } Similarities between Stacks and Queues: 1. Both are data structures in which insertion and deletion operations are restricted to ends only. 2. Both can be implemented using arrays and linked list. 3. Both use temporary memory location. 4. Both have standard functions for inserting and deleting elements. Page 56 Linked List: Array data structure is simple to understand; time to access any element from an array is constant. But some limitations can also be attributed to its simple structure. First, the size of an array has to be defined when the program is being written and its space is reserved during compilation of program. This means that the programmer has to decide the maximum size of array that can not vary during run time. The second problem in array is if we assign less values rather than their size then the remaining memory space would be wasted. We cannot insert exceed values rather than their size and the occupied memory address will not be deleted at run time if not used. To overcome such difficulties we use linked list. Linked list is a way to store the data. It is a linear collection of data element in which each data element points to next element. Data element is also called node. A node is a basic element of a linked list. Each node is divided in two parts: The first part contains the information of the element and the second part contains a pointer which points the address of the next node in the linked list called link field or nextpointer field. Representation of a linked list: struct node { int data; struct node *next; }; A structure node defines a new data type, in which a data item of integer type and a pointer to the next node in the linked list. The pointer start will always point to the first node. When the list is empty, start contains NULL. Start 14 6 17 8 X Static and Dynamic memory allocations: In some data structures, we need to allocate memory before running the program, like incase simple variable declarations as int, float or in case of complex data structures as array declarations. In such cases, we should know in advance that how much memory we will need in program and this is practically not possible in some cases. Such memory allocations are called Static memory allocations and these data structures are static data structures. There may be some data structures which need memory to be allocated on run time like linked list etc. Such memory allocation technique is called dynamic memory allocation. Dynamic data structure provides flexibility in adding and deletion data items at running time. Dynamic memory management permits us to allow additional memory space or to release unwanted space at run time. Disadvantages of Static memory allocation: Page 57 1. Specifying size in advance: We have to specify the size of the array i.e. the size of memory allocation while writing the program. In such cases there may be wastage of memory, if quantity of available data is less than that of declared size or there may be shortage of memory, if quantity of data to be stored is larger than that of declared size. 2. Memory remain allocated throughout program: There may be variables which were in use in starting of program, but program may not use them later, in such cases, the variables remain allocated throughout its execution. Functions of Dynamic memory allocation: 1. sizeof( ): This function gives the size occupied of its argument in bytes. The argument can be variable, constant, array or any data type. Syntax – sizeof(operand) 2. malloc( ): This function is used to allocate memory space. It allocates a memory space of specified size and gives the starting address to pointer variable. Syntax – pointer-var = (data-type *) malloc(specified size); 3. calloc( ): This function is used to allocate multiple blocks of memory. It initializes them to zero and then returns a pointer to the memory. This function generally used for allocating the memory space for array and structure. Syntax – pointer-var = (data-type *) calloc(nitems, size of each item); 4. free( ): We can release the memory space that is not required. We can use free( ) function for releasing the memory space. Syntax – free(pointer-var); 5. realloc( ): There are two possibilities when we want to change the size of the block. In first case, we want more memory space rather than allocated memory space. In second case, the allocated memory space is more than the required memory space. For changing the size of memory block we can use the realloc( ) function. Syntax – pointer-var = realloc(pointer-var, newsize); Advantages of Linked list over Array: 1. In the linked list, we do not need to know in advance the number of elements that will be require. While in array, we would need to allocate all the storage on the program will be started. 2. With a linked list, we can allocate memory for an element dynamically, when we need it, leading to efficient utilization of memory. 3. In linked list, it is easier to insert or delete items by rearranging the pointers but in array insertion or deletion requires large amount of data. 4. Linked list can grow or shrink in size during the execution of program. Page 58 Disadvantages of Linked list over Array: 1. A linked list will use more memory storage than array with the same number of elements is used because each time linked list has more memory for an additional linked field. 2. Array elements can be randomly accessed by giving appropriate index, while linked list elements cannot be randomly accessed. 3. A linked list takes more time in traversing of elements. 4. Binary search cannot be applied in a linked list. Types of Linked list: There are three types of linked list: 1. Single or Linear or One-way linked list In a single linked list, each node has a data part and one link part which contains the address of next node in the list. It is only traverse in one-way direction. 2. Double or Two-way linked list In a doubly linked list, each node has one data field and has two link field i.e. next pointer and previous pointer. The next pointer contains the address of next node in the list and previous pointer contains the address of the previous node in the list. It also allows reverse traversal in the linked list. 3. Circular linked list a. Single Circular linked list: A circular linked list is a singly linked list in which link field of the last node contains the address of the first node of the list, instead of NULL. The coupling between each and every elements of the list becomes a cyclic. b. Double Circular linked list: A double circular linked list is one which has two link fields i.e. next pointer and previous pointer in circular manner. The next pointer of last node points to the first node while the previous pointer of the first node point to the last node in the linked list. Page 59 Linked List operations: There are several operations that can be performed on linked list as follows: 1. Creation of a linked list 2. Traversing of a linked list 3. Counting the nodes in linked list 4. Insertion in linked list 5. Deletion in linked list 6. Searching a node in linked list 7. Sorting a linked list 8. Merging two linked list Single linked list: Creation of a linked list: There are two methods of creating single linked list: a. Using stack b. Using queue a.) Using stack: The stack is a LIFO order list. To create a linked list using stack, follow the steps: 1. Create a memory allocation for new TEMP node. 2. Assign the value to the data part of TEMP node. 3. Assign the START to the next pointer of TEMP node. 4. Now assign the START on TEMP node. Algorithm: - Create-by-stack(Start, val) Begin Temp = create a node Temp [Data] = val Temp [Next] = Start Start = Temp End b.) Using queue: The queue is a FIFO order list. To create a linked list using queue, follow the steps: 1. Create a memory allocation for new TEMP node. 2. Assign the value to the data part of TEMP node. 3. Assign the NULL to the next pointer of TEMP node. Page 60 4. Check if the list is empty then assign the address of TEMP node to START. 5. If list is not empty then first traverse each node of list until end of list does not encountered. Then insert the new node TEMP at the end of list. Algorithm: - Create-by-queue(Start, val) Begin Temp = create a node Temp [Data] = val Temp [Next] = NULL If Start = NULL Then Start = Temp Else Ptr = Start While Ptr [Next] != NULL do Ptr = Ptr [Next] [End of while statement] Ptr [Next] = Temp [End of if statement] End Traversing a linked list: Traversing of linked list means accessing each node’s data exactly once. Traversing may be displaying, adding, squaring or any processing of each node’s data. To display the elements of linked list, follow the steps: 1. Firstly assign a temporary pointer ‘Ptr’ to ‘Start’ node. 2. Traverse the each node of linked list until the ‘Ptr’ has NULL address. Algorithm: - Traverse(Start) Begin If Start = NULL Then Display “List is Empty” Else Ptr = Start While Ptr != NULL do Display Ptr [Data] Ptr = Ptr [Next] [End of while statement] [End of if statement] End Example – Write a program to create a singly linked list using stack and display the elements. #include<stdio.h> #include<conio.h> #include<alloc.h> Page 61 struct node { int data; struct node *next; }; typedef struct node node; node *create(node *, int); void display(node *); void main( ) { int x; node *start = NULL; clrscr( ); while(1) { printf("Enter the number (Type 0 for Exit) - "); scanf("%d", &x); if(x = = 0) break; start = create(start, x); } display(start); getch( ); } node *create(node *start, int val) { node *temp; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = start; start = temp; return start; } void display(node *start) { node *ptr = start; if(start = = NULL) printf("List is empty"); else { while(ptr != NULL) { printf("%d -> ", ptr->data); ptr = ptr->next; Page 62 } } } Example – Write a program to create a singly linked list using queue and display the elements. #include<stdio.h> #include<conio.h> #include<alloc.h> struct node { int data; struct node *next; }; typedef struct node node; node *create(node *, int); void display(node *); void main( ) { int x; node *start = NULL; clrscr( ); while(1) { printf("Enter the number (Type 0 for Exit) - "); scanf("%d", &x); if(x = = 0) break; start = create(start, x); } display(start); getch( ); } node *create(node *start, int val) { node *temp, *ptr; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = NULL; if(start = = NULL) start = temp; else { ptr = start; while(ptr->next != NULL) Page 63 ptr = ptr->next; ptr->next = temp; } return start; } void display(node *start) { node *ptr = start; if(start = = NULL) printf("List is empty"); else { while(ptr != NULL) { printf("%d -> ", ptr->data); ptr = ptr->next; } } } Counting the nodes in a linked list: In this operation, the nodes are counted by traversing each node of linked list without disturbing the ‘Start’ pointer and take a count variable which is incremented by 1 until the ‘Ptr’ reaches the NULL address. Algorithm: - Counting(Start) Begin If Start = NULL Then Display “List is Empty” Else Count = 0 Ptr = Start While Ptr != NULL do Count = Count + 1 Ptr = Ptr [Next] [End of while statement] Return (Count) [End of if statement] End Inserting a node in linked list: The insertion operation is classified into following three categories: 1. Insert at first node 2. Insert at last node 3. Insert at given position Page 64 1.) Insert at first node: - To insert a node at the beginning of a linked list follow the following steps: a. First create a memory allocation for new TEMP node. b. Assign the value to the data part of TEMP node. c. Assign the address of first node to the next pointer of TEMP node. d. Make the new node as the first node in the list by assigning the START on TEMP node. Algorithm: - Insert-at-first(Start, val) Begin Temp = create a node Temp [Data] = val Temp [Next] = Start Start = Temp End 2.) Insert at last node: - To insert a node at the end of a linked list follow these steps: a. First create a memory allocation for new TEMP node. b. Assign the value to the data part of TEMP node. c. Assign the NULL to the next pointer of TEMP node. d. First traverse each node of list until end of list does not encountered. Then insert the new node TEMP at the end of list. Algorithm: - Insert-at-last(Start, val) Begin Temp = create a node Temp [Data] = val Temp [Next] = NULL If Start = NULL Then Start = Temp Else Ptr = Start While Ptr [Next] != NULL do Ptr = Ptr [Next] [End of while statement] Ptr [Next] = Temp [End of if statement] End 3.) Insert at given position: - To insert a node at the specified position of a linked list follow the steps: a. First create a memory allocation for new TEMP node. b. Assign the value to the data part of TEMP node. c. Firstly obtain the desired position of node by traversing the linked list. d. Make the link field of new node to point the next node. Page 65 e. Assign the address of inserted node into the link part of the previous node. Algorithm: - Insert-at-given-position(Start, val, pos) Begin Temp = create a node Temp [Data] = val Ptr = Start For i = 1 to pos – 2 Step 1 Ptr = Ptr [Next] [End of while statement] Temp [Next] = Ptr [Next] Ptr [Next] = Temp End Example – Write a program to create a singly linked list, insert the elements and display them. #include<stdio.h> #include<conio.h> #include<alloc.h> struct node { int data; struct node *next; }; typedef struct node node; node *create(node *,int); void display(node *); node *insertatfirst(node *, int); node *insertatlast(node *, int); node *insertatposition(node *, int, int); void main( ) { int x, ch, p; node *start = NULL; clrscr( ); while(1) { printf("Enter the number (Type 0 for Exit) - "); scanf("%d", &x); if(x = = 0) break; start=create(start, x); } display(start); do Page 66 { printf("\n 1. Insert at first"); printf("\n 2. Insert at last"); printf("\n 3. Insert at given position"); printf("\n Enter the choice - "); scanf("%d",&ch); switch(ch) { case 1: printf("Enter the new value - "); scanf("%d", &x); start = insertatfirst(start, x); break; case 2: printf("Enter the new value - "); scanf("%d", &x); start = insertatlast(start, x); break; case 3: printf("Enter the new value - "); scanf("%d", &x); printf("Enter the position - "); scanf("%d", &p); start = insertatposition(start, x, p); break; } }while(ch>=1 && ch<=3); display(start); getch( ); } node *create(node *start, int val) { node *temp, *ptr; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = NULL; if(start = = NULL) start = temp; else { ptr = start; while(ptr->next != NULL) ptr = ptr->next; ptr->next = temp; } Page 67 return start; } void display(node *start) { node *ptr = start; if(start = = NULL) printf("List is empty"); else { while(ptr != NULL) { printf("%d -> ", ptr->data); ptr = ptr->next; } } } node *insertatfirst(node *start, int val) { node *temp; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = start; start = temp; return start; } node *insertatlast(node *start, int val) { node *temp, *ptr = start; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = NULL; while(ptr->next != NULL) ptr = ptr->next; ptr->next = temp; return start; } node *insertatposition(node *start, int val, int pos) { node *temp, *ptr = start; int i; temp = (node *)malloc(sizeof(node)); temp->data = val; for(i = 1; i < pos - 1; i++) ptr = ptr->next; Page 68 temp->next = ptr->next; ptr->next = temp; return start; } Deletion in linked list: The deletion operation is classified into following three categories: 1. Delete from first node 2. Delete from last node 3. Delete from given position 1.) Delete from first node: - To delete a node from the beginning of a linked list follow these steps: a. Firstly check if the list is empty then give the appropriate message otherwise do the next steps. b. First point a temporary pointer Ptr to Start node. c. Assign the next pointer of Start address to the Start. d. Deallocate the Ptr pointer. Algorithm: - Delete-from-first(Start) Begin If Start = NULL Then Display “List is empty” Else Ptr = Start Start = Start [Next] Free (Ptr) [End of if statement] End 2.) Delete from last node: - To delete a node from the end of a linked list follow the following steps: a. Firstly check if the list is empty then give the appropriate message otherwise do the next steps. b. First point a temporary pointer ‘Ptr’ to Start node. c. Traverse the linked list till the last node and take another pointer Ptr1 which points to the previous node of the current node ‘Ptr’. d. Assign the NULL to next pointer of second last node ‘Ptr1’. e. Deallocate the Ptr pointer. Algorithm: - Delete-from-last(Start) Begin If Start = NULL Then Display “List is empty” Page 69 Else Ptr = Start While Ptr [Next] != NULL Ptr1 = Ptr Ptr = Ptr [Next] [End of while statement] Ptr1 [Next] = NULL Free (Ptr) [End of if statement] End 3.) Delete node from the given position: - To delete a node from the given position of a linked list follow these steps: a. Firstly check if the list is empty then give the appropriate message otherwise do the next steps. b. First point a temporary pointer ‘Ptr’ to Start node. c. Firstly obtain the desired position of node by traversing the linked list. d. The other pointer Ptr1 which points the previous node of Ptr. The next pointer of Ptr1 assigns the address of next pointer of Ptr. e. Deallocate the Ptr pointer. Algorithm: - Delete-from-given-position(Start, Pos) Begin If Start = NULL Then Display “List is empty” Else Ptr = Start For i = 1 to Pos – 1 Step 1 Ptr1 = Ptr Ptr = Ptr [Next] [End of while statement] Ptr1 [Next] = Ptr [Next] Free (Ptr) [End of if statement] End Example – Write a program to create a singly linked list, delete the elements and display them. #include<stdio.h> #include<conio.h> #include<alloc.h> struct node { int data; struct node *next; Page 70 }; typedef struct node node; node *create(node *, int); void display(node *); node *deletefromfirst(node *); node *deletefromlast(node *); node *deletefromposition(node *, int); void main( ) { int x, ch, p; node *start = NULL; clrscr( ); while(1) { printf("Enter the number (Type 0 for Exit) - "); scanf("%d", &x); if(x = = 0) break; start=create(start, x); } display(start); printf("\n 1. Delete from first"); printf("\n 2. Delete from last"); printf("\n 3. Delete from given position"); printf("\n Enter the choice - "); scanf("%d",&ch); switch(ch) { case 1: start = deletefromfirst(start); break; case 2: start = deletefromlast(start); break; case 3: printf("Enter the position - "); scanf("%d", &p); start = deletefromposition(start, p); break; } display(start); getch( ); } node *create(node *start, int val) { Page 71 node *temp, *ptr; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = NULL; if(start = = NULL) start = temp; else { ptr = start; while(ptr->next != NULL) ptr = ptr->next; ptr->next = temp; } return start; } void display(node *start) { node *ptr = start; if(start = = NULL) printf("List is empty"); else { while(ptr != NULL) { printf("%d -> ", ptr->data); ptr = ptr->next; } } } node *deletefromfirst(node *start) { node *ptr; if(start = = NULL) printf("List is empty"); else { ptr = start; start = start->next; free(ptr); } return start; } node *deletefromlast(node *start) Page 72 { node *ptr, *ptr1; if(start = = NULL) printf("List is empty"); else { ptr = start; while(ptr->next != NULL) { ptr1 = ptr; ptr = ptr->next; } ptr1->next = NULL; free(ptr); } return start; } node *deletefromposition(node *start, int pos) { node *ptr, *ptr1; int i; if(start = = NULL) printf("List is empty"); else { ptr = start; for(i = 1; i < pos; i++) { ptr1 = ptr; ptr = ptr->next; } ptr1->next = ptr->next; free(ptr); } return start; } Searching a node in linked list: Searching means finding information in the given linked list. For searching an element, we first traverse the linked list and during traversing, we compare the data part of each node with the searching element. Algorithm: - Search(Start, num) Begin If Start = NULL Then Page 73 Display “List is empty” Else Loc = 1 Ptr = Start While Ptr != NULL do If num = Ptr [Data] Then Return Loc [End of if statement] Ptr = Ptr [Next] Loc = Loc + 1 [End of while statement] Return -1 [End of if statement] End Example – Write a program to create a singly linked list and search the element in list. #include<stdio.h> #include<conio.h> #include<alloc.h> struct node { int data; struct node *next; }; typedef struct node node; node *create(node *, int); int search(node *, int); void main( ) { int x, s, loc; node *start = NULL; clrscr( ); while(1) { printf("Enter the number (Type 0 for Exit) - "); scanf("%d", &x); if(x = = 0) break; start = create(start, x); } printf("Enter the number to be searched - "); scanf("%d", &s); loc = search(start, s); if(loc = = -1) printf("Value not found"); Page 74 else printf("Value found on position = %d", loc); getch( ); } node *create(node *start, int val) { node *temp, *ptr; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = NULL; if(start = = NULL) start = temp; else { ptr = start; while(ptr->next != NULL) ptr = ptr->next; ptr->next = temp; } return start; } int search(node *start, int num) { node *ptr; int loc = 1; if(start = = NULL) printf("List is empty"); else { ptr = start; while(ptr != NULL) { if(num = = ptr->data) return loc; ptr = ptr->next; loc++; } return -1; } } Sorting a linked list: Sometimes it is also required to sorting a list in ascending or descending order. In the sorting operation, first assign a temporary pointer Ptr to Start pointer and then traverse each node and compare the current node with next node’s data. If the current node’s data is greater Page 75 than next node’s data then interchange the data values. This process continues till the entire list will not be sorted. Algorithm: - Sort(Start) Begin If Start = NULL Then Display “List is empty” Else Ptr = Start While Ptr [Next] != NULL do Ptr1 = Ptr [Next] While Ptr1 != NULL do If Ptr [Data] > Ptr1 [Data] Then Temp = Ptr [Data] Ptr [Data] = Ptr1 [Data] Ptr1 [Data] = Temp [End of if statement] Ptr1 = Ptr1 [Next] [End of while statement] Ptr = Ptr [Next] [End of while statement] [End of if statement] End Example – Write a program to sort the elements of singly linked list. #include<stdio.h> #include<conio.h> #include<alloc.h> struct node { int data; struct node *next; }; typedef struct node node; node *create(node *, int); void display(node *); node *sort(node *); void main( ) { int x; node *start=NULL; clrscr( ); while(1) { printf("Enter the number (Type 0 for Exit) - "); Page 76 scanf("%d", &x); if(x = = 0) break; start=create(start, x); } printf("\n Before sorting.........\n"); display(start); start = sort(start); printf("\n After sorting..........\n"); display(start); getch( ); } node *create(node *start, int val) { node *temp, *ptr; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = NULL; if(start = = NULL) start = temp; else { ptr = start; while(ptr->next != NULL) ptr = ptr->next; ptr->next = temp; } return start; } void display(node *start) { node *ptr = start; if(start = = NULL) printf("List is empty"); else { while(ptr != NULL) { printf("%d -> ", ptr->data); ptr = ptr->next; } } } node *sort(node *start) { Page 77 node *ptr, *ptr1; int temp; if(start = = NULL) printf("List is empty"); else { for(ptr = start; ptr->next != NULL; ptr = ptr->next) { for(ptr1 = ptr->next; ptr1 != NULL; ptr1 = ptr1->next) { if(ptr->data > ptr1->data) { temp = ptr->data; ptr->data = ptr1->data; ptr1->data = temp; } } } } return start; } Merging two linked list: To merge two separate single linked list, firstly traverse the first list till the last node and then assign the address of first node of the second linked list to the next pointer field of the last node of first list. Algorithm: - Merge(Start, Start1) Begin Ptr = Start While Ptr [Next] != NULL do Ptr = Ptr [Next] [End of while statement] Ptr [Next] = Start1 End Double Linked List: Structure of Double linked list: struct node { struct node *prev; int data; struct node *next; }; Creation of a double linked list: To create a double linked list, follow the following steps: Page 78 1. 2. 3. 4. 5. 6. 7. 8. Create a memory allocation for new TEMP node. Assign the value to the data part of TEMP node. Assign the NULL to the next pointer of TEMP node. Check if the list is empty then assign the NULL into previous pointer of TEMP node. Initiate the Start and End pointer to TEMP node. If list is not empty then assign the address of End pointer to the previous pointer part of the Temp node. Assign the address of Temp node to the next pointer of End node. Set the End pointer on New Temp node. Algorithm: - Create(Start, val) Begin Temp = create a node Temp [Data] = val Temp [Next] = NULL If Start = NULL Then Temp [Prev] = NULL Start = End = Temp Else Temp [Prev] = End End [Next] = Temp End = Temp [End of if statement] End Traversing a double linked list: Traversing of double linked list means accessing each node’s data exactly once. Traversing may be either in serial or reverse direction. To display the elements of linked list in serial order, follow the steps: 1. Firstly assign a temporary pointer ‘Ptr’ to ‘Start’ node. 2. Traverse the each node of linked list until the next pointer of ‘Ptr’ has NULL address. To display the elements of linked list in reverse order, follow the steps: 1. Firstly assign a temporary pointer ‘Ptr’ to ‘End’ node. 2. Traverse the each node of linked list until the previous pointer of ‘Ptr’ has NULL address. Algorithm: - Traverse(Start) Begin If Start = NULL Then Display “List is Empty” Else Display “In serial order……..” Ptr = Start Page 79 While Ptr != NULL do Display Ptr [Data] Ptr = Ptr [Next] [End of while statement] Display “In reverse order……..” Ptr = End While Ptr != NULL do Display Ptr [Data] Ptr = Ptr [Prev] [End of while statement] [End of if statement] End Example – Write a program to create a doubly linked list and display them. #include<stdio.h> #include<conio.h> #include<alloc.h> struct node { int data; struct node *prev, *next; }; typedef struct node node; node *start, *end; void create(int); void display( ); void main( ) { int x; start = end = NULL; clrscr( ); while(1) { printf("Enter the number (Type 0 for Exit) - "); scanf("%d", &x); if(x = = 0) break; create(x); } display( ); getch( ); } void create(int val) { node *temp; Page 80 temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = NULL; if(start = = NULL) { temp->prev = NULL; start = end = temp; } else { temp->prev = end; end->next = temp; end = temp; } } void display( ) { node *ptr; if(start = = NULL) printf("List is empty"); else { printf("\n Display in serial order........\n"); ptr = start; while(ptr != NULL) { printf("%d -> ", ptr->data); ptr = ptr->next; } printf("\n Display in reverse order........\n"); ptr = end; while(ptr != NULL) { printf("%d -> ", ptr->data); ptr = ptr->prev; } } } Inserting a node in doubly linked list: The insertion operation is classified into following three categories: 1. Insert at first node 2. Insert at last node Page 81 3. Insert at given position 1.) Insert at first node: - To insert a node at the beginning of a doubly linked list follow these steps: a. First create a memory allocation for a new TEMP node. b. Assign the value to the data part of TEMP node. c. Assign the NULL to the previous part of TEMP node. d. Assign the address of START node to the next pointer part of TEMP node. e. Assign the address of TEMP node to the previous pointer part of START node. f. Make the new node as the first node in the list by assigning the START on TEMP node. Algorithm: - Insert-at-first(val) Begin Temp = create a node Temp [Data] = val Temp[Prev]=NULL Temp [Next] = Start Start[Prev] = Temp Start = Temp End 2.) Insert at last node: - To insert a node at the end of a double linked list follow these steps: a. First create a memory allocation for new TEMP node. b. Assign the value to the data part of TEMP node. c. Assign the NULL to the next pointer of TEMP node. d. Assign the address of END node to the previous pointer of TEMP node. e. Assign the address of TEMP node to the next pointer of END node. f. Finally, Set the END pointer to the TEMP node. Algorithm: - Insert-at-last(val) Begin Temp = create a node Temp [Data] = val Temp [Next] = NULL Temp [Prev] = End End [Next] = Temp End = Temp End 3.) Insert at given position: - To insert a node at the specified position of a doubly linked list follow these steps: a. First create a memory allocation for new TEMP node. b. Assign the value to the data part of TEMP node. Page 82 c. d. e. f. g. Then obtain the desired position of node by traversing the linked list. Make the link field of new node to point the next node. Assign the address of TEMP node into the link part of the previous node. Assign the address of previous node to the previous pointer of TEMP node. Assign the address of TEMP node to the previous part of next node and next part of previous node. Algorithm: - Insert-at-given-position(val, pos) Begin Temp = create a node Temp [Data] = val Ptr = Start For i = 1 to pos – 2 Step 1 Ptr = Ptr [Next] [End of while statement] Temp [Next] = Ptr [Next] Temp [Prev] = Ptr Ptr [Next] [Prev] = Temp Ptr [Next] = Temp End Example – Write a program to create a singly linked list, insert the elements and display them. #include<stdio.h> #include<conio.h> #include<alloc.h> struct node { int data; struct node *prev, *next; }; typedef struct node node; node *start, *end; void create(int); void display( ); void insertatfirst(int); void insertatlast(int); void insertatposition(int, int); void main( ) { int x, ch, p; start = end = NULL; clrscr( ); while(1) { Page 83 printf("Enter the number (Type 0 for Exit) - "); scanf("%d", &x); if(x == 0) break; create(x); } display( ); do { printf("\n 1. Insert at first"); printf("\n 2. Insert at last"); printf("\n 3. Insert at given position"); printf("\n Enter the choice - "); scanf("%d", &ch); switch(ch) { case 1: printf("Enter the new value - "); scanf("%d", &x); insertatfirst(x); break; case 2: printf("Enter the new value - "); scanf("%d", &x); insertatlast(x); break; case 3: printf("Enter the new value - "); scanf("%d", &x); printf("Enter the position - "); scanf("%d", &p); insertatposition(x, p); break; } }while(ch>=1 && ch<=3); display( ); getch( ); } void create(int val) { node *temp; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = NULL; if(start = = NULL) Page 84 { temp->prev = NULL; start = end = temp; } else { temp->prev = end; end->next = temp; end = temp; } } void display( ) { node *ptr; if(start = = NULL) printf("List is empty"); else { printf("\n Display in serial order........\n"); ptr = start; while(ptr != NULL) { printf("%d -> ", ptr->data); ptr = ptr->next; } printf("\n Display in reverse order........\n"); ptr = end; while(ptr != NULL) { printf("%d -> ", ptr->data); ptr = ptr->prev; } } } void insertatfirst(int val) { node *temp; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = start; temp->prev = NULL; start->prev = temp; start = temp; } Page 85 void insertatlast(int val) { node *temp; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->next = NULL; temp->prev = end; end->next = temp; end = temp; } void insertatposition(int val, int pos) { node *temp, *ptr = start; int i; temp = (node *)malloc(sizeof(node)); temp->data = val; for(i = 1; i < pos - 1; i++) ptr = ptr->next; temp->next = ptr->next; temp->prev = ptr; ptr->next->prev = temp; ptr->next = temp; } Deletion in doubly linked list: The deletion operation is classified into following three categories: 1. Delete from first node 2. Delete from last node 3. Delete from given position 1.) Delete from first node: - To delete a node from the beginning of a double linked list follow these steps: a. Firstly check if the list is empty then give the appropriate message otherwise do the next steps. b. Then point a temporary pointer ‘Ptr’ to ‘Start’ node. c. Move the ‘Start’ pointer to the next node. d. Assign the NULL to the previous pointer part of current ‘Start’ node. e. Deallocate the memory of ‘Ptr’ pointer. Algorithm: - Delete-from-first Begin If Start = NULL Then Display “List is empty” Else Page 86 Ptr = Start Start = Start [Next] Start [Prev] = NULL Free (Ptr) [End of if statement] End 2.) Delete from last node: - To delete a node from the end of a double linked list follow these steps: a. Firstly check if the list is empty then give the message otherwise do the next steps. b. First point a temporary pointer ‘Ptr’ to End node. c. Assign the NULL to next pointer of second last node. d. Deallocate the Ptr pointer. Algorithm: - Delete-from-last Begin If Start = NULL Then Display “List is empty” Else Ptr = End End = End[Prev] End [Next] = NULL Free (Ptr) [End of if statement] End 3.) Delete node from the given position: - To delete a node from the given position of a double linked list follow these steps: a. Firstly check if the list is empty then give the appropriate message otherwise do the next steps. b. Then point a temporary pointer ‘Ptr’ to Start node. c. After that obtain the desired position of node by traversing the linked list. d. The other pointer Ptr1 which points the previous node of Ptr. The next pointer of Ptr1 assigns the address of next pointer of Ptr. e. Assign the address of Ptr1 to the previous pointer of next node. f. Deallocate the Ptr pointer. Algorithm: - Delete-from-given-position(Pos) Begin If Start = NULL Then Display “List is empty” Else Ptr = Start For i = 1 to Pos – 1 Step 1 Page 87 Ptr = Ptr [Next] [End of while statement] Ptr [Prev][Next] = Ptr [Next] Ptr [Next][Prev] = Ptr [Prev] Free (Ptr) [End of if statement] End Single Circular Linked List: A circular linked list is a singly linked list in which the link field of the last node contains the address of first node of the list, i.e. last node does not contain NULL. With this type of arrangement, the coupling between each and every elements of the list becomes cyclic. A circular linked list has no end. Creation of a single circular linked list: Creation of a circular linked list is same as singly linked list only one thing is vary i.e. the last node will always point the address of the first node instead of NULL. To create a circular linked list, follows these steps: 1. Create a new node TEMP by allocating the memory. 2. Assign the value to the data part of TEMP node. 3. Check if START pointer has NULL then it is the first node and assign the address of TEMP node to the next pointer of TEMP node. 4. If the START pointer has nodes then first traverse the list till last node until the next pointer of a node does not have the address of START node. 5. Assign the address of TEMP node to the next pointer part of last node and assign the address of START node to the new TEMP node. Algorithm: - Create(Start, val) Begin Temp = create a node Temp [Data] = val If Start = NULL Then Temp [Next] = Temp Start = Temp Else Ptr=Start While Ptr [Next] != Start Ptr = Ptr [Next] [End of While loop] Ptr [Next] = Temp Temp [Next] = Start [End of if statement] End Traversing a linked list: Page 88 Traversing of linked list means accessing each node one by one. Traversing may be displaying or any other processing of each node’s data. To display the elements of linked list, follow these steps: 1. Firstly assign a temporary pointer ‘Ptr’ to ‘Start’ node. 2. Traverse the each node of linked list until the ‘Ptr’ has again point to the Start node. Algorithm: - Traverse(Start) Begin If Start = NULL Then Display “List is Empty” Else Ptr = Start Do Display Ptr [Data] Ptr = Ptr [Next] While (Ptr != Start) [End of if statement] End Inserting a node in single circular linked list: The insertion operation is classified into following three categories: 1. Insert at first node 2. Insert at last node 3. Insert at given position 1.) Insert at first node: - To insert a node at the beginning of a single circular linked list follow these steps: a. First create a memory allocation for new TEMP node. b. Assign the value to the data part of TEMP node. c. Store the address of START node in the link field of new TEMP node. d. Traverse the list till the last node by using Ptr pointer and then assign the address of new node to the next pointer of last node. e. Assign the Start pointer to TEMP node. Algorithm: - Insert-at-first(Start, val) Begin Temp = create a node Temp [Data] = val Temp [Next] = Start Ptr = Start While Ptr [Next] != Start Ptr = Ptr [Next] [End of while statement] Ptr [Next] = Temp Start = Temp Page 89 End 2.) Insert at last node: - To insert a node at the end of a circular linked list follow the steps: a. First create a memory allocation for new TEMP node. b. Assign the value to the data part of TEMP node. c. Assign the temporary pointer Ptr to START node and traverse the list till the end node. d. Then assign the address of new node TEMP to the next pointer of last node. e. Finally, assign the Start address to the next pointer of TEMP node. Algorithm: - Insert-at-last(Start, val) Begin Temp = create a node Temp [Data] = val Temp [Next] = Start Ptr = Start While Ptr [Next] != Start Ptr = Ptr [Next] [End of while statement] Ptr [Next] = Temp End 3.) Insert at given position: - To insert a node at the specified position of a circular linked list follow the steps: a. First create a memory allocation for new TEMP node. b. Assign the value to the data part of TEMP node. c. Firstly obtain the desired position of node by traversing the linked list. d. Make the link field of new node to point the next node. e. Assign the address of inserted node into the link part of the previous node. Algorithm: - Insert-at-given-position(Start, val, pos) Begin Temp = create a node Temp [Data] = val Ptr = Start For i = 1 to pos – 2 Step 1 Ptr = Ptr [Next] [End of while statement] Temp [Next] = Ptr [Next] Ptr [Next] = Temp End Deletion in circular linked list: The deletion operation is classified into following three categories: Page 90 1. Delete from first node 2. Delete from last node 3. Delete from given position 1.) Delete from first node: - To delete a node from the beginning of a circular linked list follow these steps: a. Firstly check if the list is empty then display the appropriate message otherwise do the next steps. b. First point a temporary pointer Ptr to Start node. c. Assign another pointer ‘Ptr1’ to Start node and traverse till the end node. d. Assign the next pointer of Start address to the Start. e. Assign the address of second node to the next pointer of Ptr1. f. Deallocate the Ptr pointer. Algorithm: - Delete-from-first(Start) Begin If Start = NULL Then Display “List is empty” Else Ptr = Ptr1 = Start While Ptr1 [Next] != Start Ptr1 = Ptr1 [Next] [End of while statement] Start = Start [Next] Ptr1 [Next] = Start Free (Ptr) [End of if statement] End 2.) Delete from last node: - To delete a node from the end of a circular linked list follow these steps: a. Firstly check if the list is empty then display the appropriate message otherwise do the next steps. b. First point a temporary pointer ‘Ptr’ to Start node. c. Traverse the linked list till the last node and take another pointer Ptr1 which points to the previous node of the current node ‘Ptr’. d. After that assign the address of Start node to the next pointer of node ‘Ptr1’. e. Deallocate the Ptr pointer. Algorithm: - Delete-from-last(Start) Begin If Start = NULL Then Display “List is empty” Else Ptr = Start While Ptr [Next] != Start Page 91 Ptr1 = Ptr Ptr = Ptr [Next] [End of while statement] Ptr1 [Next] = Start Free (Ptr) [End of if statement] End 3.) Delete node from the given position: - To delete a node from the given position of a linked list follow these steps: a. Firstly check if the list is empty then give the message otherwise do the next steps. b. First point a temporary pointer ‘Ptr’ to Start node. c. Firstly obtain the desired position of node by traversing the linked list. d. The other pointer Ptr1 which points the previous node of Ptr. The next pointer of Ptr1 assigns the address of next pointer of Ptr. e. Deallocate the Ptr pointer. Algorithm: - Delete-from-given-position(Start, Pos) Begin If Start = NULL Then Display “List is empty” Else Ptr = Start For I = 1 to Pos – 1 Step 1 Ptr1 = Ptr Ptr = Ptr [Next] [End of while statement] Ptr1 [Next] = Ptr [Next] Free (Ptr) [End of if statement] End Advantages of Circular Linked list: 1. Cyclic traversal of a linked list can be possible at a very high speed especially when we are working with a very large database. 2. No extra memory is required to implement a circular linked list. Sorted Singly Linked list: In case of creation of sorted linked list when we add the elements in the linked list then it should be inserted at the proper place. If the list is empty then directly assign the first node to START pointer, but if the value is less than the value of first node then add at beginning or if greater then either it is lies between or at the end of list. Algorithm: - Create(Start, val) Begin Temp = Create a node Page 92 Temp [Data] = val If Start = NULL Then Temp [Next] = NULL Start = Temp Else If val < Start [Data] Then Temp [Next] = Start Start = Temp Else Ptr = Start While Ptr [Next] != NULL And Ptr [Next][Data] < val Ptr = Ptr [Next] [End of while statement] Temp [Next] = Ptr [Next] Ptr [Next] = Temp [End of if statement] End Example – Write a program to create a sorted linked list and display them. #include<stdio.h> #include<conio.h> #include<alloc.h> struct node { int data; struct node *next; }; typedef struct node node; node *create(node *, int); void display(node *); void main( ) { int x; node *start=NULL; clrscr( ); while(1) { printf("Enter the number (Type 0 for Exit) - "); scanf("%d", &x); if(x = = 0) break; start = create(start, x); } display(start); getch( ); } Page 93 node *create(node *start, int val) { node *temp, *ptr; temp = (node *)malloc(sizeof(node)); temp->data = val; if(start = = NULL) { temp->next = NULL; start = temp; } else if(val < start->data) { temp->next = start; start = temp; } else { ptr = start; while(ptr->next != NULL && ptr->next->data < val) ptr = ptr->next; temp->next = ptr->next; ptr->next = temp; } return start; } void display(node *start) { node *ptr = start; if(start = = NULL) printf("List is empty"); else { while(ptr != NULL) { printf("%d -> ", ptr->data); ptr = ptr->next; } } } Header Linked List: A header linked list always contains a special node, called the header node, at the beginning of the list. This type of list is useful when information other than that found in each node is needed. E.g. – suppose there is an application in which the number of items in a list is Page 94 often calculated. Usually a list is always traversed to find the length of the list. However, if the current length is maintained in an additional header node, that information can be easily obtained. There are two kinds of widely used header lists: 1. Grounded Header Linked list 2. Circular Header Linked list 1.) Grounded Header Linked list: It is a header list where the last node contains NULL pointer. In the header linked list the ‘Start’ pointer always points to the header node. Next pointer of Start assigns NULL indicates that a grounded header linked list is empty. The operations that are possible on this type of linked list are: Insertion Deletion Traversing Creating the grounded header linked list: Algorithm: - Create(Start, val, Count) Begin Temp = Create a node Temp [Data] = val Temp [Next] = NULL If Count = 0 Then Start [Next] = Temp Count = Count + 1 Start [Data] = Count Else Ptr = Start [Next] While Ptr [Next] != NULL Ptr = Ptr [Next] [End of while statement] Ptr [Next] = Temp Count = Count + 1 Start [Data] = Count [End of if statement] End Traversing grounded header linked list: Algorithm: - Traverse(Start) Begin If Start = NULL Then Display “List is empty” Else Page 95 Ptr = Start Count = Ptr [Data] Ptr = Ptr [Next] While Count != 0 Display Ptr [Data] Ptr = Ptr [Next] Count = Count – 1 [End of while statement] [End of if statement] End 2.) Circular Header Linked list: It is a header linked list where the last node points back to the header node. The chains do not indicate first or last nodes. In this case, external pointers provide a frame of reference because last node of a circular linked list does not contain the NULL pointer. The possible operations on this type of linked list are: Insertion Deletion Traversing Creating the circular header linked list: Algorithm: - Create(Start, val, Count) Begin Temp = Create a node Temp [Data] = val Temp [Next] = Start If Count = 0 Then Start [Next] = Temp Count = Count + 1 Start [Data] = Count Else Ptr = Start [Next] While Ptr [Next] != Start Ptr = Ptr [Next] [End of while statement] Ptr [Next] = Temp Count = Count + 1 Start [Data] = Count [End of if statement] End Traversing circular header linked list: Algorithm: - Traverse(Start) Page 96 Begin If Start = NULL Then Display “List is empty” Else Ptr = Start Count = Ptr [Data] Ptr = Ptr [Next] While Ptr != Start Display Ptr [Data] Ptr = Ptr [Next] Count = Count – 1 [End of while statement] [End of if statement] End Page 97 Unit - III Trees: Trees are the most important data structures in computer science. Trees are used to represent data containing a hierarchical relationship between parent and their child. A tree is a non-linear data structure in which data elements are arranged in a sorted sequence. A tree can be defined as a finite set of one or more nodes such that: 1. There is a specially designed node called the root. 2. The remaining nodes are partitioned into number of disjoint set T1, T2, …….., Tn where each of these sets is a tree T1, T2, …….., Tn, are called the subtrees of the root. Tree Terminology: 1. Root: - It is specially designed data item in a tree. The root of tree is the origin of tree from where the tree starts. 2. Node: - Each data item in a tree called a node. A node holds the item of information and branches to other nodes. 3. Degree of node: - The number of subtrees of a node is called its degree. 4. Degree of a tree: - Degree of a tree is the total number of subtrees or number of levels in a tree. The degree of above tree is 3. 5. Leaf node or Terminal node or External node: - A node that has no child is called leaf node or a node that has degree 0 is called leaf or terminal or external node. In the above figure D, H, E, F and G are leaf nodes. 6. Non-leaf or non-terminal or internal node: - Any node whose degree is not 0 except the root node is called the non-leaf, non-terminal or internal node. In the above figure B and C are internal nodes. 7. Siblings: - The children nodes of the same parent are said to be siblings. In the above figure H and E are the siblings of D node. 8. Edges: - It is connecting line down from one node to another node. 9. Path: - It is a sequence of consecutive edges from the source node to the destination node. In the above figure, the path between A and E is given by the nodes pairs (A, B) & (B, E). 10. Levels: - Each node in a tree is assigned a level number. The root node of the tree is assigned a level number 0 then its children at level 1 and their childrens are at level 2 and so on up to the terminal nodes. 11. Branch: - A path ending on a leaf node is called branch. 12. Depth: - Depth or height of a tree is the maximum number of nodes in a branch of tree i.e. one more than the largest level number of tree. Page 98 13. Forest: - It is a set of disjoint trees. In a given tree, if we remove its root node then it becomes a forest. 14. Predecessor or Ancestor: - A node is called ancestor of another node, if it is parent of that node. In the above figue, node A is ancestor of nodes B and C. 15. Successor or Descendant: - A node is called successor of another node, if it is child of that node. In the above figure, B and C are successor of node A. Binary Tree: A tree is a binary tree if each node of it can have at most two childrens or branches. A binary tree ‘T’ is a finite set of nodes which is either empty (called empty or null tree) or consists of special node called root ‘R’ of the tree ‘T’ and two disjoint binary tree ‘T1’ and ‘T2’ which are called left subtrees and right subtrees. In binary tree, the maximum degree of any node is at most two. That means, there may be a zero degree node or one degree node and two degree node. Strictly Binary Tree: If every non terminal node in a binary tree consists of non empty left subtrees and right subtrees, then such a tree is called strictly binary tree. Complete Binary Tree: A complete binary tree is called a binary tree if each node of a tree have either exactly two children or no child at all, and all of leaves are at same level. A complete binary tree at the level L can have 2L nodes. E.g. – If L = 0, then 20 = 1 i.e. 1 node that is a root. If L = 1, then 21 = 2 i.e. 2 nodes at level 1. If L = 2, then 22 = 4 i.e. 4 nodes at level 2 and so on. Page 99 Full Binary Tree: A binary tree in which all the leaf nodes are on the same level and every non leaf node has two children is called full binary tree. A full binary tree must have 2L node at each level L. Extended Binary Tree or 2-Tree: A binary tree is called extended binary tree if each node has either 0 or 2 children. Nodes with 2 children are called ‘internal node’ and the nodes, which have no children, are called ‘external nodes’. Skewed Tree: A skewed tree is a binary tree that is skewed to either left side or right side. Left Skewed Tree Right Skewed Tree Similar Tree and Equivalent Tree: The binary tree T and T’ are similar if they have same structures or if they have same shape but with different values is called similar tree. The tree are said to be equivalent or copies if they are similar and they have same contents at the corresponding nodes. Representation of a binary tree: There are following two ways to implement a binary tree: 1. Sequential or Array representation 2. Linked list representation Page 100 1.) Sequential or Array representation: If a binary tree is complete or nearly complete binary tree can be efficiently represented by sequential representation. This representation uses a one dimensional array. An array can be used to store the nodes of binary tree. It requires the numbering of nodes. In array, the root node is always numbered by 0 and then its left child and right child are stored at 1 and 2 respectively. The array representation of this binary tree is as follows: A 0 B 1 C 2 3 4 D 5 E 6 7 8 9 10 F 11 G 12 13 14 2.) Linked list representation: The array representation is good for complete binary tree, but it is wasteful for many other binary trees like skewed tree. In array representation, the insertion and deletion of nodes from the middle of a tree requires the movement of many nodes. This problem can be overcome easily through the use of a linked list representation. Basic component in a binary tree is a node. Each node has three fields, one for the link of left child, second for the data and third for the link of right child. Left child contains the address of its left node and right child contains the address of its right node. Left Child Data Right Child The representation of a node in C is: struct node { struct node *leftchild; int data; struct node *rightchild; }; typedef struct node node; Page 101 Operations on Binary Tree: 1. Creation of Binary Tree 2. Traversal of Binary Tree 3. Insertion of Nodes 4. Deletion of Nodes 5. Searching for the Nodes Creation of Binary Tree: Algorithm – Create_Tree(T, val) Where val is element for which we have to create node and T is structure type variable to points both left and right child. Begin If T = NULL Then T = create a node T [Data] = val T [Left_child] = NULL T [Right_child] = NULL Else if T [Data] >= val Then T [Left_child] = Call Create_Tree(T[Left_child], val) Else T [Right_child] = Call Create_Tree(T[Right_child], val) [End of if statement] Return (T) End Traversal of a Binary Tree: Traversing is a way in which each node in the binary tree is visited exactly once. There are three standard ways of a binary tree traversal. These methods are known as: 1. Inorder Traversal 2. Preorder Traversal 3. Postorder Traversal The tree traversal methods are written either in recursive or non recursive algorithm. 1.) Preorder Traversal: To traverse a non empty binary tree in preorder, we perform the following operations: a. Process the root b. Traverse the left subtrees c. Traverse the right subtrees Algorithm – Preorder(T) Begin If T != NULL Then Display T [Data] Call Preorder(T [Left_child]) Page 102 Call Preorder(T [Right_child]) [End of if statement] End 2.) Inorder Traversal: To traverse a non empty binary tree in inorder, we perform the following operations: a. Traverse the left subtrees b. Process the root c. Traverse the right subtrees Algorithm – Inorder(T) Begin If T != NULL Then Call Inorder(T [Left_child]) Display T [Data] Call Inorder(T [Right_child]) [End of if statement] End 3.) Postorder Traversal: To traverse a non empty binary tree in postorder, we perform the following operations: a. Traverse the left subtrees b. Traverse the right subtrees c. Process the root Algorithm – Postorder(T) Begin If T != NULL Then Call Postorder(T [Left_child]) Call Postorder(T [Right_child]) Display T [Data] [End of if statement] End Example – Write a program to create a binary tree using recursive algorithm and traverse it. #include<stdio.h> #include<conio.h> struct node { int data; struct node *left_child, *right_child; }; typedef struct node node; Page 103 node *create_tree(node *, int); void preorder(node *); void inorder(node *); void postorder(node *); void main( ) { int x; node *T = NULL; clrscr( ); while(1) { printf("Enter the number (type 0 for exit) - "); scanf("%d",&x); if(x = = 0) break; T = create_tree(T, x); } printf("\n Preorder Traversal....."); preorder(T); printf("\n Inorder Traversal....."); inorder(T); printf("\n Postorder Traversal....."); postorder(T); getch( ); } node *create_tree(node *T, int val) { if(T == NULL) { T = (node *)malloc(sizeof(node)); T->data = val; T->left_child = NULL; T->right_child = NULL; } else if(T->data >= val) T->left_child = create_tree(T->left_child, val); else T->right_child = create_tree(T->right_child, val); return T; } void preorder(node *T) { if(T != NULL) { printf("\n %d", T->data); Page 104 preorder(T->left_child); preorder(T->right_child); } } void inorder(node *T) { if(T != NULL) { inorder(T->left_child); printf("\n %d", T->data); inorder(T->right_child); } } void postorder(node *T) { if(T != NULL) { postorder(T->left_child); postorder(T->right_child); printf("\n %d", T->data); } } BST (Binary Search Tree) A binary tree in which all elements in the left subtrees of a node ‘N’ are less than the node element and all elements in the right subtrees of node ‘N’ are greater than the node element is called Binary search tree (BST). 1. If the BST is traversed in inorder, then the contents of each node are printed in ascending order. 2. In BST, we can search for an element easily with an average running time f(n) = O(log2n) Searching a value in Binary Search Tree: Searching is used to find whether the data is present or not in the tree. To search a particular node in binary search tree, follow these steps: 1. To search any node in a BST, initially the data is compared with the data of the root node. If the data is matched then searching is successful. 2. If the searching is found to be greater than the data of the root node then we will move for searching in the right subtree of the root node, otherwise we will move for searching in left subtree of root node. 3. This procedure is repeated until the data is found. 4. If the leaf node is reached and data is not found then it is concluded that the data is not present in the tree. Page 105 Algorithm: - search(T, val) Begin If T = NULL Then Display "Tree is empty" Else ptr = T While ptr != NULL do If val < ptr [Data] Then ptr = ptr [Left] Else if val > ptr [Data] Then ptr = ptr [Right] Else return 1 [End of if statement] [End of while statement] Return 0 [End of if statement] End Insertion of a node in Binary Search Tree: To insert a data in BST, we need to find out the position of the data where it exactly fits into the tree so that the tree remains binary search tree. To insert any node into BST, initially the data that is to be inserted is compared with the data of the root node. If the data is found to be greater than the data of root node then the new node is inserted in right subtree of the root node. Otherwise, the node is inserted in the left subtree of the root node. This procedure is repeated for the left subtrees and right subtrees. This is done till the left or right subtree where the new node is to be inserted is found to be empty. Finally the new node is made the appropriate child of the current node. Algorithm: - insert(T, val) Begin Temp = create a node Temp [Data] = val Temp [Left] = NULL Temp [Right] = NULL If T = NULL Then T = Temp Else ptr = T While ptr != NULL do ptr1 = ptr If val < ptr [Data] Then ptr = ptr [Left] Else if val > ptr [Data] Then ptr = ptr [Right] Page 106 Else Display "Duplicate values are not allowed" return T [End of if statement] [End of while statement] If val < ptr1 [Data] Then ptr1 [Left] = Temp Else ptr1 [Right] = Temp [End of if statement] [End of if statement] Return T End Example – Write a program to insert nodes in BST and traverse it. #include<stdio.h> #include<conio.h> struct node { int data; struct node *left,*right; }; typedef struct node node; node *insert(node *, int); void preorder(node *); void inorder(node *); void postorder(node *); void main( ) { int x; node *T = NULL; clrscr( ); while(1) { printf("Enter the number (type 0 for exit) - "); scanf("%d",&x); if(x = = 0) break; T = insert(T, x); } printf("\n Preorder Traversal....."); preorder(T); printf("\n Inorder Traversal....."); inorder(T); printf("\n Postorder Traversal....."); Page 107 postorder(T); getch( ); } node *insert(node *T, int val) { node *temp, *ptr, *ptr1; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->left = temp->right = NULL; if(T = = NULL) T = temp; else { ptr = T; while(ptr != NULL) { ptr1 = ptr; if(val < ptr->data) ptr = ptr->left; else if(val > ptr->data) ptr = ptr->right; else { printf("Duplicate values are not allowed"); return T; } } if(val < ptr1->data) ptr1->left = temp; else ptr1->right = temp; } return T; } void preorder(node *T) { if(T != NULL) { printf("\n %d", T->data); preorder(T->left); preorder(T->right); } } Page 108 void inorder(node *T) { if(T != NULL) { inorder(T->left); printf("\n %d", T->data); inorder(T->right); } } void postorder(node *T) { if(T != NULL) { postorder(T->left); postorder(T->right); printf("\n %d", T->data); } } Example – Write a program to create a BST and search the element is BST. #include<stdio.h> #include<conio.h> struct node { int data; struct node *left,*right; }; typedef struct node node; node *insert(node *, int); int search(node *, int); void main( ) { int x, s; node *T = NULL; clrscr( ); while(1) { printf("Enter the number (type 0 for exit) - "); scanf("%d",&x); if(x = = 0) break; T = insert(T, x); } printf("\n Enter the number to be searched - "); Page 109 scanf("%d", &s); if(search(T, s) = = 1) printf("Value found"); else printf("Value not found"); getch( ); } node *insert(node *T, int val) { node *temp, *ptr, *ptr1; temp = (node *)malloc(sizeof(node)); temp->data = val; temp->left = temp->right = NULL; if(T = = NULL) T = temp; else { ptr = T; while(ptr != NULL) { ptr1 = ptr; if(val < ptr->data) ptr = ptr->left; else if(val > ptr->data) ptr = ptr->right; else { printf("Duplicate values are not allowed"); return T; } } if(val < ptr1->data) ptr1->left = temp; else ptr1->right = temp; } return T; } int search(node *T, int val) { node *ptr; if(T = = NULL) printf("Tree is empty"); else Page 110 { ptr = T; while(ptr != NULL) { if (val < ptr->data) ptr = ptr->left; else if (val > ptr->data) ptr = ptr->right; else return 1; } return 0; } } Deletion of a node in Binary Search Tree: Before deleting a node, first we find the location of node ‘Ptr’ which contains the required data and also the location of parent node. Deletion of a node from the binary search tree depends on the number of children of node ‘Ptr’. There are following four cases: Case 1: If the node Ptr to be deleted has no child: In this case, node ‘Ptr’ is deleted from the tree by simply replacing the location of node in the parent node by the NULL pointer. Algorithm – Deletion of a node in BST Ptr points the current node and Ptr1 points to the parent node. Begin If Ptr [Left] = NULL And Ptr [Right] = NULL Then If Ptr1 [Right] = Ptr Then Ptr1 [Right] = NULL Else Ptr1 [Left] = NULL [End of if statement] Free (Ptr) [End of if statement] End Case 2: If the node Ptr to be deleted has only right child: In this case, node ‘Ptr’ is deleted from the tree by simply replacing the location of deleted node ‘Ptr’ in the parent node by the location of the child of deleted node ‘Ptr’. Algorithm – Deletion of a node in BST Ptr points the current node and Ptr1 points to the parent node. Begin If Ptr [Left] = NULL And Ptr [Right] != NULL Then If Ptr1 [Left] = Ptr Then Page 111 Ptr1 [Left] = Ptr [Right] Else Ptr1 [Right] = Ptr [Right] [End of if statement] Free (Ptr) [End of if statement] End Case 3: If the node Ptr to be deleted has only left child: In this case, node ‘Ptr’ is deleted from the tree by simply replacing the location of deleted node ‘Ptr’ in the parent node by the location of the child of deleted node ‘Ptr’. Algorithm – Deletion of a node in BST Ptr points the current node and Ptr1 points to the parent node. Begin If Ptr [Left] != NULL And Ptr [Right] = NULL Then If Ptr1 [Left] = Ptr Then Ptr1 [Left] = Ptr [Left] Else Ptr1 [Right] = Ptr [Left] [End of if statement] Free (Ptr) [End of if statement] End Case 4: If the node Ptr to be deleted has two children: When a node Ptr is deleted, we replace node Ptr by left most child of its right subtree. Algorithm – Deletion of a node in BST Ptr points the current node and Ptr1 points to the parent node. Begin If Ptr [Left] != NULL And Ptr [Right] != NULL Then Ptr1 = Ptr PtrSucc = Ptr [Right] While PtrSucc [Left] != NULL Ptr1 = PtrSucc PtrSucc = PtrSucc [Left] [End of while statement] Ptr [Data] = PtrSucc [Data] Ptr = PtrSucc [End of if statement] End Threaded Binary Tree: Generally the pointer fields LEFT and RIGHT will contain NULL elements. This space may be more efficiently used by replacing the null entries by some other type of Page 112 information. We will replace the null entries by special pointers with which point to nodes higher in the tree. These special pointers are called threads, and the binary trees with such pointers are called threaded trees. An extra 1-bit TAG field may be used to differentiate threads from ordinary pointers or threads may be denoted by negative integers when ordinary pointers are denoted by positive integers. There are two ways to thread a binary tree: 1. One way or Right threading 2. Two way or Left threading 3. Full threading One way or right threading of tree: In one way threading of tree, a thread will appear in right field of the node and will point to the next node in the inorder traversal of tree. Two way or left threading of tree: In two way threaded binary trees, a thread will appear in left field of a node and will point to the preceding node in the inorder traversal of tree. Full threaded tree: In full threaded binary tree, two threads will appear in both left and right field of a node and will point to the preceding and next node in the tree. Height Balanced Tree: A tree is perfectly height balanced if the left and right subtrees of any node are at the same height. AVL Tree: In 1962, the Russian mathematicians G.M. Adelson, Velskii and E.M. Landis gave a technique to balance the height of a binary tree, then the resulting tree is called AVL tree. In other words, AVL tree is a binary search tree in which the height of the left and right subtrees of each node will be with maximum difference 1. With the help of AVL trees; searching, insertions and deletions in a tree with node n is achieved in time of order O(n), even in the worst case. It is clear that at each level, there are twice as many nodes at the previous level. However, a perfect height balanced tree is very rare. It is only possible if there are exactly 2 L – 1 node at level L. The difference of each node is in the range of -1, 0 and +1. Page 113 Computing height of a Binary tree: For the height balanced, we calculate the balance factor (B.F.) of each node. The balance factor of each node should lies in the range of -1, 0, and +1. If the balance factor of any node of a tree is not in this range, then that tree is not height balanced. Balance factor may be defined as: B.F. = Height of left subtree – Height of right subtree Example – To construct an AVL tree, consider the following data to be inserted in AVL tree: 25, 45, 50, 55, 60, 65, 75 Solution – 1. Start from the first node 25. 2. Insert 45, node 45 is greater than 25, so it will add right side of 25. Find B.F. of every node and check whether every node is balanced or not. 3. Insert 50, since 50 > 45, it will add right child of node 45. Now find the B.F. of every node. 4. Insert 55 in the right side of 50. Now find B.F. of every node. Page 114 5. Insert 60 in the right side of 55. Now find B.F. of every node. After balancing the critical node – 6. Insert 65 in the right side of 60. Now find B.F. of every node. After balancing the critical node – 7. Insert 75 in the right side of 65. Now find B.F. of every node. Page 115 After balancing the critical node – B – Tree: In BST, so many nodes have left subtree but no right subtree. Similarly they have right subtree but no left subtree. Insertion of key also increases the height of tree. When the height of tree increases, then the access time in tree is totally increases on level of tree. So if we want to minimize the access time which can be through balanced tree only. So we have a need to take all there leaf nodes at same level and non leaf nodes should not contain the empty subtree. A B-tree is a balanced M-way tree. B-tree or order M has the following properties: 1. It should be perfectly balanced i.e. every leaf node is at the same level. 2. Each node except the root contains minimum M/2 children and maximum M children. 3. Each node has one fewer value than children. No node can contain more than M – 1 values. 4. Keys are arranged in a defined order within the node. 5. When a new key is to be inserted into a full node, this is split into two nodes, and the key with the median value is inserted in the parent node. In case the parent node is the root, a new root is created. Page 116 UNIT – IV Graphs: A graph G consists of two sets V and E where V is a finite set of vertices or nodes and E is a set of edges. Thus a graph is defined as a collection of vertices and edges and it is represented by G = (V, E). An edge is defined as a pair of vertices, which are adjacent to each other. It shows a Simple graph, for which – V(G) = {A, B, C} E(G) = {e1, e2, e3} Where V(G) is a set of vertices and E(G) is a set of edges. There are three vertices and three edges in the graph. The edge e1 is incident with node A and node B. e1 = (A, B) or (B, A) e2 = (A, C) or (C, A) e3 = (C, B) or (B, C) then E(G) = {(A, B), (A, C), (B, C)} Graph terminology: 1. Directed Edge: An edge that is directed from one vertex to another is called a directed edge. 2. Undirected Edge: An edge which has no specific direction is called a undirected edge. 3. Directed Graph: A graph in which every edge is directed is called a directed graph or diagraph. V = {A, B, C, D} Page 117 E = {e1, e2, e3, e4, e5} e1 = {A, B} e2 = {C, A} e3 = {C, D} e4 = {D, B} e5 = {A, D} 4. Undirected Graph: A graph in which every edge is undirected is called a undirected graph. e1 = {A, B} or {B, A} e2 = {C, A} or {A, C} e3 = {C, D} or {D, C} e4 = {D, B} or {B, D} e5 = {A, D} or {D, A} 5. Mixed Graph: If some of the edges are directed and some are undirected graph, then the graph is called mixed graph. 6. Multi Graph: When two or more edges are used to join vertices, such edges are called parallel edges and the graph is called multi graph. 7. Simple Graph: If there is only one edge between a pair of vertices, then such graph is called simple gaph. 8. Null Graph: A graph without any edge is called Null graph. Page 118 9. Isolated Vertex: When a node which is not adjacent to any other node in the graph is called an isolated vertex. 10. Path: A path is a sequence of consecutive edges from the source node to destination node. 11. Cycle: A cycle is a path in which the first and last vertices are same. 12. Loop: An edge will be called self loop or self edge if it starts and ends on the same node. 13. Cyclic Graph: If a graph contains loop or cycles it is called cyclic graph. 14. Connected Graph: An undirected graph is called connected, if there exist a path fron any vertex to any other vertex. 15. Complete Graph: A graph is said to be complete or fully connected if every node is connected to every other node in a graph. An undirected complete graph with n nodes will have n(n – 1) / 2 edges. 16. Weighted or Network Graph: Number associated with an edge is called its weight or value. A graph with edge value is called weighted graph. 17. Indegree: The indegree of the vertex in directed graph is the number of edges ending at it. 18. Outdegree: The indegree of the vertex in directed graph is the number of edges starting from it. 19. Acyclic Graph: A graph that has no cycles is called acyclic graph. When the direction exists in acyclic graph is called DAG (Directed Acyclic Graph). 20. Maximum edges in Graph: In an undirected graph, there can be n(n – 1) / 2 maximum edges and in a directed graph, there can be n (n – 1) maximum edges, where n is the total number of vertices in the graph. 21. Weakly Connected: - Page 119 A directed graph is called weakly connected if for any pair of vertices u and v there is not a path from u to v and v to u. 22. Strongly Connected: A directed graph is called strongly connected if there is a path from any vertex to any other vertex in a graph. 23. Total Degree of vertex: It is the sum of outdegree and indegree of the vertex or the number of edges incident on the vertex determine its degree. In case of undirected graph, total degree of the vertex v is the equal to the number of edges incident with v. 24. Tree: A graph is a tree it has two properties: (i) It is connected (ii) There are no cycles in the graph. 25. Source: A node which has no incoming edges but has outgoing edges is called source vertex. The indegree of source is 0. 26. Sink: A node which has no outgoing edges but has incoming edges is called sink vertex. The outdegree of sink is 0. Graph Representation: There are two popular ways to represent a graph in computer’s memory: 1. Sequential Representation 2. Linked Representation Sequential Representation: In sequential representation, graph can be represented as matrices. An adjacency matrix is the most common matrix to represent a graph. Adjacency Matrix: Adjacency matrix is the matrix, which keeps the information of adjacent vertices. Suppose there are 5 vertices in graph, then row 1 represents the vertex 1, row 2 represents the vertex 2 and so on. Similarly column 1 represents the vertex 1, column 2 represents the vertex 2 and so on. It is a sequence matrix having one row and one column for each vertex. The element of adjacency matrix is either 1 or 0. A value 1 for row i and column j implies that an edge (eij) exists between Vi and Vj. A value 0 means there is no edge between vertex Vi and Vj. The adjacency matrix A for a graph G = (V, E) with n vertices is an n * n matrix such that, 1 if there is an edge between Vi and Vj 0 if there is no edge Aij = Note – A matrix which contains 1 or 0 is called a Bit matrix or a Boolean matrix. Page 120 Example – Adjacency Matrix Representation of Directed graph A B C D E A 0 1 0 1 0 B 0 0 1 0 1 C 1 0 0 0 0 D 0 0 1 0 1 E 0 0 0 0 0 Note: 1. From the adjacency matrix, it is clear that number of 1’s is equal to the number of edges in the graph. 2. The number in each row shows the outdegree of vertex. 3. If graph is undirected, the adjacency matrix will be symmetric i.e. rows and columns value are equal. 4. For a NULL graph, adjacency matrix has all of its elements 0. 5. If there are loops at each vertex but no edges in the graph, then the adjacency matrix will be unit matrix. 6. For a weighted graph, the elements of adjacency matrix are the weight on that edge. Incidence Matrix: The incidence matrix contains the row for every vertex and a column for every edge. The values of the matrix are -1, 0 or 1. If the kth edge is (Vi, Vj), the kth column has the value 1 in the ith row, -1 in the jth row and 0 elsewhere. Linked list Representation: It is also called Adjacency List Representation. If the adjacency matrix of the graph is sparse then it is more efficient to represent the graph through adjacency list. For adjacency list representation, we maintain a list for each vertex and then for each vertex, we have a linked list of its adjacent vertices. Page 121 In actual vertices are represented by node with 3 parts, one data and 2 links parts. The data part represents vertex, one link part represents next vertex and other link part represents edges of graph. Example – Graph Traversal: A graph traversal means visiting all the nodes of the graph. There are two standard ways for traversing a graph: 1. Breadth First Search (BFS) 2. Depth First Search (DFS) Breadth First Search (BFS): The BFS uses a queue as an auxiliary structure to store the nodes for future processing. In a BFS, we will require the starting vertex from which this search will begin. First one vertex is selected as the start position, it is visited and printed, and then all unvisited vertices, adjacent to it are visited and printed in some sequential order. Finally, the unvisited vertices immediately adjacent to these vertices are visited and printed and so on, until the entire graph has been traversed. There are 3 states of nodes in BFS: 1. Ready state: - When a node is not visited at all, means it did not reaches to queue. 2. Waiting state: - When a node is inserted to queue and is to be processed later on. 3. Processed state: - When a node is removed from queue and processed, than it is said to be in processed state. Algorithm – Breadth First Search Step 1 – Begin Step 2 – [Initializing all nodes to the ready state] STATUS = 1 Step 3 – Put the starting node A in QUEUE and change its status to the waiting state (STATUS = 2). Step 4 – Repeat step 5 and 6 until QUEUE is empty Step 5 – Remove the front node N of QUEUE. Process N and change the status of N to the processed state (STATUS = 3). Step 6 – add the rear of queue all the neighbors of N that are in ready state (STATUS = 1) and change their status to the waiting state (STATUS = 2) Step 7 – End Page 122 Depth First Search (DFS): In BFS, the traversal of graph proceeds level by level. But DFS traversal follows first a path from a starting node to an ending node. Then another path from the start to the end and so on until all nodes has been visited. Here we need stack instead of queue. The nodes which are either traversed or already available in the stack are not pushed. We already know that an element is pushed or popped at the top of the stack. There are 3 states of nodes in DFS: 1. Ready state: - When a node is not pushed to stack. 2. Waiting state: - When a node is pushed to stack, but not popped. 3. Processed state: - When a node is popped from stack. Algorithm – Depth First Search Step 1 – Begin Step 2 – [Initializing all nodes to the ready state] STATUS = 1 Step 3 – Push the starting node A in STACK and change its status to the waiting state (STATUS = 2). Step 4 – Repeat step 5 and 6 until STACK is empty Step 5 – Remove the topt node N of STACK. Process N and change the status of N to the processed state (STATUS = 3). Step 6 – Add to the top of STACK all the neighbors of N that are in ready state (STATUS = 1) and change their status to the waiting state (STATUS = 2) Step 7 – End Minimum Cost Spanning Tree: Let G = (V, E) be an undirected connected graph with vertices ‘V’ and edges ‘E’. A sub-graph t = (V, E’) of the G is a Spanning tree of G if and only if ‘t’ is a tree. The problem is to generate a graph G’= (V, E) where ‘E’ is the subset of E, G’ is a Minimum spanning tree. Each and every edge will contain the given non-negative length. Connect all the nodes with edge present in set E’ and weight has to be minimum. NOTE: We have to visit all the nodes. The subset tree i.e. any connected graph with ‘N’ vertices must have at least N-1 edges and also it does not form a cycle. Definition: A spanning tree of a graph is an undirected tree consisting of only those edge that are necessary to connect all the vertices in the original graph. A Spanning tree has a property that for any pair of vertices there exist only one path between them and the insertion of an edge to a spanning tree form a unique cycle. Application of the spanning tree: Page 123 1. Analysis of electrical circuit. 2. Shortest route problems. Minimum cost spanning tree: The cost of a spanning tree is the sum of cost of the edges in that tree. There are 2 method to determine a minimum cost spanning tree are: 1. Kruskal’s Algorithm 2. Prim’s Algorithm. KRUSKAL’S ALGORITHM: In kruskal's algorithm the selection function chooses edges in increasing order of length without worrying too much about their connection to previously chosen edges, except that never to form a cycle. The result is a forest of trees that grows until all the trees in a forest (all the components) merge in a single tree. In this algorithm, a minimum cost-spanning tree ‘T’ is built edge by edge. Edges are considered for inclusion in ‘T’ in increasing order of their cost. An edge is included in ‘T’ if it doesn’t form a cycle with edge already in T. To find the minimum cost spanning tree the edge are inserted to tree in increasing order of their cost Algorithm: Algorithm kruskal(E, cost, n, t) //E set of edges in G has ‘n’ vertices. //cost[u, v] cost of edge (u, v). t set of edge in minimum cost spanning tree // the first cost is returned. { for i := 1 to n do parent[i] := -1; i := 0; mincost := 0.0; While ((i < n-1)and (heap not empty)) do { j := find(n); k := find(v); if (j not equal k) than { Page 124 i := i + 1 t[i, 1] := u; t[i, 2] := v; mincost := mincost + cost[u, v]; union(j, k); } } if(i notequal n-1) then write(“No spanning tree”) else return minimum cost; } Analysis: The time complexity of minimum cost spanning tree algorithm in worst case is O(|E| log |E|), Where E is the edge set of G. Example: - Step by Step operation of Kurskal’s algorithm. Step 1 – In the graph, the Edge(g, h) is shortest. Either vertex g or vertex h could be representative. Lets choose vertex g arbitrarily. Step 2 – The Edge (c, i) creates the second tree. Choose vertex c as representative for second tree. Step 3 – Edge (g, g) is the next shortest edge. Add this edge and choose vertex g as representative. Page 125 Step 4 – Edge (a, b) creates a third tree. Step 5 – Add edge (c, f) and merge two trees. Vertex c is chosen as the representative. Step 6 – Edge (g, i) is the next next cheapest, but if we add this edge a cycle would be created. Vertex c is the representative of both. Step 7 – Instead, add edge (c, d). Step 8 – If we add edge (h, i), edge(h, i) would make a cycle. Page 126 Step 9 – Instead of adding edge (h, i) add edge (a, h). Step 10 – Again, if we add edge (b, c), it would create a cycle. Add edge (d, e) instead to complete the spanning tree. In this spanning tree all trees joined and vertex c is a sole representative. PRIM'S ALGORITHM Start from an arbitrary vertex (root). At each stage, add a new branch (edge) to the tree already constructed; the algorithm halts when all the vertices in the graph have been reached. Algorithm: Algorithm Prims(e, cost, n, t) { Let (k, l) be an edge of minimum cost in E; Mincost := cost[k, l]; Page 127 T[1,1] := k; t[1,2] := l; For i := 1 to n do If (cost[i, l] < cost[i, k]) then near[i] := l; Else near[i] := k; Near[k] := near[l] := 0; For i := 2 to n-1 do { Let j be an index such that near[j] ≠ 0 and Cost[j, near[j]] is minimum; T[i,1] := j; t[i, 2] := near[j]; Mincost := Mincost + Cost[j, near[j]]; Near[j] := 0; For k := 0 to n do If near((near[k]≠0) and (Cost[k, near[k]]>cost[k, j])) then Near[k] := j; } Return mincost; } The Prim’s algorithm will start with a tree that includes only a minimum cost edge of G. Then, edges are added to the tree one by one. The next edge (i, j) to be added in such that I is a vertex included in the tree, j is a vertex not yet included, and cost of (i, j), cost[i, j] is minimum among all the edges. The working of Prims will be explained by following diagram: - Step 1: Step 2: Step 3: Step 4: Step 5: Step 6: Page 128 Page 129 UNIT – V Searching and Sorting: Searching: Searching refers to an operation of finding the location of the searching data in collection of elements and output some message if data does not exist in the list. The search is said to be successful if data appears in the collection else it is called unsuccessful. There are two methods of searching: Linear Search Binary Search 1. Linear Search: This is the simplest technique to find out an element in an unsorted list. The element can be start finding from first element to last element. If the element is finding on the particular position, then process that position and if it is not found then display a message. Algorithm – LinearSearch(Arr, n, s) Description – Arr is an array of n elements and n is a natural number that represents the upper bound of array. s is the searching number. Begin For i = 0 TO n-1 Step 1 If s = Arr[i] Then Return i [End of if statement] [End of For statement] Return -1 End Analysis of complexity of Linear Search: In searching and sorting, we take time complexity in worst case, average case and best case. In best case we assume that the element is found at the first position of list. In worst case we assume that the element is not found till the last and in average case we assume that the element is present at the mid of the list. If the element is not present in the list, then the time taken is O(n) which is worst case. In case of average, element is found at the mid of the list. The number of comparison would be n/2. 2. Binary Search: In this searching method, first we required the array elements is ascending order then we can obtain the element with an algorithm called Binary search. We define positions low on 0 and high of n-1 element and then determine the middle position then compare the searching number from middle value and if the value matches then display the position but if not then either the first or second half of the array can be selected from next comparison. This process continues until a match is found or there are no values left. Page 130 Algorithm – BinarySearch(Arr, n, s) Description – Arr is a sorted array of n elements and n is a natural number that represents the upper bound of array. s is the searching number. Begin [Initialize] low = 0, high = n-1 While low<=high do Mid = (low + high) / 2 If s = Arr[mid] Then Return mid Else if s < Arr[mid] Then high = mid – 1 Else low = mid + 1 [End of if statement] [End of For statement] Return -1 End Time complexity of Binary Search: Measure of complexity is f(n) which is the number of comparison to locate a value in collection of elements. It can be anluzed that each comparison reduces the search in half. 2f(n) > n f(n) = [log2n] + 1 Sorting: Sorting means arranging the elements in the ascending or descending order. There are various sorting methods: 1. Bubble Sort: It is very simple sorting technique but not very efficient in comparison to another sorting techniques. In this method, each element is compared with adjacent elements. If first element is larger than second element then interchange their location, otherwise not. Then next element is compared with its adjacent element and the same process is repeated for all the elements in the list. During the first pass, largest element positioned at last location in list. During the second pass, the same process is repeated leaving the largest element and so on. Algorithm – Bubblesort(Arr, n) Begin For i = 0 to n – 1 step 1 For j = 0 to n – i – 1 step 1 If Arr [ j ] > Arr [ j + 1] Then t = Arr [ j ] Arr [ j ] = Arr [ j + 1] Arr [ j + 1] = t Page 131 [End of if statement] [End of for statement] [End of for statement] End Example – #include<stdio.h> #include<conio.h> void main( ) { int x[20],i,n; void bubblesort(int [], int); clrscr( ); printf("how many numbers - "); scanf("%d", &n); for(i=0 ; i<n; i++) { printf("enter the value - "); scanf("%d", &x[i]); } printf("\nBefore sorting..........."); for(i=0 ; i<n; i++) printf("\n %d", x[i]); bubblesort(x,n); printf("\nAfter sorting..........."); for(i=0; i<n; i++) printf("\n %d", x[i]); getch( ); } void bubblesort(int x[], int n) { int i,j,t; for(i=0 ; i<n ; i++) { for(j=0 ; j<n-i-1 ; j++) { if(x[j] > x[j+1]) { t = x[j]; x[j] = x[j+1]; x[j+1] = t; } } } } Page 132 2. Selection Sort: In this sorting method, first to find the highest element in the array and interchange it with the value in last position of array. Now, find the second highest element in the remainder of array and interchange it with a value in the second last position, carry on till we have reached the first of array. Now all elements have been sorted into asceding order. Algorithm – Selectionsort(Arr, n) Begin For i = 0 to n – 1 step 1 max = Arr[0] p=0 For j = 1 to n – i -1 step 1 If Arr [ j ] > max Then max = Arr [ j ] p=j [End of if statement] [End of for statement] Arr [ p ] = Arr [n – i – 1] Arr [n – i – 1] = max [End of for statement] End Example – #include<stdio.h> #include<conio.h> void main( ) { int x[20],i,n; void selectionsort(int [],int); clrscr( ); printf("how many numbers - "); scanf("%d", &n); for(i=0 ; i<n; i++) { printf("enter the value - "); scanf("%d", &x[i]); } printf("\nBefore sorting..........."); for(i=0 ; i<n; i++) printf("\n %d", x[i]); selectionsort(x,n); printf("\nAfter sorting..........."); for(i=0 ; i<n; i++) Page 133 printf("\n %d", x[i]); getch( ); } void selectionsort(int x[], int n) { int i, j, max, p; for(i=0 ; i<n; i++) { max = x[0]; p=0; for(j=0 ; j<n-i; j++) { if(x [ j ] > max) { max = x [ j ]; p = j; } } x [ p ] = x [n-i-1]; x [n-i-1] = max; } } 3. Insertion Sort: In insertion sort, we assume the first element Arr[0] in pass 1 is already sorted. In pass 2, the next second element Arr[1] is compared with the first one and inserted into its proper place either before or after the first element. In pass 3, the third element Arr[2] is inserted into proper place and so on. Algorithm – Insertionsort(Arr, n) Arr is an array with n elements. Begin For i = 1 to n – 1 step 1 t = Arr [ i ] For j = i – 1 to 0 And t < Arr [ j ] step -1 Arr [ j + 1 ] = Arr [ j ] [End of for statement] Arr [ j+1 ] = t [End of for statement] End Example – #include<stdio.h> #include<conio.h> void main( ) { Page 134 int x[20],i,n; void insertionsort(int [], int); clrscr( ); printf("how many numbers - "); scanf("%d", &n); for(i=0; i<n; i++) { printf("enter the value - "); scanf("%d", &x[i]); } printf("\nBefore sorting..........."); for(i=0; i<n; i++) printf("\n %d",x[i]); insertionsort(x, n); printf("\nAfter sorting..........."); for(i=0; i<n; i++) printf("\n %d", x[i]); getch( ); } void insertionsort(int x[], int n) { int i, j, t; for(i=1 ; i<n; i++) { t = a[i]; for(j=i-1 ; j>=0 && t<x[ j ]; j--) { x[ j + 1 ] = x[ j ]; } x[ j+1 ] = t; } } 4. Quick Sort: It is developed be C.A.R. Hoare. It is also known as partition exchange sort. It is based on Divide and Conquer method. The Quick sort algorithm works by partitioning the array to be sorted. Each partition is in turn sorted recursively. In this method, we divide the list stored in the array into two parts and so on and keep track of middle element. In this sorting, we continue to divide the list into two parts until elements in list not remain single, and list finally gets sorted. Algorithm – Quicksort(X, n, low, high) X is an array with n elements. The low points to the 0th element and high points to the n-1 Page 135 element. Begin If low < high Then p = Partition(X, low, high, p) Quicksort(X, n, low, p – 1) Quicksort(X, n, p + 1, high) [End of for statement] End Algorithm – Partition(X, beg, end, loc) X is an array with n elements. The low points to the 0th element and high points to the n-1 element. Begin loc = first = beg last = end flag = 0 While (!flag) do While x[last] >= x[loc] And *loc != last last = last – 1 [End of while loop] If *loc = last Then flag = 1 Else If x[loc] > x[last] Then temp = x[loc] x[loc] = x[last] x[last] = temp loc = last [End of if statement] If (!flag) Then While x[first] <= x[loc]) And loc != first first = first + 1 [End of while loop] If loc = first Then flag = 1 Else If x[loc] < x[first] Then temp = x[loc] x[loc] = x[first] x[first] = temp loc = first [End of if statement] [End of if statement] [End of if statement] Page 136 [End of if statement] [End of while loop] End Example – #include<stdio.h> #include<conio.h> void quicksort(int [], int, int, int); void partition(int [], int, int, int *); void main( ) { int x[20],i,n; clrscr( ); printf("how many numbers - "); scanf("%d",&n); for(i=0;i<n;i++) { printf("enter the value - "); scanf("%d",&x[i]); } printf("\nBefore sorting..........."); for(i=0;i<n;i++) printf("\n %d",x[i]); quicksort(x,n,0,n-1); printf("\nAfter sorting..........."); for(i=0;i<n;i++) printf("\n %d",x[i]); getch( ); } void quicksort(int x[], int n, int low, int high) { int loc; if(low < high) { partition(x,low,high,&loc); quicksort(x,n,low,loc-1); quicksort(x,n,loc+1,high); } } void partition(int x[], int beg, int end, int *loc) { int first,last,flag,temp; *loc = first = beg; last = end; flag = 0; Page 137 while (!flag) { while (x[last] >= x[*loc] && (*loc != last)) last --; if (*loc == last) flag = 1; else { if (x[*loc] > x[last]) { temp = x[*loc]; x[*loc] = x[last]; x[last] = temp; *loc = last; } } if (!flag) { while ((x[first] <= x[*loc]) && (*loc != first)) first++; if (*loc == first) flag = 1; else { if (x[*loc] < x[first]) { temp = x[*loc]; x[*loc] = x[first]; x[first] = temp; *loc = first; } } } } } 5. Shell Sort: It is developed be Donald Shell. It is also based on Divide and Conquer method. The shell sort algorithm works by calculating the d (distance) by mid position of array. Each element of first part is compared with element of second part that is caculated as distance. In this method, we divide the list stored in the array into two parts and so on and keep track of middle element. Algorithm – Shellsort(X, n) X is an array with n elements. Page 138 Begin d = n/2 While d >= 1 do For i = 0 to n – d Step 1 If x[i] > x[i+d] Then t = x[i] x[i] = x[i+d] x[i+d] = t [End of if statement] [End of for statement] If d = 1 Then Return d = d / 2.0 + 0.5 [End of while statement] End Example – #include<stdio.h> #include<conio.h> void main( ) { int x[20], i, n; void shellsort(int [], int); clrscr( ); printf("how many numbers - "); scanf("%d", &n); for(i=0 ;i<n ;i++) { printf("enter the value - "); scanf("%d", &x[i]); } printf("\nBefore sorting..........."); for(i=0;i<n;i++) printf("\n %d",x[i]); shellsort(x,n); printf("\nAfter sorting..........."); for(i=0;i<n;i++) printf("\n %d",x[i]); getch( ); } void shellsort(int x[], int n) { int i, t, d; d = n/2; while(d >= 1) Page 139 { for(i=0 ; i<n-d ; i++) { if(x[i] > x[i+d]) { t = x[i]; x[i] = x[i+d]; x[i+d] = t; } } if(d = = 1) return; d = d / 2.0 + 0.5; } } 6. Merge Sort: In this sorting technique which divides the array into subarray of same size and merges adjacent pairs then we have approximately n / 2 arrays of same size. This process is repeated until there is only one array remaining of size n. Each pass of the merge sort will start at the beginning of array X and merge pairs of sorted sub-arrays in a common single array. Example #include<stdio.h> #include<conio.h> void mergesort(int [],int,int); void mergingsortedsubarrays(int [], int, int, int, int); void main( ) { int x[20], i , n; clrscr( ); printf("how many numbers - "); scanf("%d",&n); for(i=0;i<n;i++) { printf("enter the value - "); scanf("%d",&x[i]); } printf("\nBefore sorting..........."); for(i=0;i<n;i++) printf("\n %d",x[i]); mergesort(x,0,n-1); printf("\nAfter sorting..........."); for(i=0;i<n;i++) Page 140 printf("\n %d",x[i]); getch( ); } void mergesort(int x[], int low, int high) { int mid; if(low < high) { mid = (low+high)/2; mergesort(x, low, mid); mergesort(x, mid+1, high); mergingsortedsubarrays(x, low, mid, mid+1, high); } } void mergingsortedsubarrays(int x[], int lb, int lr, int rb, int rr) { int a, b, c, k, final[20]; a = lb; b = rb; c = lb; while((a<=lr) && (b<=rr)) { if(x[a] < x[b]) final[c] = x[a++]; else final[c] = x[b++]; c++; } if(a > lr) { while(b <= rr) final[c++] = x[b++]; } else { while(a <=lr) final[c++] = x[a++]; } for(k = lb; k <= rr ; k++) x[k] = final[k]; } 7. Heap Sort: It is a technique which sorts the elements of array that represent a tree with a special property. A heap is defined as a balanced binary tree in which the value of Page 141 each node is less than or equal to the value of the parent node. This implies that root of the binary tree has the largest element in the heap. Type of heap: 1.) Max Heap: - The tree in which the value of each node is less than or equal to the value of parent node is known as max heap. 2.) Min Heap: - The tree in which the root of the binary tree has the smallest element of the heap. A binary tree will be heap when it satisfies following two conditions: 1.) Value of each node is less than or equal to the value of parent node. 2.) Each level of binary tree must be filled from left to right and a node should not be placed on a new level until the preceding level is null. Example - #include<stdio.h> #include<conio.h> void heapsort(int [], int); void heap(int [], int); void below_heap(int [], int, int); void main( ) { int x[20], i, n; clrscr( ); printf("how many numbers - "); scanf("%d", &n); for(i=0; i<n ; i++) { printf("enter the value - "); scanf("%d", &x[i]); } printf("\nBefore sorting..........."); for(i=0 ; i<n ; i++) printf("\n %d", x[i]); heapsort(x,n); printf("\nAfter sorting..........."); for(i=0 ; i<n ; i++) printf("\n %d", x[i]); getch( ); } void heapsort(int x[], int n) { int temp, i; heap(x,n); for(i = n-1; i>0; i--) { temp = x[0]; x[0] = x[i]; Page 142 x[i] = temp; below_heap(x, 0, i-1); } } void heap(int x[], int n) { int index, i; index = (n-1) >> 1; for(i=index ; i>=0 ; i--) below_heap(x, i, n-1); } void below_heap(int x[], int first, int last) { int count, l_child, r_child, max, temp; if(first = = 0) l_child = 1; else l_child = first << 1; r_child = l_child + 1; if (l_child <= last) { max = x[l_child]; count = l_child; if (r_child <= last) { if (x[r_child] > max) { max = x[r_child]; count = r_child; } } if(x[first] < x[count]) { temp = x[first]; x[first] = x[count]; x[count] = temp; below_heap(x, count, last); } } } Page 143