100% found this document useful (1 vote)
26 views29 pages

Adsaa Unit-2 (R23)

An algorithm is a finite set of instructions that requires input, produces output, and must be definite, finite, and effective. The study of algorithms encompasses devising, validating, analyzing, and testing algorithms, with specifications often described in pseudo-code. Additionally, time and space complexity are crucial for understanding an algorithm's efficiency, with asymptotic notations like Big-O used to represent these complexities.

Uploaded by

hepsibadevireddy
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
100% found this document useful (1 vote)
26 views29 pages

Adsaa Unit-2 (R23)

An algorithm is a finite set of instructions that requires input, produces output, and must be definite, finite, and effective. The study of algorithms encompasses devising, validating, analyzing, and testing algorithms, with specifications often described in pseudo-code. Additionally, time and space complexity are crucial for understanding an algorithm's efficiency, with asymptotic notations like Big-O used to represent these complexities.

Uploaded by

hepsibadevireddy
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/ 29

UNIT-2

ALGORITHM

An algorithm is a finite set of instructions that, if followed, accomplishes a particular task. In


addition, all algorithms must satisfy the following criteria:

1. Input: Zero or more quantities are externally supplied.

2. Output: At least one quantity is produced.

3. Definiteness: Each instruction is clear and unambiguous.

4. Finiteness: If we trace out the instructions of an algorithm, then for all cases, the algorithm
terminates after a finite number of steps.

5. Effectiveness: Every instruction must be very basic so that it can be carried out, in principle,
by a person using only pencil and paper. It is not enough that each operation be definite as in
criterion 3; it also must be feasible.

The study of algorithms:


The study of algorithms includes many important and active areas of research. There are four
distinct areas of study one can identify:

1. How to devise algorithms: Creating an algorithm is an art which may never be fully
automated. A major goal is to study various design techniques that have proven to be useful. By
mastering these design strategies, it will become easier for us to devise new and useful
algorithms. Dynamic programming is one such technique. Some of the techniques are especially
useful in fields other than computer science such as operations research and electrical
engineering
2. How to validate algorithms: Once an algorithm is devised, it is necessary to show that it
computes the correct answer for all possible legal inputs. We refer to this process as algorithm
validation The purpose of the validation is to assure us that this algorithm will work correctly
independently of the issues concerning the programming language it will eventually be written
in.

3.How to analyze algorithms: This field of study is called analysis of algorithms. As an


algorithm is executed, it uses the computer's central processing unit (CPU) to perform operations
and its memory (both immediate and auxiliary) to hold the program and data. Analysis of
algorithms or performance analysis refers to the task of determining how much computing time
and storage an algorithm requires. This requires great mathematical skill.

4. How to test a program: Means that Debugging and profiling (or performance measurement).
Debugging is the process of executing programs on sample data sets to determine whether faulty

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 1


results occur and, if so, to correct them. However, as E. Dijkstra has pointed out, "debugging can
only point to the presence of errors, but not to their absence.
Profiling or performance measurement is the process of executing a correct program on data sets
and measuring the time and space it takes to compute the results.

ALGORITHM SPECIFICATION:
Pseudo-code Conventions

We can describe an algorithm using natural language like English and simple mathematical
statements called pseudo-code. We must make sure that the resulting instructions are definite.
Graphic representations called flowcharts are another possibility, but they work well only if the
algorithm is small and simple. We present most of our algorithms using a pseudo-code

1. Comments begin with ‘// ’ and continue until the end of line.

2. Blocks are indicated with matching braces: { and }. A compound statement (i.e., a collection
of simple statements) can be represented as a block. The body of a procedure also forms a block.
Statements are delimited by ; .

3. An identifier begins with a letter. The data types of variables are not explicitly declared. The
types will be clear from the context. Whether a variable is global or local to a procedure will also
be evident from the context. We assume simple data types such as integer, float, char, boolean,
and so on. Compound data types can be formed with records as follows

