0% found this document useful (0 votes)
6 views39 pages

Module 1

The document provides a comprehensive overview of algorithms, defining them as a set of rules for calculations that take inputs and produce outputs. It outlines the properties of algorithms, the design process, and various algorithmic strategies, including pseudocode and flowcharts for specification. Additionally, it discusses the importance of algorithm analysis, efficiency metrics, and the distinction between recursive and non-recursive algorithms.

Uploaded by

asrinivasan328
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views39 pages

Module 1

The document provides a comprehensive overview of algorithms, defining them as a set of rules for calculations that take inputs and produce outputs. It outlines the properties of algorithms, the design process, and various algorithmic strategies, including pseudocode and flowcharts for specification. Additionally, it discusses the importance of algorithm analysis, efficiency metrics, and the distinction between recursive and non-recursive algorithms.

Uploaded by

asrinivasan328
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 39

INTRODUCTION TO ALGORITHMS

ALGORITHM:

The word “Algorithm” comes from the Persian author Abdullah Jafar Muhammad ibn Musa
Al-khowarizmi in ninth century, who has given the definition of algorithm as follows:

 An Algorithm is a set of rules for carrying out calculation either by hand or on a


machine.
 An Algorithm is a well defined computational procedure that takes input and produces
output.
 An Algorithm is a finite sequence of instructions or steps (i.e. inputs) to achieve some
particular output.

Any Algorithm must satisfy the following criteria (or Properties)

 Input: there are zero or more quantities, which are externally supplied;
 Output: at least one quantity is produced
 Definiteness: each instruction must be clear and unambiguous;
 Finiteness: if we trace out the instructions of an algorithm, then for all cases the
algorithm will terminate after a finite number of steps;
 Effectiveness: every instruction must be sufficiently basic that it can be carried out by
a person using only pencil and paper. It is not enough that each operation be definite,
but it must also be feasible.

DESIGN OF ALGORITHM: The study of algorithm includes many important and active
areas of researches. They are:
 Understanding the problem:
o This is the very first step in designing of an algorithm. In this step first of all
need to understand the problem statement completely by reading the problem
description carefully.
o After that, find out what are the necessary inputs for solving that problem.
o The input to the algorithm is called instance of the problem.
o It is very important to decide the range of inputs so that the boundary values of
algorithm get fixed. The algorithm should work correctly for all valid inputs.
 Decision Making:
o After finding the required input set for the given problem we have to analyze the
input and need to decide certain issues such as
o Capabilities of computational devices:
 It is necessary to know the computational capabilities of devices
on which the algorithm will be running ie., sequential or parallel
algorithm.
 Complex problems require huge amount of memory and more
execution time. For solving such problems it is essential to have
proper choice of a computational device which is space and time
efficient.
o Choice for either exact or approximate problem solving method:
 The next important decision is to decide whether the problem is
to be solved exactly or approximately.
 If the problem needs to be solved correctly then we need exact
algorithm. Otherwise, if the problem is so complex then we need
approximation algorithm.(Example: Salesperson Problem)
o Data Structures:
 Data Structure and algorithm work together and these are
interdependent.
 Hence choice of proper data structure is required before
designing the actual algorithm.
o Algorithmic Strategies:
 It is a general approach by which many problems can be solved
algorithmically.
 Algorithmic strategies are also called as algorithmic techniques
or algorithmic paradigm.
 Algorithm Design Techniques:
 Brute Force: This is straight forward technique with naïve
approach.
 Divide-and-Conquer: The problem is divided into smaller
instances.
 Dynamic Programming: The results of smaller, reoccurring
instances are obtained to solve the problem.
 Greedy Technique: To solve the problem locally optimal
decisions are made.
 Back tracking: This method is based on the trial and error.
 Specification of Algorithm:

o There are various ways to specify an algorithm


 Using natural language:
 It is very simple to specify an algorithm using natural language
 For Example: Write an algorithm to perform addition of two
numbers.
o Step1: Read the first number say a.
o Step2: Read the second number say b.
o Step3: Add the two numbers and store the result in a
variable c.
o Step 4: Display the result.
 Pseudo code:
 It is a combination of natural language and programming
