Lecture 3 divide conquer
Lecture 3 divide conquer
ADVANCED ALGORITHMS
AND PROBLEM SOLVING
Based on slides of Shafi Goldwasser, David Luebke, George Kollios, Roger Crawfis, and Cevdet Aykanat
RECAP
• What have we seen?
• Worst-case vs. average-case analysis
• Stable Marriage Problem
• Fun problem applicable to many scenarios
• Algorithm design must take into account the goals
• Simple correctness proofs
• Insertion Sort
• A daily algorithm (sorting a deck of cards)
• Merge Sort
• Analyzing recurrence relations
• Divide-and-Conquer paradigm
2
DIVIDE AND CONQUER
• Divide the problem into a number of sub-problems
• Similar sub-problems of smaller size
2n bit output
4
MULTIPLYING LARGE INTEGERS:
DIVIDE AND CONQUER
for A0 , A1 , B0 , B1
Divide: Write a = A1 2n/2
+A0
n/2 bit integers
b = B1 2n/2 +B0
Assume n=2k w.l.o.g.
5
MULTIPLYING LARGE INTEGERS:
DIVIDE AND CONQUER
T(n) = 4 T(n/2)+cn
T(n) = 3 T(n/2) + cn
9
EXPONENTIATION
• Problem: compute an, where n is in N.
• Naive algorithm: Compute a1, a2, a3, ..., an Complexity: Θ(n)
multiplications
• Divide-and-Conquer algorithm:
10
MATRIX MULTIPLICATION
for i ← 2 to length[A]
do for j ← 1 to n
do cij ← 0
for k ← 1 to n
do cij ← cij + aik . bkj
Non-square matrices?
12
DIVIDE AND CONQUER
ALGORITHM
• Idea: n x n matrix = 2 x 2 matrix of (n/2) x (n/2) submatrices
C = A ∙ B
13
ANALYSIS OF D&C ALGORITHM
18
QUICKSORT
• Proposed by C.A.R. Hoare in 1962.
• Divide and conquer algorithm but the work is in divide rather than
in combine
• Different versions:
• Basic: Good in average case (for a random input)
• Randomized: good for all inputs in expectation (Randomized Las
Vegas algorithm)
• Sorts in place (like insertation sort, but unlike merge sort).
• Very practical (even though asymptotically not optimal).
19
IDEA: DIVIDE AND CONQUER
• Quicksort an n-element array A:
• Divide:
1. Pick a pivot element x in A
2. Partition the array into three sub-arrays
L(elements < x), E(elements = x), G(elements > x)
20
PSEDOCODE FOR BASIC QUICKSORT
QUICKSORT (A,p,r)
if p < r then
q ← PARTITION(A,p,r)
QUICKSORT(A,p,q-1)
QUICKSORT(A,q+1,r)
21
HOW TO CHOOSE PIVOT X
Basic Quick Sort:
Pivot is the first element: X = A[1]
Time: worst case O(n2) time
O(n log n) time for average input
22
TWO PARTITIONING ALGORTIHMS
23
HOARE PARTITIONING
• Pick first element as pivot
40 20 10 80 60 50 7 30 100
24
PARTITIONING EXAMPLE
pivot_index = 0 40 20 10 80 60 50 7 30 100
too_big_index too_small_index
25
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
pivot_index = 0 40 20 10 80 60 50 7 30 100
too_big_index too_small_index
26
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
pivot_index = 0 40 20 10 80 60 50 7 30 100
too_big_index too_small_index
27
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
pivot_index = 0 40 20 10 80 60 50 7 30 100
too_big_index too_small_index
28
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
pivot_index = 0 40 20 10 80 60 50 7 30 100
too_big_index too_small_index
29
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
pivot_index = 0 40 20 10 80 60 50 7 30 100
too_big_index too_small_index
30
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
pivot_index = 0 40 20 10 80 60 50 7 30 100
too_big_index too_small_index
31
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
pivot_index = 0 40 20 10 30 60 50 7 80 100
too_big_index too_small_index
32
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 60 50 7 80 100
too_big_index too_small_index
33
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 60 50 7 80 100
too_big_index too_small_index
34
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 60 50 7 80 100
too_big_index too_small_index
35
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 60 50 7 80 100
too_big_index too_small_index
36
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 60 50 7 80 100
too_big_index too_small_index
37
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 60 50 7 80 100
too_big_index too_small_index
38
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 7 50 60 80 100
too_big_index too_small_index
39
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 7 50 60 80 100
too_big_index too_small_index
40
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 7 50 60 80 100
too_big_index too_small_index
41
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 7 50 60 80 100
too_big_index too_small_index
42
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 7 50 60 80 100
too_big_index too_small_index
43
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 7 50 60 80 100
too_big_index too_small_index
44
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 7 50 60 80 100
too_big_index too_small_index
45
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 7 50 60 80 100
too_big_index too_small_index
46
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
pivot_index = 0 40 20 10 30 7 50 60 80 100
too_big_index too_small_index
47
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
5. Swap data[too_small_index] and data[pivot_index]
pivot_index = 0 40 20 10 30 7 50 60 80 100
too_big_index too_small_index
48
PARTITIONING EXAMPLE
1. While data[too_big_index] <= data[pivot]
++too_big_index
2. While data[too_small_index] > data[pivot]
--too_small_index
3. If too_big_index < too_small_index
swap data[too_big_index] and data[too_small_index]
4. While too_small_index > too_big_index, go to 1.
5. Swap data[too_small_index] and data[pivot_index]
pivot_index = 4 7 20 10 30 40 50 60 80 100
too_big_index too_small_index
49
PARTITION RESULT
7 20 10 30 40 50 60 80 100
RUNTIME: O(n)
50
RECURSION: QUICKSORT SUB- ARRAYS
7 20 10 30 40 50 60 80 100
51
ANOTHER EXAMPLE OF PARTITIONING
• choose pivot: 4 3 6 9 2 4 3 1 2 1 8 9 3 5 6
• search:4 3 6 9 2 4 3 1 2 1 8 9 3 5 6
• swap:4 3 3 9 2 4 3 1 2 1 8 9 6 5 6
• search:4 3 3 9 2 4 3 1 2 1 8 9 6 5 6
• swap:4 3 3 1 2 4 3 1 2 9 8 9 6 5 6
• search:4 3 3 1 2 4 3 1 2 9 8 9 6 5 6
• swap:4 3 3 1 2 2 3 1 4 9 8 9 6 5 6
• search:4 3 3 1 2 2 3 1 4 9 8 9 6 5 6
• swap with pivot:1 3 3 1 2 2 3 4 4 9 8 9 6 5 6
52
ANOTHER PARTITIONING SUBROUTINE
53
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
i j
54
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
i j
55
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
i j
56
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
6 5 13 10 8 3 2 11
i j
57
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
6 5 13 10 8 3 2 11
i j
58
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
6 5 13 10 8 3 2 11
i j
59
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
6 5 13 10 8 3 2 11
6 5 3 10 8 13 2 11
i j
60
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
6 5 13 10 8 3 2 11
6 5 3 10 8 13 2 11
i j
61
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
6 5 13 10 8 3 2 11
6 5 3 10 8 13 2 11
6 5 3 2 8 13 10 11
i j
62
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
6 5 13 10 8 3 2 11
6 5 3 10 8 13 2 11
6 5 3 2 8 13 10 11
i j
63
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
6 5 13 10 8 3 2 11
6 5 3 10 8 13 2 11
6 5 3 2 8 13 10 11
i j
64
EXAMPLE OF PARTITIONING
6 10 13 5 8 3 2 11
6 5 13 10 8 3 2 11
6 5 3 10 8 13 2 11
6 5 3 2 8 13 10 11
2 5 3 6 8 13 10 11
i
65
LOMUTO PARTITIONING
• Select the last element A[r] in the subarray A[p..r] as
the pivot.
• The array is partitioned into four (possibly empty)
regions.
1. A[p..i ] — All entries in this region are < pivot.
2. A[i+1..j – 1] — All entries in this region are > pivot.
3. A[r] = pivot.
4. A[j..r – 1] — Not known how they compare to pivot.
• These hold before each iteration of the for loop, and
constitute a loop invariant.
66
CORRECTNESS OF PARTITION
• Use loop invariant. 1.
2.
A[p..i ] < pivot
A[i+1..j – 1] > pivot
• Initialization: 3. A[r] = pivot
x >x
p i j r
x
x >x
1. A[p..i ] < pivot
2. A[i+1..j – 1] > pivot
3. A[r] = pivot
68
CORRECTNESS OF PARTITION
• Case 2: A[j] x
• Increment i 1. A[p..i ] < pivot
• Swap A[i] and A[j] 2. A[i+1..j – 1] > pivot
• Increment j 3. A[r] = pivot
p i j r
x x
x >x
p i j r
x
x >x
69
CORRECTNESS OF PARTITION
• Termination:
• When the loop terminates, j = r, so all elements in A are partitioned
into one of the three cases:
• A[p..i] pivot
• A[i+1..j – 1] > pivot
• A[r] = pivot
• At last, swap A[i+1] and A[r].
• Before swap A[i+1] > pivot
• After swap pivot moves from the end of the array to between the two
subarrays.
• Thus, procedure partition correctly performs the divide step.
70
ANALYZING QUICKSORT
• What will be the worst case for the algorithm?
• Partition is always unbalanced
• What will be the best case for the algorithm?
• Partition is perfectly balanced
• Which one is more likely?
• Balanced, except...
• Will any particular input cause the worst case?
• Yes: Already-sorted or reverse-sorted input
71
Worst Case Partitioning
Worst-case partitioning
One region has one element and the other has n – 1 elements
Maximally unbalanced
Recurrence: q=1 n n
1 n-1 n
T(n) = T(1) + T(n – 1) + n, n-1
1 n-2
T(1) = (1) n 1 n-3 n-2
T(n) = T(n – 1) + n 1
2 3
1 1 2
= n
n + k − 1 = (n) + (n 2 ) = (n 2 ) (n2)
k =1
72
WORST CASE
Depth Partition Time
0 n
1 n-1
… …
n-1 1
• Total: n + ( n - 1 ) + …… + 2 + 1
• Thus, the worst-case running time of quicksort is O(n2)
73
WORST-CASE RECURSION TREE
𝑻 𝒏 = 𝑻 𝟎 + 𝑻 𝒏 − 𝟏 + 𝒄𝒏
𝒄𝒏
𝑻𝟎 𝒄 𝒏 −𝟏
𝒉= 𝒏 𝑻𝟎 𝒄(𝒏 − 𝟐)
𝑻𝟎 ⋱
𝑻(𝟏)
74
WORST-CASE RECURSION TREE
𝑻 𝒏 = 𝑻 𝟏 + 𝑻 𝒏 − 𝟏 + 𝒄𝒏
𝒏
𝒄𝒏
𝜣 ∑𝒌 = 𝜣(𝒏𝟐)
𝒌=𝟏
Θ𝟏 𝒄 𝒏 −𝟏
𝒉= 𝒏 Θ𝟏 𝒄(𝒏 − 𝟐)
Θ𝟏 ⋱
Θ(𝟏)
𝑻 𝒏 = 𝜣 𝒏 + 𝜣(𝒏𝟐) = 𝜣(𝒏𝟐)
75
Best Case Partitioning
• Best-case partitioning
• Partitioning produces two regions of size n/2
• Recurrence: q=n/2
• T(n) = 2T(n/2) + (n)
• T(n) = (nlgn)
(Master theorem)
76
What if the split is ??
• Partition into two halves
• T(n) = 2 T(n/2) + cn
• T(n) = (n log n)
1 9
• What if the split is always ∶ ?
10 10
• T(n) = T( 1 n) + T( 9 n) + cn
10 10
77
n cn
log𝟏𝟎 𝒏
1/10 n 9/10 n cn
81/1000 n 729/1000 n cn
1
≤cn
log𝟏𝟎 𝒏
𝟗 1 ≤cn
O(n logn)
78
How does partition affect
performance?
79
INTUTION FOR AVERAGE CASE
• Assumption: All permutations equally likely (realistic??)
• Unlikely: Splits always the same way at every level
• Expectation: Some splits will be reasonably balanced.
Some splits will be fairly unbalanced.
• Average case: A mix of good and bad splits.
Good and bad splits distributed randomly through the tree.
Good and bad splits occur in the alternate levels of the tree.
• Good split: Best-case split (n/2 and n/2)
• Bad split: Worst-case split (1 and n-1)
80
INTUTION FOR AVERAGE CASE
Average case
• All permutations of the input numbers are equally likely
• On a random input array, we will have a mix of well balanced and
unbalanced splits
• Good and bad splits are randomly distributed across throughout the
tree