Recursive Array Programming - PowerPoint PPT Presentation

1 / 49
About This Presentation
Title:

Recursive Array Programming

Description:

Recursive function definitions assume that a function works for a smaller value. ... We shuffle around elements from a[lo 1] to a[hi] so that all elements less than ... – PowerPoint PPT presentation

Number of Views:60
Avg rating:3.0/5.0
Slides: 50
Provided by: jeffreysro
Category:

less

Transcript and Presenter's Notes

Title: Recursive Array Programming


1
Introduction to Computer Science
Unit 16
  • Recursive Array Programming
  • Recursive Sorting Algorithms

2
Recursive Array Programming
  • Recursive function definitions assume that a
    function works for a smaller value.
  • With arrays, "a smaller value" means a shorter
    array, i.e., a subarray, contiguous elements from
    the original array
  • We'll define a recursive function over an array
    by using the same function over a subarray, and a
    base case
  • Subscripts will mark the lower and upper bounds
    of the subarrays

3
Subarrays
myArray
0
1
2
3
4
5
6
7
8
9
1 through 9
2 through 9
3 through 9
4 through 9
5 through 9
6 through 9
7 through 9
8 through 9
9 through 9
Base case
4
Example Recursively find sum of array elements,
Alo to Ahi
  • Assume sum( ) properly returns sum of elements
    for a smaller array of doubles
  • Then we could writedouble sum (double A,
    int lo, int hi) return ( Alo sum(A, lo
    1, hi) )
  • But we're not done what's the base case?

5
Base Case is when Subarray is Empty, hi is less
than lo
  • double sum (double A, int lo, int hi) if
    (hi lt lo) return 0.0 else return ( Alo
    sum(A, lo 1, hi) )
  • Yes, we could have defined this using(hi lo)
    as the base case

6
Recursive Sorting Algorithms
  • We can use this same idea of recursive functions
    over subarrays to rewrite our sorting algorithms
  • Let's see how this works for selection sort,
    insertion sort, and then some new sorting
    algorithms

7
Selection Sort (REVIEW)
starting order
18
22
35
97
84
55
61
10
47
search through array, find largest value,
exchange with first array value
18
84
22
55
61
10
47
35
97
search through rest of array, find second-largest
value, exchange with second array value
18
35
84
55
22
61
10
47
97
8
Selection Sort Pseudocode (REVIEW)
  • for every first component in the array
  • find the largest component in the array
  • exchange it with the first component

9
The Selection Sort Java Code (REVIEW)
void select (int data) // Uses selection
sort to order an array of integers. int
first, current, largest, temp for (first 0
first lt data.length - 1 first) largest
first for (current first 1 current lt
data.length current) if ( datacurrent
gt datalargest ) largest current //
Postcondition largest is index of largest item
// from first..end of array if (largest !
first) // We have to make a swap temp
datalargest datalargest datafirst //
Make the swap datafirst temp // select
10
Recursive Selection Sort
  • Let's say we want to sort an array A from index
    "lo" to index "hi", largest to smallest
  • We place the largest element in Alo
  • Then recursively sort the rest of the array from
    Alo 1 to Ahi
  • The base case is the one-element subarray when lo
    equals hi

11
The Recursive Selection Sort Java Code
void selectionSort(int data, int lo, int hi)
// data0datalo-1 contain the largest
values in data, // in descending order if (lo
lt hi) //subarray has more than one
element swap(data, lo, findMaximum(data, lo,
hi)) selectionSort(data, lo1, hi) int
findMaximum(int data, int lo, int hi) if
(lo hi) return lo else int
locationOfMax findMaximum(data, lo1, hi)
if (datalo gt datalocationOfMax) return lo
else return locationOfMax
12
Code for swap( )
void swap(int data, int first, int second)
int temp temp datafirst datafirst
datasecond datasecond temp
  • The above version of selectionSort( ) is much
    less efficient than the iterative version we
    show it just as an example of recursive array
    programming

13
What Does the Outside World See?
  • We can use overloading, and provide a
    one-argument version of selectionSort( ) for
    outside use. No one needs to know whether it was
    implemented using recursion or iterationvoid
    selectionSort(int data) selectionSort(data,
    0, data.length - 1)
  • The internal version should be private