language
Algorithm sum(a,b):
// Addition of two numbers
//Input: Two numbers a and b
//Output: sum of numbers
{
c=a+b;
write(c)
}
 Flowchart:
 Flowchart is a graphical representation of an algorithm
o Start/ Stop state:

o Transition:

o Processing or assignment statement:


o Conditional Statement:

 Algorithm Verification:
o Algorithm verification means checking correctness of an algorithm that is to
check whether the algorithm gives correct output in finite amount of time for a
valid set of input.
 Analysis of algorithm: The following factors should consider while analyzing an
algorithm
o Time Complexity: The amount of time taken by an algorithm to run.
o Space Complexity: The amount of space taken by an algorithm to store
variable.
o Range of Input: The design of an algorithm should be such that it should
handle the range of input.
o Simplicity: Simplicity of an algorithm means generating sequence of
instructions which are easy to understand.
o Generality: Generality shows that sometimes it becomes easier to design an
algorithm in more general way rather than designing it for particular set of
input.(Example: GCD)
Implementation of Algorithm: The implementation of an algorithm is done by
suitable programming language.
 Testing a Program: Testing a program is an activity carried out to expose as many
errors as possible and to correct them.
o There are two phases for testing a program:
o Debugging
o Profiling
 Debugging is a technique in which a sample set of data is tested to see
whether faulty results occur or not. If any faulty result occurs then those
results are corrected.
 But in Debugging technique only presence of error is pointed out. Any hidden
error cannot be identified.
 So, we cannot verify correctness of output on sample data. Hence, Profiling
Concept is introduced.
 Profiling or Performance Measurement is the process of executing a correct
program on a sample set of data. Then the time and space required by the
program to execute is measured.

PSEUDO CODE FOR EXPRESSING ALGORITHMS:

 In computational theory, we distinguish between an algorithm and a program


conventions used in writing a pseudo code.
 Pseudo code is a combination of natural language and programming language.
 Pseudo code is divided into two parts
o Algorithm Heading which contains the keyword algorithm, name of
algorithm, Parameters, Problem Description, Input and Output.
Example:
Algorithm name(p1,p2..pn)
// problem description
// Input
//Output

Comments begin with // and continuous until the end of line.

o Algorithm Body which consists of logical body of the algorithm by


making use of various programming constructs and assignment
statement
o Block of statements that are enclosed within „{ }‟
o Each statement is ended with delimiter “;”
o An identifier begins with a letter not by digit and can contain
combination of letters and numbers
o Data types are not declared but we assume simple data types
like int, float, char etc.
o The compound data types are represented with node. If an
instance of ‘P’ is created to a node then the values of node can
be accessed by using the operator ( . ) or
o Assignment of value to a variable is done using assignment
statement

o Logical operators such as AND, OR, NOT and Relational


operators such as ,<=,>=,==,= are used to get a Boolean values
true or false.
o The array indices are stored within square brackets “[ ]”.
 The multidimensional arrays can also be used in
algorithm. Example: A[i]- Single Dimensional Array,
A[i,j]-2D Array
o Loop statements like for, while, repeat until are represented as
follows

o Conditional Statements such as if-then or if-then-else are


represented as follows:
o Input and output are represented by using read and write
read (val);
write (stmt);

PROPERTIES THAT DEFINE A GOOD ALGORITHM

1. Correctness: An algorithm must accurately solve the problem it is designed for,