node record
{
datatype 1 data 1;
.
.
datatypen data_n;
node *link;

In this example, link is a pointer to the record type node. Individual data items of a record can be
accessed with and period. For instance if p points to a record of type node, p→ data 1 stands for
the value of the first field in the record. On the other hand, if q is a record of type node, q.data_1
will denote its first field.

4. Assignment of values to variables is done using the assignment statement

(variable):= (expression);

5. There are two boolean values true and false. In order to produce these values, the logical
operators and, or, and not and the relational operators <, <= , =, ≠, > , >= are provided.

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 2


6. Elements of multidimensional arrays are accessed using [and]. For example, if A is a two
dimensional array, the (i, j)th element of the array is denoted as A[i, j]. Array indices start at
zero.

7. The following looping statements are employed: for, while, and repeat until. The while loop
takes the following form:

while (condition) do

(statement 1)

(statement n)

As long as (condition) is true, the statements get executed. When (condition) becomes false, the
loop is exited. The value of (condition) is evaluated at the top of the loop.

The general form of a for loop is

for variable := valuel to value2 step step do

(statement 1)

(statement n)

Here valuel, value2, and step are arithmetic expressions. A variable of type integer or real or a
numerical constant is a simple form of an arithmetic expression. The clause "step step" is
optional and taken as +1 if it does not occur. step could either be positive or negative. variable is
tested for termination at the start of each iteration. The for loop can be implemented as a while
loop as follows:

variable : valuel;

fin := value2;

incr := step;

while ((variable - fin) * step < 0) do

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 3


{
(statement 1)

(statement n)

variable : =variable + incr;

}
A repeat-until statement is constructed as follows:

repeat
{
(statement 1)
.
.
.
(statement n)

}until (condition);

The statements are executed as long as (condition) is false. The value of (condition) is computed
after executing the statements.The instruction break; can be used within any of the above looping
instructions to force exit. In case of nested loops, break; results in the exit of the innermost loop
that it is a part of. A return statement within any of the above also will result in exiting the loops.
A return statement results in the exit of the function itself.

8. A conditional statement has the following forms:

if (condition) then (statement)

if (condition) then (statement 1) else (statement 2)

Here (condition) is a boolean expression and (statement), (statement 1), and (statement 2) are
arbitrary statements (simple or compound).

We also employ the following case statement:

case
{
:(condition 1): (statement 1)

:(condition n): (statement n)

:else: (statement n + 1)
}

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 4


Here (statement 1), (statement 2), etc. could be either simple state-ments or compound
statements. A case statement is interpreted as follows. If (condition 1) is true, (statement 1) gets
executed and the case statement is exited. If (statement 1) is false, (condition 2)
is evaluated. If (condition 2) is true, (statement 2) gets executed and the case statement exited,
and so on. If none of the conditions (condition 1),..., (condition n) are true, (statement n+1) is
executed and the case statement is exited. The else clause is optional.

9. Input and output are done using the instructions read and write. No format is used to specify
the size of input or output quantities.

10. There is only one type of procedure: Algorithm. An algorithm con-sists of a heading and a
body. The heading takes the form

Algorithm Name ( <parameter list >)

where Name is the name of the procedure and ((parameter list)) is a listing of the procedure
parameters. The body has one or more (simple or compound) statements enclosed within braces
{ and }. An algorithm may or may not return any values. Simple variables to procedures are
passed by value. Arrays and records are passed by reference. An array name or a record name is
treated as a pointer to the respective data type.

TIME AND SPACE COMPLEXITY

Space Complexity

Space complexity of an algorithm represents the amount of memory space needed the
algorithm in its life cycle. Space needed by an algorithm is equal to the sum of the following two
components

1. A fixed part that is independent of the characteristics (e.g., number, size) of the inputs and
outputs. This part typically includes the in-struction space (i.e., space for the code), space for
simple variables and fixed-size component variables (also called aggregate), space for constants,
and so on.

2. A variable part that consists of the space needed by component variables whose size is
dependent on the particular problem instance being solved, the space needed by referenced
variables (to the extent that this depends on instance characteristics), and the recursion stack
space (in so far as this space depends on the instance characteristics).

The space requirement S(P) of any algorithm P may therefore be written as S(P) = c + SP (I)
(instance characteristics), where c is a constant. the space complexity of an algorithm, we
concentrate solely on estimating S( P) ( instance characteristics).

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 5


Space complexity S(p) of any algorithm p is S(p) = c + Sp(I) Where c is treated as the fixed part
and S(I) is treated as the variable part of the algorithm which depends on instance characteristic
I.

Example:-
1. Algorithm
abc(x,y,z)
{
return x*y*z+(x-y)
}

Here we have three variables x, y and z. x,y and z each variable requires one unit of memory.
S(p) = c + sp
S(p) = 3 + 0
S(p)=3

2. Algoritham sum(x,n)
{
Total:=0
For i←1 to n do
Total:=total + x[i]
}
S(p)=c+sp
Here c = x,n,total (each one requires one unit of memory)=3
Sp=x[i] and its depends on n
S(p)=3+n

Time complexity
The time complexity of an algorithm is defined as the amount of time taken by an algorithm to
run as a function of the length of the input. Note that the time to run is a function of the length
of the input and not the actual execution time of the machine on which the algorithm is running
on. To estimate the time complexity, we need to consider the cost of each fundamental
instruction and the number of times the instruction is executed.

1. We introduce a variable, count into the program statement to increment count with initial
value 0.Statement to increment count by the appropriate amount are introduced into the program.
This is done so that each time a statement in the original program is executes count is
incremented by the step count of that statement.

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 6


Examples:-
Algorithm sum(a,n)
{
S: = 0.0
For i: = 1 to n do
{
S: = S + a[i]
}
return S
}

Now we can calculate execution statement count. Initially count = 0. Then


Algorithm sum(a,n)
{
S: = 0.0
Count : = count+1;
For i: = 1 to n do
{
Count : = count+1;
S: = S + a[i];
Count : = count+1;

}
Count : = count+1; // for last exexution
return S;
Count : = count+1;
}
If the count is zero to start with, then it will be 2n+3 on termination. So each invocation of sum
executes a total of 2n+3 steps.

2. 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 contributes by each statement.
First determine the number of steps per execution (s/e) of the statement and the total number of
times (ie., frequency) each statement is executed. By combining these two quantities, the total
contribution of all statements, the step count for the entire algorithm is obtained.

Statement S/e Frequency Total

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 7


Statement S/e Frequency Total

1. Algorithm Sum(a,n) 0 - 0
2.{ 0 - 0
3. s:=0.0; 1 1 1
4. for i:=1 to n do 1 n+1 n+1
5. s:=s+a[i]; 1 n n
6. return s; 1 1 1
7.} 0 - 0

Total 2n+3

Algorithm RSum(a, n)
{
if (n <= 0) then return 0.0;
else return RSum (a, n - 1) + a[n]
}

tRSum (n) =2+t RSum (n - 1)


=2+2+ t RSum (n - 2)
= 2(2) + t RSum (n-2)
= n(2) + t RSum (0)
= 2n + 2 n >= 0

So for RSum Algorithm tRSum (n) is 2n + 2

The step count is useful in that it tells us how the run time for a program changes with changes in
the instance characteristics. From the step count of Sum, we see that if n is doubled, the run time
also doubles (approximately)

Worst-case, Average-case, Best-case Time Complexity

Worst-case running time


This denotes the behaviour of an algorithm with respect to the worst possible case of the input
instance. The worst-case running time of an algorithm is an upper bound on the running time for
any input. Therefore, having the knowledge of worst-case running time gives us an assurance
that the algorithm will never go beyond this time limit.

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 8


Average-case running time
The average-case running time of an algorithm is an estimate of the running time for an
‘average’ input. It specifies the expected behaviour of the algorithm when the input is randomly
drawn from a given distribution. Average-case running time assumes that all inputs of a given
size are equally likely.

Best-case running time


The term ‘best-case performance’ is used to analyze an algorithm under optimal conditions. For
example, the best case for a simple linear search on an array occurs when the desired element is
the first in the list. However, while developing and choosing an algorithm to solve a problem, we
hardly base our decision on the best-case performance. It is always recommended to improve the
average performance and the worst-case performance of an algorithm.

ASYMPTOTIC NOTATIONS

Asymptotic notations are used to represent the complexities of algorithms for asymptotic
analysis. These notations are mathematical tools to represent the complexities. There are three
notations that are commonly used.

Big-O Notation (O): It represents the upper bound of the runtime of an algorithm. Big O
Notation's role is to calculate the longest time an algorithm can take for its execution, i.e., it is
used for calculating the worst-case time complexity of an algorithm.

Let g and f be functions from the set of natural numbers to itself. The function f is said to be
O(g) (read big-oh of g), if there is a constant c > 0 and a natural number n0 such that

f(n) ≤ cg(n) for all n ≥ n0 .

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 9


Example-1:
f(n) = 2n+2, g(n) = n2
2n+2 ≤ 3n2 for all n ≥ 2 i.e c=3, n0 =2
f(n) ≤ c g(n) for all n ≥ n0
f(n)=O(g(n)) for all n ≥ 2
Example-2:
3n + 2 = O(n) as 3n + 3 <= 4n n >= 3
3n + 2 = O(n) as 3n + 2 <= 4n for all n >= 2
Example-3:
100n + 6 = O(n) as 100n + 6 <= 101n for n >= 6
Example-4:
10n 2 + 4n + 2 = O(n2) as 10n2 + 4n + 2 <= 11n2 for all n >= 5
Big Omega Notation (Ω): It represents the lower bound of the runtime of an algorithm. It is
used for calculating the best time an algorithm can take to complete its execution, i.e., it is used
for measuring the best case time complexity of an algorithm.

We write f(n) = Ω(g(n)), If there are positive constants n0 and c such that,

c g(n) ≤ f(n), for all n ≤ n0

Example-1:-
f(n) = 2n+2, g(n) = n
2n ≤ 2n + 2, for all n ≥ 2, i.e c=2, n0 =2
i.e cg(n) ≤ f(n) for all n ≥ n0
f(n) = Ω(g(n)) for all n ≥ 2,

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 10


Example-2:-
3n + 2 = Ω(n) as 3n + 2 >= 3n for all n >= 1
Example-3:-
100n + 6 = Ω (n) as 100n + 6 >= 100n, for all n >= 1
Example-4:-
10n2 + 4n + 2 = Ω (n 2) as 10n 2 + 4n + 2 >= n 2 ,for all n >= 1
Big Theta Notation (Θ): It carries the middle characteristics of both Big O and Omega notations
as it represents the lower and upper bound of an algorithm.

We write f(n) = Θ(g(n)), If there are positive constants n0 and c1 and c2 such that, to the right of
n0 the f(n) always lies between c1*g(n) and c2*g(n) inclusive.

Θ(g(n)) = {f(n) : There exist positive constant c1, c2 and n0 such that 0 ≤ c1 g(n) ≤ f(n) ≤ c2 g(n),
for all n ≥ n0}

Example-1:-
f(n) = 2n+2, c1g(n) = 2n, c2g(n)=4n,f(n) = Θ (g(n)) for all n ≥ 2
3n + 2 = Θ (n) as
3n + 2 >= 3n for all n >= 2 and
3n + 2 <= 4n for all n >= 2
Therefore 3n + 3 = Θ(n)
Example-2:-
10n2 + 4n + 2 = Θ(n2) ,
6x2n + n2 = Θ(2n)
10 x log(n) + 4 = Θ (log(n))
Example-3:-
3n+2 ≠ Θ (1)
3n+3 ≠ Θ (n2)

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 11


10n2 + 4n +2≠ Θ(n) ≠ Θ(1)
Common Time Complexities (from most efficient to least efficient):
 O(1): Constant time – the algorithm takes the same amount of time regardless of input
size.
 O(log n): Logarithmic time – time grows logarithmically with input size (e.g., binary
search). Here f(n)=log n
 O(n): Linear time – time grows linearly with input size. Here f(n)=n
 O(n log n): Quasi-linear time – typical for efficient sorting algorithms like merge sort.
Here f(n) = n log n
 O(n²): Quadratic time – often seen in algorithms with nested loops, such as bubble sort.
Here f(n)= n2
n
 O(2 ): Exponential time – very slow, used in algorithms that solve combinatorial
problems. Here f(n)= 2n

Flot of functions

DIVIDE AND CONQUER

Divide and Conquer is a fundamental algorithm design technique used to solve problems by
breaking them down into smaller sub-problems, solving the sub-problems independently, and
then combining their solutions to solve the original problem. It is widely applied in various

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 12


algorithms, particularly those that deal with recursion. divide-and-conquer algorithms that
produce sub problems of the same type as the original problem.

Key Concepts in Divide and Conquer:

1. Divide: The problem is divided into smaller sub-problems of the same type.
2. Conquer: Solve the sub-problems recursively. If the sub-problem size is small enough,
solve it directly (base case).
3. Combine: Merge the solutions of the sub-problems to produce the solution to the original
problem.

Control abstraction for divide and conquer:


Algorithm DAndC(P)
{
if Small(P) then
return S(P)
else
{
divide P into smaller instances P1, P2,...,Pk; k >= 1
Apply DAndC to each of these sub-problems;
return Combine(DAndC(P₁), DAndC (P2),..., DAndC(Pk));
}
}
recursive applications of DAndC. Combine is a function that determines the solution to P using
the solutions to the k sub problems. If the size of P is n and the sizes of the k sub problems are n1
, n2 ,...,nk respectively, then the computing time of DAndC is described by the recurrence relation

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 13


g n n small
T(n)=
T n1 + T n2 +∗∗∗∗∗∗∗∗ +T nk + 𝑓 n otherwise
where T(n) is the time for DAndC on any input of size n and g(n) is the time to compute the
answer directly for small inputs. The function f(n) is the time for dividing P and combining the
solutions to sub problems. divide-and-conquer-based algorithms that produce sub problems of
the same type as the original problem.
It is very natural to first describe such algorithms using recursion.
The complexity of many divide-and-conquer algorithms is given by recurrences of the form

T 1 n = 1
T(n) = n where a and b are known constants.
aT +f n n>1
b
We assume that T(1) is known and n is a power of b (i.e., n = bk )

One of the methods solving any such recurrence relation is called the substitution method. This
method repeatedly makes substitution for each occurrence of the function T in the right-hand
side until all such occurrences disappear.

Time Complexity

The complexity of the divide and conquer algorithm is calculated using the master theorem which
is as follow.
T(n) = aT(n/b) + f(n), where ,n = size of input, a = number of sub-problems in the recursion
n/b = size of each sub-problem.
All sub-problems are assumed to have the same size.
f(n) = cost of the work done outside the recursive call, which includes the cost of dividing the problem
and cost of merging the solutions

Now let’s take an example by finding the time complexity of a recursive problem
T(n) = aT(n/b) + f(n)
= 2T(n/2) + O(n)
Where, a = 2 (each time, a problem is divided into 2 sub-problems)
n/b = n/2 (size of each sub problem is half of the input)
f(n) = time taken to divide the problem and merging the sub-problems
T(n/2) = O(n log n) (To understand this, please refer to the master theorem.)

Now, T(n) = 2T(n log n) + O(n)≈ O(n log n)


e case in which a = 2 and b = 2 Let T(1) = 2 and f(n) = n We have

T(n) = 2T(n / 2) + n
= 21 T(n / 21) + 1 n

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 14


= 2[2T(n / 4) + n / 2] + n
= 4T(n / 4) + 2n
= 22 T(n / 22) + 2n
= 4[2T(n / 8) + n / 4] + 2n
= 8T(n / 8) + 3n
= 23T(n / 23) + 3n
…………………………..
…………………………..
= 2i T(n / (2i)) + in for any n>=2 i >= 1 i.e 𝑙𝑜𝑔2𝑛 >=i>=1 without loss of generality we
assume n=2 i i.e 𝑙𝑜𝑔2𝑛 =i,

Hence
=2i T(1)) + in
=bn + n 𝑙𝑜𝑔2𝑛
= 2n + n 𝑙𝑜𝑔2𝑛
≈ O(n log n)