14
Insertion Sort
starting order
18
22
35
97
84
55
61
10
47
move through the array, keeping the left side
ordered when we find the 35, we have to slide
the 18 over to make room
35
18
97
84
22
55
61
10
47
18 slid over
continue moving through the array, always keeping
the left side ordered, and sliding values over as
necessary to do so
18
22
35
97
84
55
61
10
47
18 slid over
15
Continue the Insertion Process
the left side of the array is always sorted, but
may require one or more components to be slid
over to make room
18
22
35
97
84
55
61
10
47
35, 22, and 18 slid over
18
22
35
97
84
55
61
10
47
35, 22, and 18 slid over
18
22
35
97
84
55
61
10
47
35, 22, and 18 slid over
16
Continue the Insertion Process
61
18
22
35
97
84
55
10
47
55, 35, 22, and 18 slid over
61
18
22
35
97
84
55
10
47
nothing slides over
61
47
18
22
35
97
84
55
10
35, 22, 18, and 10 slid over
17
The Insertion Sort Java Code(Review)
void insert (int data) // Uses insertion
sort to order an array of integers. int newest,
current, newItem boolean seeking for (newest
1 newest lt data.length newest) seeking
true current newest newItem
datanewest while (seeking) // seeking
newItem's new position on left if
(datacurrent - 1 lt newItem) datacurrent
datacurrent -1 //slide value right current- -
seeking (current gt 0) else
seeking false // while // Postcondition
newItem belongs in datacurrent datacurrent
newItem // newest for // insert
18
How Do We Do Insertion Sort Recursively?
  • How can the ability to sort an array of length
    n-1 be used to sort an array of length n?
  • Answer sort the array of length n-1, then insert
    the nth element in the proper place
  • That is to sort subarray A0Ahi, sort
    A0Ahi-1, then insert Ahi into that smaller
    subarray
  • insertInOrder(A, hi, x) will be used to insert x
    into subarray A0Ahi-1

19
Recursive Insertion Sort
  • void insertionSort(int data, int hi)
  • // Sort data0datahi if (hi gt 0)
  • insertionSort(data, hi-1)
  • insertInOrder(data, hi, datahi)

20
What About insertInOrder( )?
  • We'll define it recursively
  • To insert x into subarray A0Ahi-1
  • If x Ahi-1, then put x into Ahi
  • If x gt Ahi-1, then move Ahi-1 into Ahi and
    insert x into subarray A0Ahi-2

21
Recursive insertInOrder( )
void insertInOrder(int data, int hi, int x)
// Insert x into data0datahi-1,
filling // in datahi in the process. //
data0datahi-1 are sorted. if ( (hi 0)
(datahi-1 gt x) ) datahi x else
datahi datahi-1 insertInOrder(data,
hi-1, x)
22
What Does the Outside World See (again)?
  • We can use overloading, and provide a
    one-argument version of insertionSort( ) for
    outside use. No one needs to know whether it was
    implemented using recursion or iterationpublic
    void insertionSort(int data)
    insertionSort(data, data.length - 1)
  • The internal version should be private

23
More Recursive Sorting Quicksort
  • Quicksort is an O(n2) algorithm in the worst
    case, but its running time is usually
    proportional to n log2 (n) it is the method of
    choice for many sorting jobs
  • Well first look at the intuition behind the
    algorithm take an array

V
O
N
I
C
A
E
R
arrange it so the small values are on the left
half and all the big values are on the right half
O
N
I
C
A
E
R
V
24
Quicksort Intuition
  • Then, do it again

O
N
I
C
A
E
R
V
and again
R
O
N
C
V
I
A
E
The divide-and-conquer strategy will, in general,
take log2n steps to move the A into position. The
intuition is that, doing this for n elements, the
whole algorithm will take O(n log2 n) steps.
25
What Quicksort is really doing
  • 1. Partition array a into smaller elements and
    larger ones smaller ones from a0am-1 (not
    necessarily in order), larger ones in positions
    am1alength-1 (not necessarily in order),
    and the middle element in am. So a