producing the correct output for all valid inputs.
2. Efficiency: This pertains to the algorithm's performance in terms of time and space:
a. Time Complexity: The amount of time an algorithm takes to complete
as a function of the input size. Efficient algorithms have lower time
complexity, often analyzed using Big-O notation.
b. Space Complexity: The amount of memory an algorithm uses during
its execution. A good algorithm minimizes its memory usage.
3. Determinism: A good algorithm produces the same output for a given input every
time it is executed, ensuring predictability and reliability.
4. Generality: The algorithm should be applicable to a broad set of problems or inputs,
enhancing its utility across different scenarios.
5. Simplicity and Clarity: An algorithm should be straightforward, making it easy to
understand, implement, and maintain. Clear algorithms reduce the likelihood of errors
and facilitate debugging.
6. Finiteness: An algorithm must terminate after a finite number of steps, ensuring that it
doesn't result in an infinite loop and that it provides a result in a reasonable amount of
time.
7. Robustness: A robust algorithm can handle unexpected or erroneous inputs
gracefully, without crashing or producing incorrect results.
EFFICIENCY CONSIDERATIONS IN ALGORITHMS
Efficiency analysis of algorithms is crucial for designing optimal solutions. It helps in
determining the feasibility of an algorithm in terms of execution time and memory
requirements. The primary focus of efficiency considerations is on time complexity and
space complexity.
Efficiency Metrics

1. Time Complexity
a. Measures the number of operations an algorithm performs relative to input
size.
b. Expressed using Big O Notation (O), Theta (), and Omega ().
c. Example:
i. Linear Search:
ii. Binary Search:
iii. Quick Sort: in average case, in worst case.
2. Space Complexity
a. Measures the memory consumed by an algorithm.
b. Includes input storage, auxiliary space, and function call stack usage.
c. Example:
i. Recursive algorithms often have higher space complexity due to stack
usage.

Algorithm Analysis Techniques

3. Asymptotic Notations
a. Big O (Upper Bound): Worst-case growth rate.
b. Theta () (Tight Bound): Average-case behavior.
c. Omega () (Lower Bound): Best-case behavior.
d. Example:
i. Insertion Sort: Worst-case , Best-case .
4. Empirical vs. Theoretical Analysis
a. Theoretical Analysis provides asymptotic complexity without running the
program.
b. Empirical Testing measures actual runtime on specific hardware
c. Example:
i. Measuring sorting algorithms' execution time on large datasets.
Difference between Algorithm and Pseudo code:

 Algorithm is a well-defined sequence of steps that provide a solution for a


given problem.
 Pseudo code is one of the methods that can be used to represent an algorithm.
 Algorithms can be written in natural Language.
 Pseudo code is written in a format that is closely related to high level
programming language structures

 Pseudo code does not use specific programming language syntax and therefore
could be understood by programmer‟s who are familiar with different
programming language.
 Transforming an algorithm presented in pseudo code to programming code
could be much easier than converting an algorithm written in natural language.

RECURSIVE ALGORITHM: A recursive function is a function that is defined in


terms of itself. Similarly, an algorithm is said to be recursive if the same algorithm is
invoked in the body. An algorithm that calls itself is Direct Recursive. If it calls
another algorithm then indirect recursive.
NON-RECURSIVE ALGORITHM

A non-recursive algorithm is an algorithm that does not use recursion to solve a


problem. Instead of calling itself, it typically relies on loops (iteration), stacks, or
queues to manage computations. These algorithms are generally more efficient in
terms of memory usage because they do not involve the overhead of recursive
function calls.

Example: Binary Search is a divide-and-conquer algorithm that works efficiently on sorted


arrays.

Algorithm:

1. Set low = 0 and high = n - 1.


2. Repeat until low ≤ high:
o Find mid = (low + high) / 2.
o If arr[mid] == key, return mid.
o If arr[mid] < key, search in the right half (low = mid + 1).
o Otherwise, search in the left half (high = mid - 1).
3. If not found, return -1.

Example: Tower of Hanoi (Using Stack)

The recursive Tower of Hanoi problem can be solved iteratively using a stack.

Algorithm:
1. Push the initial problem onto a stack.
2. Use an iterative approach to move disks based on rules.
3. Keep track of movements using a loop.
COMPLEXITY

Algorithm evaluation can be done in two ways either before execution of a program or
after execution of a program

 Priori Estimate (Performance Analysis) - [before execution of a program]


 Posteriori Estimate (Performance Measurement) - [after execution of a
program]
Efficiency of an algorithm can be done by measuring the performance of algorithm.
Performance Analysis mainly deals with two factors

 Space Complexity: The space complexity of an algorithm is the amount of memory it


needs to run to completion.
 Time Complexity: The Time complexity of an algorithm is the amount of computer