QUICK SORT

Quick sort is a sorting algorithm that uses the divide and conquers strategy. In this method
division is dynamically carried out. The three steps of quick sort are as follows:
Divide: split the array into two sub arrays that each elements in the left sub array is less than or
equal the middle element and each element in the right is greater than the middle element. The
splitting of the array into two sub arrays is based on pivot element. All the elements that are less
that are less than pivot should be in left sub array and all the elements that are more than pivot
should be in right sub array.
Conquer: Recursively sort the two sub array.
Combine: Combine all the sorted elements in a group to from a list of sorted elements.

The quick sort algorithm works as follows:


1. Select an element pivot from the array elements.
2. Rearrange the elements in the array in such a way that all elements that are less than the pivot
appear before the pivot and all elements greater than the pivot element come after it (equal
values can go either way). After such a partitioning, the pivot is placed in its final position. This
is called the partition operation.
3. Recursively sort the two sub-arrays thus obtained. (One with sub-list of values smaller than
that of the pivot element and the other having higher value elements.)After each iteration, one
element (pivot) is always in its final position. Hence, with every iteration, there is one less
element to be sorted in the array. Thus, the main task is to find the pivot element, which will
partition the array into two halves. To understand how we find the pivot element, follow the
steps given below. (We take the first element in the array as pivot.)
ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 15
Quick sort works as follows:
1. Set the index of the first element in the array to loc and left variables. Also, set the index of
the last element of the array to the right variable. That is, loc = 0, left = 0, and right = n–1
(where n in the number of elements in the array)

