Transcript Document

CSCE350 Algorithms and Data Structure
Lecture 9
Jianjun Hu
Department of Computer Science and Engineering
University of South Carolina
2009.9.
Outline
Divide and Conquer for algorithm design
QuickSort algorithm
Binary Search
Binary Tree traversal
Annoucement:
Algorithm Problems
• http://projecteuler.net/index.php?section=problems
• list of 255 math/programming problems that are excellent
practice with algorithms
Quicksort
Select a pivot (partitioning element)
Rearrange the list so that all the elements in the positions
before the pivot are smaller than or equal to the pivot and
those after the pivot are larger than or equal to the pivot
Exchange the pivot with the last element in the first (i.e., ≤
sublist) – the pivot is now in its final position
Sort the two sublists
p
A[i] ≤ p
A[i]  p
The partition algorithm

or i = r
Illustrations
p
p
p
all are ≤ p
→i
≥p
j←
≤p
...
all are ≤ p
j←
≤p
→i
≥p
all are ≤ p
→ i= j ←
=p
all are ≥ p
all are ≥ p
all are ≥ p
QuickSort Algorithm
ALGO RITHMQuickSort( A[l..r ])
if l  r
s  Partition( A[l..r ]) // s is a splitposition
QuickSort A[l..s  1]
QuickSort A[ s  1..r ]
Quicksort Example
5 3 1 9 8 2 4 7
l=0, r=7
s=4
l=0, r=3
l=5, r=7
s=1
s=6
l=0, r=0
l=2, r=3
l=5, r=5
s=2
l=2, r=1
l=3, r=3
(b)
l=7, r=7
Efficiency of Quicksort
Basic operation: key comparison
Best case: split in the middle — Θ( n log n)
Worst case: sorted array! — Θ( n2)
Average case: random arrays — Θ( n log n)
Improvements:
• better pivot selection: median of three partitioning avoids worst
case in sorted files
• switch to insertion sort on small subfiles
• elimination of recursion
these combine to 20-25% improvement
Binary Search
Brute Force sequential search -- Θ(n)
Binary Search – searching in a sorted array
Basic idea
• Compare a search key K with the array’s middle element A[m]
• If they match, the algorithm stops
• Otherwise, repeat the same operation recursively for the first
half of the array if K<A[m], and for the second half if K>A[m]
K
A[0] … A[m-1] A[m] A[m+1] … A[n-1]
search here if
K<A[m]
search here if
K>A[m]
Algorithm
ALGO RITHMBinarySearch( A[0..n  1], K )
l  0; r  n  1
wh i l el  r do
m  (l  r ) / 2
i f K  A[m ] re tu rnm
e l sei f K  A[m ] r  m  1
e l sel  m  1
re tu rn-1
Example
Search for K=70
index
0 1
2
3
4
5
6
7
value 3 14 27 31 39 42 55 70
iter#1 l
m
8
9
10 11 12
74 81 85 93 98
r
iter#2
l
iter#3
l, m r
m
r
Time Efficiency
In the worst case, no key K exists in this array
Although this is an nonrecursive algorithm, we can see that the time
efficiency can be analyzed using the recurrence relation
T(n)=T(n/2)+1 for n>1, T(1)=1
 T(n) --- Θ(logn)
Exact solution:
T (n)  log2 n  1  log2 (n  1)
Binary search is in fact not a typical example of divide and conquer
because it does not solve two subproblems.
Binary Tree Traversals
A binary tree T is defined as a finite set of nodes that is either
empty or consists of a root and two disjoint binary trees TL
and TR called the left and right subtree of the root
Internal and external nodes: #ext_node = #internal_node+1
TL
TR
Height of a binary tree
ALGO RITHMHeight(T )
if T   re turn 1
e lsere turnmax{Height(TL ), Height(Tr )}  1
Input size n(T): # nodes in T, basic operation: “+”
Recurrence
A(n(T ))  A(n(TL ))  A(n(Tr ))  1, for n(T )  0
A(0)  0
 A(n)=n why?
If the basic operation is the line to check whether a tree is
empty  A(n)=2n+1 why?
Traverse the binary tree
List all the nodes
Preorder traversal: root  left subtree  right subtree
Inorder traversal: left subtree  root  right subtree
Postorder traversal: left subtree  right subtree  root
ALGO RITHM preorder(T )
if T  
ou tpu tTroot
preorder(TL )
preorder(Tr )
What is the efficiency?
Large Integer Multiplication
Some applications, notably modern cryptology, require
manipulation of integers that are over 100 decimal digits
long
Such integers are too long to fit a single word of a computer
Therefore, they require special treatment
Consider the multiplication of two such long integers
If we use the classic pen-and-pencil algorithm to multiply two
n-digit integers, we need n2 digit multiplications
Can we design a divide-and-conquer algorithm to solve this
problem with better efficiency?
The Basic Idea
We want to calculate 23 x 14
Since
23  2  101  3  100 and14  1  101  4  100
We have
23*14  (2  101  3  100 ) * (1  101  4  100 )
 (2 *1)102  (3 *1  2 * 4)101  (3 * 4)100
Which includes four digit multiplications (n2)
But
3 *1  2 * 4
 (2  3) * (1  4)  (2 *1)  (3 * 4)
Therefore, we only need three digit multiplications
One Formula
Given a=a1a0 and b=b1b0, compute c=a*b
We have
c  a * b  c2102  c1101  c0100
wh e re
c2  a1 * b1
c0  a0 * b0
c1  ( a1  a0 ) * (b1  b0 )  ( c2  c0 )
That means only three digit multiplications are needed to
multiply two 2-digit integers
To Multiply Two n-digit integers
Assume n is even, write
a  a110n / 2  a0 andb  b110n / 2  b0
Then
c  a * b  c210n  c110n / 2  c0100
wh e re
c2  a1 * b1
c0  a0 * b0
c1  ( a1  a0 ) * (b1  b0 )  ( c2  c0 )
To calculate the involved three multiplications – recursion!
Stops when n=1
Efficiency
The recurrence relation is
T (n)  3T (n / 2) for n  1, T (1)  1
Solving it by backward substitution for n=2k yields
T (2k )  3T (2k 1 )  32 T (2k 2 )
 3k T (2k k )  3k
Therefore,
T (n)  3log2 n  nlog2 3  n1.585  n2