time it needs to run to completion.

Performance Analysis also deals with other factors like

 Measuring Input Range


 Measuring run time
 Computing order of growth of an algorithm
 Computing best case, worst case and average case.

Space Complexity:

 It is defined as amount of memory required by an algorithm to run.


 Two factors are used to compute space complexity
o Fixed Part: Independent of input and output characteristics. It includes
instruction space, Space for variables, Space for constants and so on.
o Variable Part: It is also called as dynamic part that consists of space needed by
variable whose size is dependent on problem instance at runtime. It includes
Space needed by reference variables, Recursion stack space and so on.

Let P be an algorithm, then total space required for algorithm is S(P)=C+Sp Where C is
constant which is fixed space and Sp is variable space which varies depend on the problem
When we analyze space complexity of an algorithm, we concentrate on estimating
Sp(Variable Space)
Time Complexity:

 The amount of time required by an algorithm to complete its execution.


 Two factors are used to compute time complexity.
o Compile Time: Does not depend on instance characteristics
o Run Time: Depend on particular problem instance

Let P be an algorithm, then total time required for algorithm is T(P)=C+Tp, Where c is
compile time and Tp is runtime

 Time depends on several other factors like


o System Load
o Number of programs that are running
o Instruction set used 
o Speed of underlying hardware
Because of these reasons the time complexity is calculated by using frequency count that is
number of times each instruction is executed. One of the easiest methods to calculate time
complexity is counting the number of steps. We can determine the number of steps needed by
a program to solve a particular problem instance in one of two ways

 In the First method, introduce a new variable count into the program. This is a global
variable with initial value „0‟.
 The Second method to determine the step count of an algorithm is to build a table in
which we list the total number of steps contributed by each statement.
BEST , WORST AND AVERAGE CASE WITH SIMPLE EXAMPLES

Suppose M is an algorithm, and suppose n is the size of the input data. The time
and space used by the algorithm M are the two main measures for the efficiency of M.

 The time is measured by counting the number of key operations, for example, in case
of sorting and searching algorithms, the number of comparisons is the number of key
operations.
 That is because key operations are so defined that the time for the other operations is
much less than or at most proportional to the time for the key operations.
 The space is measured by counting the maximum of memory needed by the
algorithm.
 The complexity of an algorithm M is the function f(n), which give the running time
and/or storage space requirement of the algorithm in terms of the size n of the input
data.
 Frequently, the storage space required by an algorithm is simply a multiple of the
data size n.
 In general the term “complexity” given anywhere simply refers to the running time
of the algorithm.
 There are 3 cases, in general, to find the complexity function f(n):
o Best case: The minimum value of f(n) for any possible input.
o Worst case: The maximum value of f(n) for any possible input.
o Average case: The value of f(n) which is in between maximum and minimum
for any possible input. Generally the Average case implies the expected value
of f(n).
 To understand the Best, Worst and Average cases of an algorithm, consider a linear
array A[1….n], where the array A contains n-elements. Suppose you want either to
find the location LOC of a given element (say x ) in the given array A or to send
some message, such as LOC=0, to indicate that does not appear in A. Here the linear
search algorithm solves this problem by comparing given x, one-by-one, with each
element in A. That is, we compare x with A[1], then A[2], and so on, until we find
LOC such that x=A[LOC].
Analysis of linear search algorithm

The complexity of the search algorithm is given by the number C of comparisons between x
and array elements A[K].

Best case: Clearly the best case occurs when x is the first element in the array A. That is
x=A[LOC]. In this case c(n)=1

Worst case: Clearly the worst case occurs when x is the last element in the array A or x is not
present in given array A (to ensure this we have to search entire array A till last element). In
this case, we have c(n)=n

Average case: Here we assume that searched element x appear array A, and it is equally
likely to occur at any position in the array. Here the number of comparisons can be any of
numbers 1,2,3,…n , and each number occurs with the probability p=1/n then

It means the average number of comparisons needed to find the location of x is