2. Start from the element pointed by right and scan the array from right to left, comparing each
element on the way with the element pointed by the variable loc. That is, a[loc] should be less
than a[right].
(a) If that is the case, then simply continue comparing until right becomes equal to loc. Once
right = loc, it means the pivot has been placed in its correct position.
(b) However, if at any point, we have a[loc] > a[right], then interchange the two values and jump
to Step 3.
(c) Set loc = right

3. Start from the element pointed by left and scan the array from left to right, comparing each
element on the way with the element pointed by loc. That is, a[loc] should be greater than a[left].
(a) If that is the case, then simply continue comparing until left becomes equal to loc. Once left =
loc, it means the pivot has been placed in its correct position.
(b) However, if at any point, we have a[loc] < a[left], then interchange the two values and jump
to Step 2.
(c) Set loc = left.

Example Sort the elements given in the following array using quick sort algorithm Let us
consider an array A. 54, 26, 93, 17, 77, 31, 44, 56, 20

First element is considered as pivot element. l = A [0] and r = A [n]. l = l+1 until l > p and r = r - 1
until r < p, this is done until l > r

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 16


Now l = 93 and r = 20 then swap (l, r) i.e. swap (93, 20) then

l = l+1 until l > p

r = r-1 until r < p

Now l = 77 and r = 44, then swap the positions of l and r i.e. swap (77, 44) then the array is

