Divide and
Conquer
A
problem solving technique
Divide and conquer algorithms
D & C algorithms divide a problem into two or more
smaller problems
The smaller problems are usually the same problem, but
smaller than the original problem
We keep dividing the problem into smaller instances
until the solution of the problem is obvious
D & C is a top down approach
The solution to a top-level problem is found by going
down and finding solutions to smaller instances of the same problem
This is the same method used by recursive routines
When you are writing recursion, you should think at
the problem solving level, and let the system handle the details
Sometimes then it can be rewritten more efficiently
iteratively
This is often the
case if there is tail recursion (no operations are done after the
recursion)
Top down solution to binary search
Known: a sorted array with indices from low to high
Find: the
location of an item x in the array; return 0 if not found
Ignoring the details for now, write in pseudocode a
recursive algorithm to solve this problem
Analyzing the worst case time complexity
What we are looking for here is a way to find the
Big O time complexity, from the way the algorithm runs
We assume that the algorithm is implemented as
efficiently as possible
Since a comparison is the most costly operation,
we are interested in the # of comparisons
For each recursive call,
We make a
comparison to see if we have found the item
Then we divide
the list in half
A mathematical way to express this is:
T(n) = T(n/2) + 1 where T(n) is the running time with input size n
This is called a recurrence
relation
Recurrence relations
Recurrence
relations are used to find the time complexity of recursive function
A recursive
function always has two parts
The stopping place (when the recursion ends)
The rule for making the problem smaller
With binary
search, the stopping place is
T(1) = 1; when n is 1,
there is one comparison
Actually, this is a small simplification
The rule for making the problem smaller is
T(n) = T(n/2) + 1
We must solve
this recurrence relation to find the time complexity
Solving the recurrence relation T(n) = T(n/2) + 1
Solving a
recurrence relation means to find T(n) independently
of previous terms
There are several
ways to do this, depending on the type of recurrence relation
You will spend more time doing this in CS 222
To solve our
recurrence relation lets substitute a number for n and see if we can see a
pattern emerging
We know that T(1) = 1
Let n = 2; T(2) = T(2/2) + 1
n =4;
T(4) = T(4/2) + 1
n=8;
T(8) = T(8/2) + 1
n=16;
T(16) = T(16/2) + 1
At some point, we
should be able to deduce what T(n) is in terms of n,
not in terms of the previous term
Analyzing Merge sort
With merge sort, we divide the list in half, then
recursively merge sort each half; then we have to put the list back together
So T(n) = T(n/2) + T(n/2) + n
Collecting terms
this is T(n) = 2T(n/2) + n
T(1) = 1;
N = 2; T(2) = 2T(1) + 2
N = 4; T(4) = 2T(2) + 4
N = 8; T(8) = 2T(4) + 8
Multiplying large integers
Multiplication of very large integers is used in
encryption schemes
They must
multiply two primes of about 200 digits
The number of bits to represent these integers cannot
be handled directly by the ALU of a single processor
The usual algorithm used to multiple integers is O(n2) since each digit in X is multiplied by each
digit in Y
A divide and conquer algorithm can do better than O(n2)
A concrete example of multiplying large
integers
Suppose X =
61,438,521 and Y=94,736,407
Then XY=5,820,464,730,934,047
Break X and Y into two halves,
consisting of the most significant and least significant digits.
Xhi=6,143 , Xlow = 8,521 Yhi=9,473 Ylow=6,407
It is also true that X = Xhi104
+ Xlow and Y = Yhi104 + Ylow
Multiplying big integers
We have Xh=6,143 ,
Xl = 8,521
Yh=9,473 Yl=6,407
And
X = Xh104
+ Xl and
Y = Yh104
+ Yl
So XY =
XhYh108 + (XhYl + XlYh)104 + XlYl
What do we do if the number of digits in the large
integer is not even
Let n be the
number of digits
Ceiling n/2 is
the number of high digits
Floor n/2 is the
number of low order digits
Floor n/2 is the
exponent
Pseudocode to multiply large integers
public static large
prod(large x, large y)
large x_hi, x_lo, y_hi, y_lo;
int n, m;
n =
max(#0f digits in x and y)
if (x ==
0) || y==0) return 0;
else if (n<= threshold)
return x * y obtained in usual
way
else
{
m = floor n/2;
x_hi = x divide 10m; x_lo = x rem 10m;
y_hi = y divide 10m;
y_lo = y rem 10m;
return (prod x_hi, y_hi) * 102m
+
(prod(x_hi, y_lo)
+ prod(y_hi, x_lo))* 10m +
prod x_lo, y_lo);
Analyzing the multiplication
The time comsuming part of the algorithm is the
recursive calls
return (prod x_hi, y_hi) * 102m
+
(prod(x_hi, y_lo) + prod(y_hi, x_lo))* 10m +
prod x_lo, y_lo);
Notice that this equation has four multiplications,
each half the size of the original problem
Each
multiplication is a recursive call to prod
The addition, subtraction, and divide10m or
rem 10m can be done in linear O(n) time
Here, n is the number of digits
So, what is the recurrence equation T(n)
= ?
T(n) = 4T(n/2)
+ cn; this is an O(n2) algorithm
Improving the time complexity of the
algorithm
To achieve a sub quadratic algorithm, we must use
fewer than four recursive calls
Each
multiplication results in a recursive call
XY = XhYh108
+ (XhYl + XlYh)104
+ XlYl
We can reduce this to three recursive calls by
rewriting the middle term
Note that
the middle term:
XhYl + XlYh
= (Xh+Xl) (Yl+Yh
) - XhYh - XlYl
To see this,
multiply out (Xh+Xl) (Yl+Yh
); of the four terms, two are the first and last terms in the equation
above
Improved pseudo code
public static large
prod2(large x, large y)
large x_hi, x_lo, y_hi, y_lo;
int n, m;
n =
max(#0f digits in x and y)
if (x ==
0) || y==0) return 0;
else if (n<= threshold)
return x * y obtained in usual
way
else
{
m = floor n/2;
x_hi = x divide 10m; x_lo = x rem 10m;
y_hi = y divide 10m;
y_lo = y rem 10m;
r = prod2(x_hi + x_lo,
y_hi + y_lo);
p = prod2(x_hi, y_hi);
q = prod2(x_lo, y_lo);
return p * 102m +
(r p q) * 10m + q;
}
Analyzing the new algorithm
How many recursive calls do we have here?
What is the running time?
T(n) = 3T(n/2)
What is the time complexity?
T(n) O(nlog3)