11
5
3
7
19
27
12
18
might be partitioned (with m4) as
5
7
19
3
11
12
18
27
smaller than pivot
larger than pivot
pivot
26
quicksort(), next 2 steps
  • 2. Recursively sort a0am-1. Our a becomes

5
3
7
19
11
12
18
27
pivot
3. Recursively sort am1alength-1. Our a
becomes
5
3
7
19
27
11
12
18
pivot
27
quicksort( )
private void quicksort(double a, int lo, int
hi) int m if (hi gt lo1) // there are at
least 3 elements // so sort recursively m
partition(a, lo, hi) quicksort(a, lo,
m-1) quicksort(a, m1, hi) else // the
base case
28
The base case
  • We have the base case in this recursion when the
    subarray aloahi contains zero elements
    (lohi1), one element (lohi), or two elements
    (lohi-1).
  • With no elements, we ignore it
  • With one element, its already sorted
  • With two elements, we just swap them

// 0, 1, or 2 elements, so sort directlyif (hi
lo1 alo gt ahi) swap(a, lo, hi)
29
quicksort( )
private void quicksort(double a, int lo, int
hi) int m if (hi gt lo1) // there are at
least 3 elements // so sort recursively m
partition(a, lo, hi) quicksort(a, lo,
m-1) quicksort(a, m1, hi) else // 0, 1,
or 2 elements, so sort directly if (hi lo1
alo gt ahi) swap(a, lo, hi)
30
The outside worlds version
  • As usual, we overload quicksort( ) and provide a
    public version that hides the last two
    arguments

public void quicksort(double a) quicksort(a,
0, a.length-1)
31
Now, all we need is partition( )
int partition(double a, int lo, int hi) //
Choose middle element among aloahi, // and
move other elements so that aloam-1 // are
all less than am and am1ahi are // all
greater than am // // m is returned to the
caller
32
Are you feeling lucky?
  • Now, this would work great if we knew the median
    value in the array segment, and could choose it
    as the pivot (i.e., know which small values go
    left and which large values go right). But we
    cant know the median value without actually
    sorting the array!
  • So instead, we somehow pick a pivot and hope that
    it is near median.
  • If the pivot is the worst choice (each time), the
    algorithm becomes O(n2). If we are roughly
    dividing the subarrays in half each time, we get
    an O(nlog2n) algorithm.

33
How to pick the median value
  • There are many techniques for doing this. In
    practice, one good way of choosing the pivot is
    to take the median of three elements,
    specifically alo1, a(lohi)/2, and ahi
  • Well choose their median using the method
    medianLocation( )

34
medianLocation( )
int medianLocation(double a, int i, int j,
int k) if (ai lt aj) if (aj lt
ak) return j else if (ai lt
ak) return k else return i else // aj
lt ai if (ai lt ak) return i else if
(aj lt ak) return k else return j
35
The partitioning process
  • From the three red elements, we choose the
    median, ahi

2
3
5
7
8
1
6
4
9
10
lo1
hi
(lohi)/2
  • We swap the median with alo, and start the
    partitioning process on the rest

2
3
5
8
7
1
6
4
9
10
lo1
hi
(lohi)/2
36
The partitioning process
  • We shuffle around elements from alo1 to ahi
    so that all elements less than the pivot (alo)
    appear to all the elements greater than the pivot
  • Until we are done, we have no way of knowing how
    many elements are less and how many elements are
    greater

2
10
8
9
7
1
6
4
5
3
lo1
hi
(lohi)/2
m
37
The partitioning process
2
10
8
9
7
1
6
4
5
3
lo1
hi
(lohi)/2
m
  • m is the largest subscript that contains a value
    less than the pivot
  • We have discovered (in our example) that m 6
  • We then swap am with alo, placing the pivot
    in its rightful position, in am, then continue
    to sort the left and right subarrays recursively

2
10
8
9
6
1
7
4
5
3
lo1
hi
(lohi)/2
m
lo
pivot
38
How partition( ) works
  • We will use a 3-argument versionint
    partition(double a, int lo, int hi)and a
    4-argument versionint partition(double a,
    int lo, int hi, double pivot)
  • The 3-argument version moves the pivot element
    into alo, calls the 4-argument partition to
    shuffle the elements in the subarray
    alo1ahi, then swaps alo into am and
    returns m