l = l+1 until l > p

r = r-1 until r < p

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 17


Here l = 77, r = 31. But in this position l > r then swap (p, r) i.e. swap (54, 33)

Here 54 are a partition element and fix the 54 position. In this position the left side elements of 54 are
arranged less than 54 and the right side elements of 54 are arranged greater than 54. Now we can
divide the array into two sub arrays.

Partition – 1(sub array -1)

l = l+1 until l > p and r = r-1 until r < p then

Here l > r then swap (p, r)

Here p is a partition element

Continue the same process finally we can get the sorted sub array-1 as

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 18


Partition – 2(sub array -1)

Then combine these two sorted arrays we get the sorted array as

Algorithm QuickSort(p, q)
// Sorts the elements a[p], ..., a[q] which reside in the global
// array a[1: n] into ascending order; a[n+1] is considered to
// be defined and must be ≥ all the elements in a[1: n].
{
if (p <q) then // If there are more than one element
{
// divide P into two sub-problems.
j := Partition(a, p, q + 1); // j is the position of the partitioning element.
// Solve the sub-problems.
QuickSort(p, j – 1);
QuickSort(j + 1, q);
// There is no need for combining solutions.
}
}

Algorithm Partition (a, m, p)


// Within a[m] a[m + 1] a[p - 1] the elements
// rearranged in manner if initially t = a[m]
// then after completion a[q] = t for some q between
// and p - 1 a[k] <= t for m <= k < q and a[k] >= t
// for q < k < p { q returned a[p] = ∞
v:= a[m] ; i :=m; j :=p;
repeat
{
repeat
i:= i + 1 ;
until (a[i] >= v) ;
repeat
j:= j - 1
ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 19
until (a[j] <= v) ;
if (i < j) then Interchange (a, i, j);
} until (i >= j);
a[m] :=a[j]; a[j] :=v;
return j;
}

