Searching and Sorting 2
Searching and Sorting 2
Searching and Sorting 2
Searching is used to find the location where an element is available. There are two
types of search techniques. They are:
1. Bubble sort
2. Quick sort
3. Selection sort
4. Merge Sort
5. Insertion Sort
6. Radix Sort
1. Internal sorting
2. External sorting
If all the elements to be sorted are present in the main memory then such sorting is
called internal sorting on the other hand, if some of the elements to be sorted are
kept on the secondary storage, it is called external sorting. Here we study only
internal sorting techniques.
Linear Search:
This is the simplest of all searching techniques. In this technique, an ordered or
unordered list will be searched one by one from the beginning until the desired element
is found. If the desired element is found in the list then the search is successful
otherwise unsuccessful.
Let array a[n] stores n elements. Determine whether element x is present or not.
linsrch(a[n], x)
{
index = 0;
flag = 0;
while (index < n) do
{
if (x == a[index])
{
flag = 1;
break;
}
index ++;
}
if(flag == 1)
printf(Data found at %d position, index);
else
printf(data not found);
Example 1:
Suppose we have the following unsorted list: 45, 39, 8, 54, 77, 38, 24, 16, 4, 7, 9, 20
If we are searching for: 45, well look at 1 element before success 39,
well look at 2 elements before success 8,
well look at 3 elements before success 54,
well look at 4 elements before success 77,
well look at 5 elements before success 38
well look at 6 elements before success 24,
well look at 7 elements before success 16,
well look at 8 elements before success 4,
well look at 9 elements before success 7,
well look at 10 elements before success 9,
well look at 11 elements before success 20,
well look at 12 elements before success
For any element not in the list, well look at 12 elements before failure.
Example 2:
Index 0 1 2 3 4 5 6 7 8
Elements -15 -6 0 7 9 23 54 82 101
# include <stdio.h>
# include <conio.h>
main()
{
int number[25], n, data, i, flag = 0; clrscr();
printf("\n Enter the number of elements: "); scanf("%d",
&n);
printf("\n Enter the elements: "); for(i = 0; i <
n; i++)
scanf("%d", &number[i]);
printf("\n Enter the element to be Searched: "); scanf("%d",
&data);
for( i = 0; i < n; i++)
{
if(number[i] == data)
{
flag = 1; break;
}
}
if(flag == 1)
printf("\n Data found at location: %d", i+1);
else
printf("\n Data not found ");
}
# include <stdio.h>
# include <conio.h>
{
if(a[position] == data)
printf("\n Data Found at %d ", position);
else
linear_search(a, data, position + 1, n);
}
else
printf("\n Data not found");
}
void main()
{
int a[25], i, n, data;
clrscr();
printf("\n Enter the number of elements: ");
scanf("%d", &n);
printf("\n Enter the elements:
"); for(i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
BINARY SEARCH
If we have n records which have been ordered by keys so that x1 < x2 < < xn . When we
are given a element x, binary search is used to find the corresponding element from the
list. In case x is present, we have to determine a value j such that a[j] = x (successful
search). If x is not in the list then j is to set to zero (un successful search).
In Binary search we jump into the middle of the file, where we find key a[mid], and
compare x with a[mid]. If x = a[mid] then the desired record has been found. If x <
a[mid] then x must be in that portion of the file that precedes a[mid]. Similarly, if
a[mid] > x, then further search is only necessary in that part of the file which follows
a[mid].
If we use recursive procedure of finding the middle key a[mid] of the un-searched
portion of a file, then every un-successful comparison of x with a[mid] will eliminate
roughly half the un-searched portion from consideration.
Since the array size is roughly halved after each comparison between x and a[mid],
and since an array of length n can be halved only about log2n times before reaching a
trivial length, the worst case complexity of Binary search is about log 2n.
Algorithm:
binsrch(a[], n, x)
{
low = 1; high = n;
while (low < high) do
{
mid = (low + high)/2 if
(x < a[mid])
high = mid 1;
else if (x > a[mid])
low = mid +
1; else return mid;
}
return 0;
}
low and high are integer variables such that each time through the loop either x is
found or low is increased by at least one or high is decreased by at least one. Thus we
have two sequences of integers approaching each other and eventually low will become
greater than high causing termination in a finite number of steps if x is not present.
Index 1 2 3 4 5 6 7 8 9 10 11 12
Elements 4 7 8 9 16 20 24 38 39 45 54 77
20 requires 1 comparison;
8 and 39 requires 2 comparisons;
4, 9, 24, 54 requires 3 comparisons and
7, 16, 38, 45, 77 requires 4 comparisons
Summing the comparisons, needed to find all twelve items and dividing by 12, yielding
37/12 or approximately 3.08 comparisons per successful search on the average.
Example 2:
Index 0 1 2 3 4 5 6 7 8
Elements -15 -6 0 7 9 23 54 82 101
Solution:
Continuing in this manner the number of element comparisons needed to find each of
nine elements is:
Index 1 2 3 4 5 6 7 8 9
Elements -15 -6 0 7 9 23 54 82 101
Comparisons 3 2 3 4 1 3 2 3 4
There are ten possible ways that an un-successful search may terminate depending
upon the value of x.
If x < a(1), a(1) < x < a(2), a(2) < x < a(3), a(5) < x < a(6), a(6) < x < a(7) or a(7)
< x < a(8) the algorithm requires 3 element comparisons to determine that x is not
present. For all of the remaining possibilities BINSRCH requires 4 element comparisons.
Thus the average number of element comparisons for an unsuccessful search is:
(3 + 3 + 3 + 4 + 4 + 3 + 3 + 3 + 4 + 4) / 10 = 34/10 = 3.4
Time Complexity:
The time complexity of binary search in a successful search is O(log n) and for an
unsuccessful search is O(log n).
# include <stdio.h>
# include <conio.h>
main()
{
int number[25], n, data, i, flag = 0, low, high, mid; clrscr();
printf("\n Enter the number of elements: "); scanf("%d",
&n);
printf("\n Enter the elements in ascending order: "); for(i = 0; i <
n; i++)
scanf("%d", &number[i]);
printf("\n Enter the element to be searched: "); scanf("%d",
&data);
low = 0; high = n-1; while(low <=
high)
{
mid = (low + high)/2; if(number[mid]
== data)
{
flag = 1; break;
}
# include <stdio.h>
# include <conio.h>
Example:
Suppose we want our array to be stored in ascending order. Then we pass through the
array 5 times as described below:
We compare X[i] and X[i+1] for i = 0, 1, 2, 3, and 4, and interchange X[i] and X[i+1] if
X[i] > X[i+1]. The process is shown below:
The biggest number 66 is moved to (bubbled up) the right most position in the array.
We repeat the same process, but this time we dont include X[5] into our comparisons.
i.e., we compare X[i] with X[i+1] for i=0, 1, 2, and 3 and interchange X[i] and X[i+1] if
X[i] > X[i+1]. The process is shown below:
33 22 11 44 55
22 33
11 33
33 44
44 55
22 11 33 44 55
We repeat the same process, but this time we leave both X[4] and X[5]. By doing this,
we move the third biggest number 44 to X[3].
22 11 33 44
11 22
22 33
33 44
11 22 33 44
We repeat the process leaving X[3], X[4], and X[5]. By doing this, we move the fourth
biggest number 33 to X[2].
11 22 33
11 22
22 33
We repeat the process leaving X[2], X[3], X[4], and X[5]. By doing this, we move the
fifth biggest number 22 to X[1]. At this time, we will have the smallest number 11 in
X[0]. Thus, we see that we can sort the array of size 6 in 5 passes.
#include <stdio.h>
#include <conio.h>
void bubblesort(int x[], int n)
{
int i, j, temp;
for (i = 0; i < n; i++)
{
for (j = 0; j < ni-1 ; j++)
{
if (x[j] > x[j+1])
{
temp = x[j];
x[j] = x[j+1];
x[j+1] = temp;
}
}
}
}
Time Complexity:
The bubble sort method of sorting an array of size n requires (n-1) passes and (n-1)
2
comparisons on each pass. Thus the total number of comparisons is (n-1) * (n-1) = n
2
2n + 1, which is O(n ). Therefore bubble sort is very inefficient when there are more
elements to sorting.
SELECTION SORT
Selection sort will not require no more than n-1 interchanges. Suppose x is an array of
size n stored in memory. The selection sort algorithm first selects the smallest element
in the array x and place it at array position 0; then it selects the next smallest element
in the array x and place it at array position 1. It simply continues this procedure until it
places the biggest element in the last position of the array.
The array is passed through (n-1) times and the smallest element is placed in its
respective position in the array as detailed below:
Pass 1: Find the location j of the smallest element in the array x [0], x[1], . . . . x[n-1],
and then interchange x[j] with x[0]. Then x[0] is sorted.
Pass 2: Leave the first element and find the location j of the smallest element in the
sub-array x[1], x[2], . . . . x[n-1], and then interchange x[1] with x[j]. Then
x[0], x[1] are sorted.
Pass 3: Leave the first two elements and find the location j of the smallest element in
the sub-array x[2], x[3], . . . . x[n-1], and then interchange x[2] with x[j].
Then x[0], x[1], x[2] are sorted.
Pass (n-1): Find the location j of the smaller of the elements x[n-2] and x[n-1], and
then interchange x[j] and x[n-2]. Then x[0], x[1], . . . . x[n-2] are sorted. Of
course, during this pass x[n-1] will be the biggest element and so the entire
array is sorted.
Time Complexity:
In general we prefer selection sort in case where the insertion sort or the bubble sort
requires exclusive swapping. In spite of superiority of the selection sort over bubble
sort and the insertion sort (there is significant decrease in run time), its efficiency is
2
also O(n ) for n data items.
Let us consider the following example with 9 elements to analyze selection Sort:
1 2 3 4 5 6 7 8 9 Remarks
# include<stdio.h>
# include<conio.h>
int a[25];
int main()
{
int num, i= 0; clrscr();
printf( "Enter the number of elements: " ); scanf("%d", &num);
printf( "\nEnter the elements:\n" ); for(i=0; i < num; i++)
scanf( "%d", &a[i] ); selectionSort( 0, num - 1
);
printf( "\nThe elements after sorting are: " ); for( i=0; i< num; i++ )
printf( "%d ", a[i] ); return 0;
}
main()
{
int i, n = 0; clrscr();
printf (" Array Elements before sorting: "); for (i=0; i<5; i++)
selectionSort( int n)
{
int k, p, temp, min;
if (n== 4)
return (-1);
min = x[n];
p = n;
for (k = n+1; k<5; k++)
{
if (x[k] <min)
{
min = x[k];
p = k;
}
}
temp = x[n]; /* interchange x[n] and x[p] */ x[n] =
x[p];
x[p] = temp;
n++ ;
selectionSort(n);
}
The quick sort algorithm partitions the original array by rearranging it into two groups.
The first group contains those elements less than some arbitrary chosen value taken
from the set, and the second group contains those elements greater than or equal to
the chosen value. The chosen value is known as the pivot element. Once the array has
been rearranged in this way with respect to the pivot, the same partitioning procedure
is recursively applied to each of the two subsets. When all the subsets have been
partitioned and rearranged, the original array is sorted.
The function partition() makes use of two pointers up and down which are moved
toward each other in the following fashion:
The program uses a recursive function quicksort(). The algorithm of quick sort function
sorts all elements in an array a between positions low and high.
1. It terminates when the condition low >= high is satisfied. This condition will
be satisfied only when the array is completely sorted.
2. Here we choose the first element as the pivot. So, pivot = x[low]. Now it
calls the partition function to find the proper position j of the element x[low]
i.e. pivot. Then we will have two sub-arrays x[low], x[low+1], . . . . . . x[j-1]
and x[j+1], x[j+2], . . . x[high].
4. It calls itself recursively to sort the right sub-array x[j+1], x[j+2], . . x[high]
between positions j+1 and high.
Sorts the elements a[p], . . . . . ,a[q] which reside in the global array a[n] into
ascending order. The a[n + 1] is considered to be defined and must be greater than all
elements in a[n]; a[n + 1] = +
quicksort (p, q)
{
if ( p < q ) then
{
call j = PARTITION(a, p, q+1); // j is the position of the partitioning element
call quicksort(p, j 1);
call quicksort(j + 1 , q);
}
}
partition(a, m, p)
{
v = a[m]; up = m; down = p; // a[m] is the partition element
do
{
repeat
up = up + 1;
until (a[up] > v);
repeat
down = down 1;
until (a[down] < v);
if (up < down) then call interchange(a, up, down);
} while (up > down);
a[m] = a[down];
a[down] = v;
return (down);
}
Example:
Select first element as the pivot element. Move up pointer from left to right in search
of an element larger than pivot. Move the down pointer from right to left in search of
an element smaller than pivot. If such elements are found, the elements are swapped.
This process continues till the up pointer crosses the down pointer. If up pointer
crosses down pointer, the position for pivot is found and interchange pivot and
element at down position.
1 2 3 4 5 6 7 8 9 10 11 12 13 Remarks
38 08 16 06 79 57 24 56 02 58 04 70 45
swap up &
pivot up down
down
pivot 04 79
swap up &
pivot up down
down
pivot 02 57
swap pivot
pivot down up
& down
(24 08 16 06 04 02) 38 (56 57 58 79 70 45)
swap pivot
pivot down up
& down
(02 08 16 06 04) 24
pivot, swap pivot
up
down & down
02 (08 16 06 04)
swap up &
pivot up down
down
pivot 04 16
pivot down Up
swap pivot
(06 04) 08 (16)
& down
pivot down up
swap pivot
(04) 06
& down
04
pivot,
down,
up
16
pivot,
down,
up
(02 04 06 08 16 24) 38
02 04 06 08 16 24 38 45 56 57 58 70 79
# include<stdio.h>
# include<conio.h>
int main()
{
int num, i = 0;
clrscr();
printf( "Enter the number of elements: " );
scanf( "%d", &num);
printf( "Enter the elements: " );
for(i=0; i < num; i++)
scanf( "%d", &array[i] );
quicksort(0, num -1);
printf( "\nThe elements after sorting are: " );
do
{
do
up = up + 1; while(array[up] < pivot );
do
down = down - 1; while(array[down] > pivot);
MERGE SORT
Like QuickSort, Merge Sort is a Divide and Conquer algorithm. It divides input array in two
halves, calls itself for the two halves and then merges the two sorted halves. The merge()
function is used for merging two halves. The merge(arr, l, m, r) is key process that
assumes that arr[l..m] and arr[m+1..r] are sorted and merges the two sorted sub-arrays
into one.
The following diagram shows the complete merge sort process for an example array {38,
27, 43, 3, 9, 82, 10}. If we take a closer look at the diagram, we can see that the array is
recursively divided in two halves till the size becomes 1. Once the size becomes 1, the
merge processes comes into action and starts merging arrays back till the complete array is
merged.
merge(arr, l, m, r);
}
}
/* UTILITY FUNCTIONS */
/* Function to print an array */
void printArray(int A[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", A[i]);
printf("\n");
}
Given array is
12 11 13 5 6 7
Sorted array is
5 6 7 11 12 13
INSERTION SORT
#include<stdio.h>
#include<conio.h>
void main(){
getch();
}