39
3-argument partition( )
int partition(double a, int lo, int hi) //
Choose middle element among aloahi, // and
move other elements so that aloam-1 // are
all less than am and am1ahi are // all
greater than am // // m is returned to the
callerswap(a, lo, medianLocation(a, lo1, hi,
(lohi)/2)) int m partition(a, lo1, hi,
alo) swap(a, lo, m)return m
40
How the 4-argument partition( ) works
  • The 4-argument version does the main work,
    recursively calling itself on subarrays
  • We of course assume partition( ) works on any
    smaller array
  • If the first element of the array is less than or
    equal to pivot, its already in the right place,
    just call partition( ) recursively on the rest

if (alo lt pivot) // alo in correct
half return partition(a, lo1, hi, pivot)
(this is the current lo, not the lo of the
whole array)
41
How the 4-argument partition( ) works
  • If alo gt pivot, then alo belongs in the upper
    half of the subarray, and we swap it with ahi
  • We still dont know where the new alo value
    should go, so we partition recursively on the
    subarray that includes alo but not ahi

if (alo lt pivot) // alo in correct
half return partition(a, lo1, hi, pivot)else
// alo in wrong half swap(a, lo,
hi) return partition(a, lo, hi-1, pivot)
42
How the 4-argument partition( ) works
  • The base case is the one element subarray, when
    lohi. Is the one element small or large?
  • If it is small (less than the pivot), then it is
    at the middle point m (and we can swap it with
    the pivot)
  • Otherwise, it is just above the middle point (and
    we want the pivot swapped with the element just
    below it)

43
4-argument partition( )
int partition(double a, int lo, int hi,
double pivot) if (hi lo) if (alo lt
pivot) return lo else return lo-1 else
if (alo lt pivot) // alo in correct
half return partition(a, lo1, hi, pivot) else
// alo in wrong half swap(a, lo,
hi) return partition(a, lo, hi-1, pivot)
44
Example of partition
  • The starting array

1
4
2
5
3
6
lo
hi
  • Choose the median from among

1
4
2
5
3
6
lo
hi
lo1
(lohi)/2
  • Swap the median with alo

1
3
2
5
4
6
pivot
45
Example of partition
  • Now, partition the subarray (not counting pivot)
    a is now the new subarray

1
3
2
5
4
6
lo
hi
pivot
  • alo gt pivot, so swap it with ahi, and
    continue with the partition

5
3
2
1
4
6
lo
hi
pivot
46
Example of partition
  • alo is now less than pivot, so we leave it and
    continue with the partition

5
3
2
1
4
6
pivot
lo
hi
  • Now alo is greater than pivot, so we swap it
    with ahi and continue with the partition

5
3
2
1
6
4
pivot
lo
hi
47
Example of partition
  • alo is again greater than pivot, so we swap it
    with ahi and continue with the partition

5
3
6
1
2
4
pivot
lo
hi
  • alo is less than the pivot, so lo (i.e., index
    2) is returned by the 4-argument partition( )
    the 3-argument partition then swaps the pivot and
    the middle element

Now were ready to recursively quicksort the left
and right subarrays
5
3
6
1
4
2
pivot
48
quicksort( )
private void quicksort(double a, int lo, int
hi) int m if (hi gt lo1) // there are at
least 3 elements // so sort recursively m
partition(a, lo, hi) quicksort(a, lo,
m-1) quicksort(a, m1, hi) else // 0, 1,
or 2 elements, so sort directly if (hi lo1
Alo gt Ahi) swap(a, lo, hi)
49
Performance Comparison
  • Quicksort
  • Best case O(nlog2n)
  • Worst case O(n2) when the pivot is always the
    second-largest or second-smallest element (since
    medianLocation wont let us choose the smallest
    or largest)
  • Average case over all possible arrangements of n
    array elements O(nlog2n)
  • Selection Sort and Insertion Sort
  • Average case O(n2)
Write a Comment
User Comments (0)
About PowerShow.com