Algorithm Interchange (a, i, j)


// Exchange a[i] with a[j]
{
p:= a[i];
a[i] :=a[j];a[j]:=p;
}

Complexity of Quick Sort:


In analyzing QuickSort, we count only the number of element comparisons C(n). The frequency
count of other operations same order as C(n). We make the following assumptions: then
elements to be sorted are distinct, and the input distribution is such that the partition element
v = a[m] in the call to Partition (a, m, p) has an equal probability of being the ith smallest
element, 1 <= i <= p - m in a[m : p - 1]

Worst-case value Cw(n):C(n) The number of element comparisons in each call of Partition p - m
+ 1 Let r be the total number of elements in all the calls to Partition level of recursion. At level
one only one call, Partition (a, 1, n + 1) is made and r = n at level two at most two calls are made
and r = n - 1 and so on. At each level of recursion, O(r) element comparisons are made by
Partition. At each level, r is at least one less than the r at the previous level as the partitioning
elements of the previous level are eliminated. Hence Cw(n) is the sum on r as r varies from 2 to n,
or O(n2) .

Average value CA(n): C(n) is much less than Cw(n) Under the assumptions made earlier
partitioning element v has an probability of being the ith-smallest element, 1 <= i <= p - m in
a[m : p - 1] Hence the two sub-arrays remaining to be sorted a[m:j] a[j + 1 : p - 1] with
probability 1 / (p - m), m <= j < p From this we obtain
CA(n) = n + 1 + 1/n 1≤𝑘≤𝑛 [CA (k − 1)) + CA (n − k) ]

The number of element comparisons required by Partition on its first call is n + 1


Note that CA(0) = CA(1) = 0 Multiplying both sides by n, we obtain

nCA (n)=n(n+1)+2[ CA(0) + CA(1) +……+CA (n-1)] ………………(*)

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 20


Replacing n by n – 1
(n - 1)CA(n - 1) =n(n-1)+2[CA (0)+………+CA(n-2)]
Subtracting this from *
nCA(n) - (n - 1)CA(n - 1) = 2n + 2CA(n - 1) or
CA(n) / (n + 1) = CA(n - 1) / n + 2 / (n + 1)
Repeatedly using this equation to substitute for CA(n - 1), CA(n - 2) .... we get
CA(n)/ n+1 = CA (n-2)/n-1+ 2/n + 2/(n + 1)
=CA(n - 3)/(n - 2) + 2/(n - 1) + 2/n + 2/(n + 1)
………………………………………………
……………………………………………….
1
= CA(1)/2 + 2 3≤𝑘≤𝑛+1 𝑘
1
= 2 3≤𝑘≤𝑛+1 𝑘
Since
1 𝑛+1
3≤𝑘≤𝑛+1 𝑘 <= 2
1/𝑥 dx
= ln(n + 1) - ln(2)

CA(n) <= 2(n + 1)[ln(n + 2) - ln(2)] = O(n log(n))

MERGE SORT
Merge sort is a sorting algorithm that uses the divide, conquer, and combine algorithmic
paradigm.
Divide means partitioning the n-element array to be sorted into two sub-arrays of n/2 elements. If
A is an array containing zero or one element, then it is already sorted. However, if there are more
elements in the array, divide A into two sub-arrays, A1 and A2, each containing about half of the
elements of A.
Conquer means sorting the two sub-arrays recursively using merge sort.
Combine means merging the two sorted sub-arrays of size n/2 to produce the sorted array of n
elements.
Merge sort algorithm focuses on two main concepts to improve its performance (running time):
 A smaller list takes fewer steps and thus less time to sort than a large list.
 As number of steps is relatively less, thus less time is needed to create a sorted list from
two sorted lists rather than creating it using two unsorted lists.