approximately equal to half the number of elements in array A. From above discussion, it
may be noted that the complexity of an algorithm in the average case is much more
complicated to analyze than that of worst case. Unless otherwise stated or implied, we always
find and write the complexity of an algorithm in the worst case.
RECURSIVE AND NO-RECURSIVE ALGORITHMS FOR BINARY SEARCH.

BINARY SEARCH

1 < x2 n . When we

successful search).

In Binary search we jump into the middle of the file, where we find key a[mid], and

s 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 comparis
roughly half the un-searched portion from consideration.

2n times before reaching a


trivial length, the worst case complexity of Binary search is about log 2n.

Algorithm:

Let array a[n] of elements in increasing order, n


and if so, set j such that x = a[j] else return 0.
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


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

Example 1:

Let us illustrate binary search on the following 12 elements:

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

If we are searching for x = 4: (This needs 3 comparisons)


low = 1, high = 12, mid = 13/2 = 6, check 20
low = 1, high = 5, mid = 6/2 = 3, check 8
low = 1, high = 2, mid = 3/2 = 1, check 4, found

If we are searching for x = 7: (This needs 4 comparisons)


low = 1, high = 12, mid = 13/2 = 6, check 20
low = 1, high = 5, mid = 6/2 = 3, check 8
low = 1, high = 2, mid = 3/2 = 1, check 4
low = 2, high = 2, mid = 4/2 = 2, check 7, found

If we are searching for x = 8: (This needs 2 comparisons)


low = 1, high = 12, mid = 13/2 = 6, check 20
low = 1, high = 5, mid = 6/2 = 3, check 8, found

If we are searching for x = 9: (This needs 3 comparisons)


low = 1, high = 12, mid = 13/2 = 6, check 20
low = 1, high = 5, mid = 6/2 = 3, check 8
low = 4, high = 5, mid = 9/2 = 4, check 9, found

If we are searching for x = 16: (This needs 4 comparisons)


low = 1, high = 12, mid = 13/2 = 6, check 20
low = 1, high = 5, mid = 6/2 = 3, check 8
low = 4, high = 5, mid = 9/2 = 4, check 9
low = 5, high = 5, mid = 10/2 = 5, check 16, found

If we are searching for x = 20: (This needs 1 comparison)


low = 1, high = 12, mid = 13/2 = 6, check 20, found
If we are searching for x = 24: (This needs 3 comparisons)
low = 1, high = 12, mid = 13/2 = 6, check 20
low = 7, high = 12, mid = 19/2 = 9, check 39
low = 7, high = 8, mid = 15/2 = 7, check 24, found

If we are searching for x = 38: (This needs 4 comparisons)


low = 1, high = 12, mid = 13/2 = 6, check 20
low = 7, high = 12, mid = 19/2 = 9, check 39
low = 7, high = 8, mid = 15/2 = 7, check 24
low = 8, high = 8, mid = 16/2 = 8, check 38, found

If we are searching for x = 39: (This needs 2 comparisons)


low = 1, high = 12, mid = 13/2 = 6, check 20
low = 7, high = 12, mid = 19/2 = 9, check 39, found

If we are searching for x = 45: (This needs 4 comparisons)


low = 1, high = 12, mid = 13/2 = 6, check 20
low = 7, high = 12, mid = 19/2 = 9, check 39
low = 10, high = 12, mid = 22/2 = 11, check 54
low = 10, high = 10, mid = 20/2 = 10, check 45, found

If we are searching for x = 54: (This needs 3 comparisons)


low = 1, high = 12, mid = 13/2 = 6, check 20
low = 7, high = 12, mid = 19/2 = 9, check 39
low = 10, high = 12, mid = 22/2 = 11, check 54, found

If we are searching for x = 77: (This needs 4 comparisons)


low = 1, high = 12, mid = 13/2 = 6, check 20
low = 7, high = 12, mid = 19/2 = 9, check 39
low = 10, high = 12, mid = 22/2 = 11, check 54
low = 12, high = 12, mid = 24/2 = 12, check 77, found

The number of comparisons necessary by search element:

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:

Let us illustrate binary search on the following 9 elements:

Index 0 1 2 3 4 5 6 7 8
Elements -15 -6 0 7 9 23 54 82 101

Solution:

