Examples of Recursion Data Structures in Java with JUnit ©Rick Mercer.
Transcript of Examples of Recursion Data Structures in Java with JUnit ©Rick Mercer.
Converting Decimal Numbers to other bases
Problem: Convert a decimal (base 10) number into other bases
method Call Return convert(99, 2) 1100011 convert(99, 3) 10200 convert(99, 4) 1203 convert(99, 5) 344 convert(99, 6) 243 convert(99, 7) 201 convert(99, 8) 143 convert(99, 9) 120
Digits are multiplied by powers of the base 10, 8, 2, or whatever
First: converting from other bases to decimal¾ Decimal numbers multiply digits by powers of 10
950710 = 9 x 103 + 5 x 102 + 0 x 101 + 7 x 100
¾ Octal numbers powers of 8
15678 = 1 x 83 + 5 x 82 + 6 x 81 + 7 x 80
= 512 + 320 + 48 + 7 = 88710
¾ Binary numbers powers of 2
11012 = 1 x 23 + 1 x 22 + 0 x 21 + 1 x 20 = 8 + 4 + 0 + 1 = 1310
Converting base 10 to base 2
1) divide number (5) by new base(2), write remainder (1)2) divide quotient (2), write new remainder (0) to left3) divide quotient (1), write new remainder (1) to left
__2_ 2 ) 5 Remainder = 1 __1_ 2 ) 2 Remainder = 0 __0_ 2 ) 1 Remainder = 1
Stop when the quotient is 0 510 = 1012
Print remainders in reverse order
Converting base 10 to base 8
1) divide number by new base (8), write remainder (1)2) divide quotient (2), write new remainder (0) to left3) divide quotient (1), write new remainder (1) to left
_12_ 8 )99 Remainder = 3 __1_ 8 )12 Remainder = 4 __0_ 8 ) 1 Remainder = 1
Stop when the quotient is 0 9910 = 1438
Print remainders in reverse order
Possible Solutions
We could either¾ store remainders in an array and reverse it or¾ write out the remainders in reverse order
· have to postpone the output until we get quotient = 0¾ store result as a String (like a Recursion assignment)
Iterative Algorithm while the decimal number > 0 { Divide the decimal number by the new base Set the decimal number = decimal number divided by the base Store the remainder to the left of any preceding remainders }
Recursive algorithm Base Case -- Recursive Case
Base case¾ if decimal number being converted = 0
· do nothing (or return "")
Recursive case¾ if decimal number being converted > 0
· solve a simpler version of the problem– use the quotient as the argument to the next call
· store the current remainder (number % base) in the correct place
One solution
assertEquals("14", rf.convert(14, 10));assertEquals("1100011", rf.convert(99, 2));assertEquals("143", rf.convert(99, 8));assertEquals("98", rf.convert(98, 10)); // 9*10+8
public String convert(int num, int base) { if (num == 0) return ""; else return convert(num/base, base) + (num%base);}
Hexadecimal, something we see as Computer Scientists
Convert this algorithm to handle all base up through hexadecimal (base 16)¾ 10 = A¾ 11 = B¾ 12 = C¾ 13 = D¾ 14 = E¾ 15 = F
Quicksort: O(n log n) Sorting
Quicksort was discovered by Tony Hoare 1962Here is an outline of his famous algorithm:
¾ Pick one item from the array--call it the pivot¾ Partition the items in the array around the pivot so all
elements to the left are to the pivot and all elements to the right are greater than the pivot
¾ Use recursion to sort the two partitions a snapshot
pivotpartition: items > pivotpartition 1: items pivot
Before and After
Let's sort integers¾ Pick the leftmost one (27) as the pivot value¾ The array before call to partition(a, 0, n-1)
¾ Array looks like this after first partition is done
27 14 9 22 8 41 56 31 14 53 99 11 2 24
24 14 9 22 8 14 11 2 27 53 99 56 31 41
pivotitems < pivot items > pivot
The partition method
partition divvies up a around the split and returns the position of the split, an integer in the range of 0..n-1 ¾ The postcondition of partition:
a[first]..a[split-1] <= a[split] &&
a[split+1]..a[last] > a[split]
Notes:¾ May be more than 1 element equal to the pivot¾ Put them in left partition could have been the right
Recursive call to sort smaller part of the array
quickSort(a, split+1, last); // sort right
QuickSort the right. At some point¾ Pivot will be 53¾ And the left portion will be sorted
24 14 9 22 8 14 11 2 27 53 99 56 31 41
2 8 9 11 14 14 22 24 27 31 41 53 99 56
pivot
items < pivot items > pivot
left is already sorted, begin to sort part to the right of split
Complete the sort
// sort left and right around new split quickSort(a, first, split-1);
// sort right quickSort(a, split+1, last);
2 8 9 11 14 14 22 24 27 31 41 53 99 56
2 8 9 11 14 14 22 24 27 31 41 53 99 56
2 8 9 11 14 14 22 24 27 31 41 53 99 56
2 8 9 11 14 14 22 24 27 31 41 53 56 99
Entire array is now sorted
Start Over (i ==1)
Now let's back up and start with empty partitions
int partition(int a[], int first, int last) { int lastSmall = first; int i = (first + 1); // Beginning of unknowns
Compare all items from a[i]..a[last]¾ if a[i] > a[first] (the pivot), do nothing¾ if a[i] <= a[first], swap a[lastSmall+1] with a[i]
27 41 14 56 31 9 22 8 14 53 99 11 2 24
first lastSmall i unknown items (all are unknown--except first)
Result of the 1st loop iteration(i==2)
27 41 14 56 31 9 22 8 14 53 99 11 2 24
first lastSmall i unknown items
partition 1: all items <= pivot partition 2: all items > pivot
¨ The following array shows no changes were made in the array since a[i] <= a[first] was false
¨ So simply add 1 to i (i++)--create 2 partitions¨ Now partition 1 has one element (the pivot 27)
and partition 2 has 1 element (41)
Result of the 2nd loop iteration(i==3)
27 14 41 56 31 9 22 8 14 53 99 11 2 24
first lastSmall i unknown items
partition 1: all items <= pivot partition 2: all items > pivot
¨ The following array shows a swap was made in the array since a[i] <= a[first] was true (14 < 27)
¨ a[i] (14) is swapped with a[lastSmall+1] (41)¨ lastSmall gets incremented to point to the last
element in partition 1¨ i gets incremented to reference 56
Result of the 3rd loop iteration(i==4)
27 14 41 56 31 9 22 8 14 53 99 11 2 24
first lastSmall i unknown items
partition 1: all items <= pivot partition 2: all items > pivot
¨ The following array shows no swap was made in the array since a[i] <= a[first] was false
¨ lastSmall does NOT get incremented¨ i gets incremented to reference 31
Result of the 4th loop iteration(i==5)
27 14 41 56 31 9 22 8 14 53 99 11 2 24
first lastSmall i unknown items
partition 1: all items <= pivot partition 2: all items > pivot
¨ The following array shows no swap was made in the array since a[i] <= a[first] was false
¨ lastSmall does NOT get incremented¨ i gets incremented to reference 9
Result of the 5th loop iteration(i==6)
27 14 9 56 31 41 22 8 14 53 99 11 2 24
first lastSmall i unknown items
partition 1: all items <= pivot partition 2: all items > pivot
The following array shows a swap was made in the array since a[i] <= a[first] was true (9 < 27)
a[i] (9) is swapped with a[lastSmall+1] (41) lastSmall gets incremented to point to the last
element in partition 1 i++ points to the first unknown (22)
27 14 9 22 31 41 56 8 14 53 99 11 2 24
first lastSmall i unknown items
partition 1: all items <= pivot partition 2: all items > pivot
i == 7
27 14 9 22 8 41 56 31 14 53 99 11 2 24
first lastSmall i unknown
partition 1: all items <= pivot partition 2: all items > pivot
i == 8
27 14 9 22 8 14 56 31 41 53 99 11 2 24
first lastSmall i unknown
partition 1: all items <= pivot partition 2: all items > pivot
i == 9
27 14 9 22 8 14 56 31 41 53 99 11 2 24
first lastSmall i unknown
partition 1: all items <= pivot partition 2: all items > pivot
i == 10
27 14 9 22 8 14 56 31 41 53 99 11 2 24
first lastSmall i unknown
partition 1: all items <= pivot partition 2: all items > pivot
i == 11
27 14 9 22 8 14 11 31 41 53 99 56 2 24
first lastSmall i unknown
partition 1: all items <= pivot partition 2: all items > pivot
i == 12
27 14 9 22 8 14 11 2 41 53 99 56 31 24
first lastSmall i unknown
partition 1: all items <= pivot partition 2: all items > pivot
i == 13
Result of the 14th loop iteration(i==14)
27 14 9 22 8 14 11 2 24 53 99 56 31 41
first lastSmall i
partition 1: all items <= pivot partition 2: all items > pivot
¨ The following array shows what happens after traversing the entire array with this loop (i>last):for (i = first + 1; i <= last; i++) { if(a[i] <= a[first] ) { lastSmall++; swapElements(a, lastSmall, i); }
}
Post Loop Detail
Now place the pivot into where we expect the pivot to be: in-between the two partitions
swapElements( a, first, lastSmall );
Then we can return lastSmall for the next call return lastSmall;
24 14 9 22 8 14 11 2 27 53 99 56 31 41
first lastSmall (pivot position)
partition 1: all items <= pivot partition 2: all items > pivot
quickSort is called like this:quickSort(a, 0, n-1)
void quickSort(int a[], int first, int last) { // precondition: a is an array to be sorted from // a[first]..a[last] if(first >= last) return; // Done: we have an empty array
// The difficult algorithm is in partition int split = partition ( a, first, last );
// Recursively Quicksort left, then right quickSort(a, first, split-1); // sort left quickSort(a, split+1, last); // sort right
// post: the array a is sorted }
Analyzing Quicksort
The critical statement happens in the comparison of the for loop of the partition function
if(a[i] <= a[first]) ¾ So how many times is partition called?¾ And what are the values for first and last (#
comparisons)?If the pivot element is near the mode, we don't
have many calls to QuickSort, it is O(log n)
The best of Quicksort, the worst of Quicksort
In the best case (1st element is always middle value) with 7 elements, call partition 3 times
first == 0, last == 6 // 6 comparisons first == 0, last == 2 // 2 comparisons first == 4, last == 6 // 2 comparisons
In the worst case, (sorted array), with 7 elements, partition is called
first == 0, last == 6 // 6 comparisons first == 1, last == 6 // 5 comparisons first == 2, last == 6 // 4 comparisons first == 3, last == 6 // 3 comparisons first == 4, last == 6 // 2 comparisons first == 5, last == 6 // 1 comparison
Best Case:
[ 4, 1, 3, 2, 6, 5, 7 ]
[ 2, 1, 3, 4, 6, 5, 7 ]
[ 2, 1, 3] [ 6, 5, 7 ]
[ 1, 2, 3] [ 5, 6, 7 ]
[1] [3] [5] [7]
Worst Case
[ 1, 2, 3, 4, 5, 6, 7]
[] [2, 3, 4, 5, 6, 7]
[] [3, 4, 5, 6, 7]
[] [4, 5, 6, 7]
[] [5, 6, 7]
[] [6, 7]
[] [7]
[] []