The basic steps of a merge sort algorithm are as follows:


 If the array is of length 0 or 1, then it is already sorted.
 Otherwise, divide the unsorted array into two sub-arrays of about half the size.
 Use merge sort algorithm recursively to sort each sub-array.
 Merge the two sub-arrays to form a single sorted list.

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 21


Example:-
Sort the array given below using merge sort. 38, 27, 43, 3, 9, 82, 10

Algorithm MergeSort(low, high)


//a[low high] is a global array to be sorted. a[low high] is a Small(P) is true if there is to sort. In
//this case the list is already sorted. only one element
if ( low <high ) then //If there are more than one element
{
// Divide P into sub-problems.
// Find where to split the set.
mid (low + high)/2];
// Solve the sub-problems.
MergeSort(low, mid);
MergeSort(mid+1, high);
//Combine the solutions.
Merge(low, mid, high);
}

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 22


Algorithm Merge(low, mid, high)
//a[low: high] is a global array containing two sorted
//subsets in a[low, mid] and a[mid+1: high]. The goal is to merge these two sets into a single set
//residing in allow high], b[] is an auxiliary global array
h:=low; i:= low; j:= mid+1;
while ( (h <= mid) and (j<=high)) do
{
if (a[h] <= a[j]) then
{
b[i] :=a[h];
h:=h+1;
}
else
{
b[i] :=a[j];
j:= j + 1 ;
}
i:= i + 1 ;
}
If (h > mid) then
for k :=j to high do
{
i:= i + 1 ;
b[i] :=a[k];
}
else
for k :=h to mid do
{
i:= i + 1 ;
b[i] :=a[k];
}
for k low to high do
a[k] :=b[k];
}

Time Complexity:

The time for the merging operation is proportional to n. then the computing time for merge sort
is described by the recurrence relation

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 23


a, n = 1, a a constant
T(n) = n
2T + cn , n > 1, c a constant
2
When n is a power of 2, n = 2 k, we can solve this equation by successive substitutions
2(2Т(n/4) + сn/2) + сn
= 4T(n / 4) + 2cn
= 4(2T(n / 8) + cn / 4) + 2cn
…………………………
…………………………
= 2k * T(1) + kcn
= an + cn * log(n) ≈ O(n logn)

STRASSEN'S MATRIX MULTIPLICATION

Consider two matrices A and B each of the size N*N. We want to calculate the resultant matrix
C which is formed by multiplying the given two matrices i.e, A and B.Matrix A has a
size N*M and matrix B has a size A*B. Given two matrices are multiplied only when the number
of columns in the first matrix is equal to the number of rows in the second matrix. Therefore, we
can say that matrix multiplication is possible only when M==A.

Let us take the example the multiplication of two matrix of size 3 by 3 is

Where the given matrices are square matrices of size is N*N each.For multiplying every column
with every element in the row from the given matrices uses two loops, and adding up the values
takes another loop. Therefore the overall time complexity turns out to be O(N^3).

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 24


To optimize the matrix multiplication Strassen's matrix multiplication algorithm can be used. It
reduces the time complexity for matrix multiplication. Strassen’s Matrix multiplication can be
performed only on square matrices where N is a power of 2. And also the order of both of the
matrices is N × N.

The main idea is to use the divide and conquer technique in this algorithm. We need to divide
matrix A and matrix B into 8 sub matrices and then recursively compute the submatrices of the
result.

For each multiplication of size N2×N2N2×N2, follow the below recursive function as

Algorithm MM(A,B,n)
{
if(n<=2) then
{
C11=A11B11+ A12B21;
C12=A11B12+ A12B22;
C21=A21B11+ A22B21;
C22=A21B12+ A22B22;
}
else
{
MM(A11 ,B11 ,n/2)+MM(A12 ,B21,n/2);
MM(A11 ,B121 ,n/2)+MM(A12,B22,n/2);
MM(A21 ,B11,n/2)+MM(A22 ,B21,n/2);
MM(A21 ,B11 ,n/2)+MM(A22 ,B22,n/2);
}
}
Where the resultant matrix is C and can be obtained in the following way. Now we need to store
the result as follows:
C11=A11∗B11+A12∗B21 //2 multiplications and 1 addition , input size n/2
C12=A11∗B12+A12∗B22 //2 multiplications and 1 addition, input size n/2
C21=A21∗B11+A22∗B21 //2 multiplications and 1 addition, input size n/2
C22=A21∗B12+A22∗B22 //2 multiplications and 1 addition, input size n/2
ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 25
// Total 8 multiplications and 4 additions, input size n/2

3
The recurrence relation obtained is: T(n)=8T(n/2)+4n2 ≈ O(n ).

To optimize it further, we use Strassen’s Matrix Multiplication where we don't need 8 recursive
calls, as we can solve them using 7 recursive calls and this requires some manipulation which is
achieved using addition and subtraction.

Strassen’s 7 calls are as follows:


P = (A11 + A22) * (B11 + B22)
Q= (A21 + A22) * B11
R= A11 * (B12 - B22)
S=A22 * (B21 - B11)
T=(A11 + A12) * B22
U = (A21 - A11) * (B11 + B12)
V= (A12 - A22) * (B21 + B22)
Now the resultant matrix can be obtained in the following way:

C11 = P + S – T + V
C12 = R + T
C13 = Q + S
C14= P + R – Q + U
Complexity Analysis:
We just need 7 Strassen’s Matrix Multiplications and some 12 additions and 6 subtraction has to
be performed to find the answer. Therefore we have the recurrence relation
b for n ≤ 2
T(n)= n 2
7T 2 + an for n > 2
By solving the above relation
T(n) = 7T(n/2)+an2
= 7 [ 7T(n/4) +a (n/2)2] + an2
= 72 T(n/4)+7a(n/2)2+an2
= 72 [ 7T(n/8) +7a(n/4)2] + an2
= 73T(n/8)+72a(n/4)2+7a(n/2)2+an2
=73 [ 7T(n/16) +7a(n/8)2] +72a(n/4)2+7a(n/2)2+an2

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 26


=74T(n/16) +73 a(n/8)2 +72a(n/4)2+7a(n/2)2+an2
………………………………………………….
…………………………………………………..
=7kT(n/2k) +7k-1 a(n/2k-1)2 +……………..+72a(n/22)2+7a(n/2)2+an2
=7kT(n/2k) +7k-1 a(n2/4k-1) +……………..+72a(n2/42)+7a(n2/4)+an2
=an2[7k-1/ /4k-1 +7k-2/ /4k-2 +……………..+72/42+7/4+1]+ 7kT(n/2k)
=an2[(7/ /4)k-1 +(7/ /4)k-2 +……………..+(7/4)2+7/4+1]+ 7kT(1) for n=2k i.e k=𝐥𝐨𝐠 𝟐 𝒏
=(4/3)an2(7/4)k+7k
𝟕
≤cn2(𝟒)𝐥𝐨𝐠𝟐 𝒏 + 𝟕𝐥𝐨𝐠 𝟐 𝒏 , where c being any constant
= cn2𝒏𝐥𝐨𝐠𝟐 𝟕/𝟒 + 𝒏𝐥𝐨𝐠𝟐 𝟕 //change of base to logorithms
= c𝒏𝟐+𝐥𝐨𝐠𝟐 𝟕/𝟒 + 𝒏𝐥𝐨𝐠𝟐 𝟕
= c𝒏𝐥𝐨𝐠𝟐 𝟒+ 𝐥𝐨𝐠𝟐 𝟕−𝐥𝐨𝐠 𝟐 𝟒+ + 𝒏𝐥𝐨𝐠𝟐 𝟕
=𝒏𝐥𝐨𝐠𝟐 𝟒+ 𝐥𝐨𝐠𝟐 𝟕−𝐥𝐨𝐠 𝟐 𝟒+ + 𝒏𝐥𝐨𝐠𝟐 𝟕
=O(𝒏𝐥𝐨𝐠𝟐 𝟕 )≈ O(𝒏𝟐.𝟖𝟏)

2.81
We got the overall time complexity of approximately is O(n ) which is better than O(n3).

CONVEX HULL

A convex hull is the smallest convex polygon that completely encloses a set of points in a two-
dimensional or three-dimensional space. It can be thought of as the "envelope" or "wrapper" of
the points. We use the divide and conquer approach to solve this by recursively calling the
function for smaller parameters.

Here is an illustration of our approach:


The first step is to find out the farthest two points in the plane:

Then, in the two spaces S1 and S2, we will find out the farthest point:

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 27


We will continue to do operations

Finally, Our resultant polygon would look something like this:

Algorithm Quick-hull(X)
Step 1: Identify two points p1 and p2 with smallest and largest x-coordinate values.

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 28


Step 2: add p1 and p2 to convex full.
Step 3: let X1 be all the points to the left of line segment p1,p2 called as upper hull.
Step 4: let X2 be all the points to the right of line segment p1,p2 called as lower hull.
Step 5: Hull(X1,p1,p2);
Step 6: Hull(X2, p1,p2);

Algorithm Hull(XK,p1,p2)
Step 1: if Xk is null then return.
Step 2: for each p in Xk find the farthest point p3 with largest area.
Step 3: add p3 to convex hull.
Step 4: let Xk1 be all the points to the left of line segment p1, p3.
Step 5: let Xk2 be all the points to the right of line segment p2, p3.
Step 6: Hull(Xk1,p1,p3);
Step 7: Hull(Xk1,p2,p3);

Time Complexity:
Worst-case value: O(n2)
Average value/Best-case Value: O(n logn)

ADVACED DATA STRUCTURES & ALGORITHM ANALYSIS UNIT-2[R23] Page 29

You might also like