The number of comparisons required for searching different elements is as follows:


1. If we are searching for x = 101: (Number of comparisons = 4)
low high mid
1 9
6 9
8 9
9 9 9
found

2. Searching for x = 82: (Number of comparisons = 3)


high mid
1 9
6 9
8 9
found

3. Searching for x = 42: (Number of comparisons = 4)


high
1 9
6 9
6 6
7 6 not found

4. Searching for x = -14: (Number of comparisons = 3)


high mid
1 9 5
1 4 2
1 1 1
2 1 not found

Continuing in this manner the number of element comparisons needed to find each of
nine elements is:

1 3 4 5 6 9
-6 0 7 9 23 54
Comparisons 3 3 4 1 3 4

No element requires more than 4 comparisons to be found. Summing the comparisons


needed to find all nine items and dividing by 9, yielding 25/9 or approximately 2.77
comparisons per successful search on the average.

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
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).
A non-recursive program for binary search:

# 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;
}
else
{
if(data < number[mid])
high = mid - 1;
else
low = mid + 1;
}
}
if(flag == 1)
printf("\n Data found at location: %d", mid + 1);
else
printf("\n Data Not Found ");
}

A recursive program for binary search:

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

void bin_search(int a[], int data, int low, int high)


{
int mid ;
if( low <= high)
{
mid = (low + high)/2;
if(a[mid] == data)
printf("\n Element found at location: %d ", mid + 1);
else
{
if(data < a[mid])
bin_search(a, data, low, mid-1);
else
bin_search(a, data, mid+1, high);
}
}
else
printf("\n Element 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 in ascending order: ");
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
printf("\n Enter the element to be searched: ");
scanf("%d", &data);
bin_search(a, data, 0, n-1);
getch();
}

Quick Sort:

the first most efficient sorting algorithms. It is an example of a class of algorithms that

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:

1. >= pivot.
2.
3. If down > up, interchange a[down] with a[up]
4.
pivot is found and place
The program uses a recursive function quicksort(). The algorithm of quick sort function

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
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].

3. It calls itself recursively to sort the left sub-array x[low], x[low+1], . . . . . . .


x[j-1] between positions low and j-1 (where j is returned by the partition
function).

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.

The time complexity of quick sort algorithm is of O(n log n).

Algorithm

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;
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);
}
interchange(a, up, down)
{
p = a[up];
a[up] = a[down];
a[down] = p;
}

Example:

an element smaller than pivot. If such elements are found, the elements are swapped.

Let us consider the following example with 13 elements to analyze quick sort:

2 3 4 5 6 7 9 10 11 12 13 Remarks

08 24 02 58 04 70 45

pivot

pivot 04 79

pivot up down

pivot 57

pivot up & down


08 38 57 58 79 70 45)

pivot down up & down


08 24

& down
02 (08 04)

16

(06 08 & down

(04) 06 & down


04
pivot,
down,

16
pivot,

04 06 08 16 38
(56 57 79

pivot up
down
pivot 45 57

pivot & down


79 57)
45

& down

79 57)
pivot up
57 79

58 79)
& down
57

79)
pivot,
& down
70
79
pivot,
down,

57 58 70 79)

02 04 06 08 16 24 38 45 57 70 79

Recursive program for Quick Sort:

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

void quicksort(int, int);


int partition(int, int);
void interchange(int, int);
int array[25];

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: " );
for(i=0; i < num; i++)
printf("%d ", array[i]);
return 0;
}

void quicksort(int low, int high)


{
int pivotpos;
if( low < high )
{
pivotpos = partition(low, high + 1);
quicksort(low, pivotpos - 1);
quicksort(pivotpos + 1, high);
}
}

int partition(int low, int high)


{
int pivot = array[low];
int up = low, down = high;

do
{
do
up = up + 1;
while(array[up] < pivot );

do
down = down - 1;
while(array[down] > pivot);

if(up < down)


interchange(up, down);

} while(up < down);


array[low] = array[down];
array[down] = pivot;
return down;
}

void interchange(int i, int j)


{
int temp;
temp = array[i];
array[i] = array[j];
array[j] = temp;
}

You might also like