Download Sorting and Searching

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Sorting and Searching
"Why were you searching for me? Did you not know that I must be in my Father's house?"
Two links showing animated sorts:
http://www.cs.oswego.edu/~mohammad/classes/csc241/samples/sort/Sort2-E.html
http://maven.smith.edu/~thiebaut/java/sort/demo.html
Chapter 12 Litvin has code for the AP tested sorts: Insertion, Selection, and Merge. These
are included on the Student Disk. HW from Litvin: problems 4, 7, 8 on p 343-344. Also
do the Assignments on this handout.
Some of the following material is from Java: How to Program, 6th Edition (Deitel).
Searching is an important topic in computer science (see Google). Searching (looking for
an item (the search key) in a dataset, and returning its location) is most efficient if the
data to be searched is sorted. The search for efficient (fast, consuming little memory)
sorts has resulted in methods embodied in classes such as Java's Arrays class (see
http://www.leepoint.net/notes-java/data/arrays/70sorting.html).
Linear Search
Data need not be sorted for a linear search. For searching small data sets, this search
method works well. It runs in O(n) (pronounced "on the order of n") time. Big O notation
shows how a method's run time grows as the number of items processed increases. If
your data set gets 1000 times bigger, linear search takes 1000 times longer (in the worst
case, having to compare the search key to every item of data).
// Fig 16.2: LinearArray.java from Deitel
// Class that contains an array of random integers and a method
// that will search that array sequentially.
import java.util.Random;
public class LinearArray
{
private int[] data; // array of values
private static Random generator = new Random();
// create array of given size and fill with random integers
public LinearArray( int size )
{
data = new int[ size ]; // create space for array
// fill array with random ints in range 10-99
for ( int i = 0; i < size; i++ )
data[ i ] = 10 + generator.nextInt( 90 );
} // end LinearArray constructor
// perform a linear search on the data
public int linearSearch( int searchKey )
{
// loop through array sequentially
for ( int index = 0; index < data.length; index++ )
1
if ( data[ index ] == searchKey )
return index; // return index of integer
return -1; // integer was not found
} // end method linearSearch
// method to output values in array
public String toString()
{
StringBuffer temporary = new StringBuffer();
// iterate through array
for ( int element : data )
temporary.append( element + " " );
temporary.append( "\n" ); // add endline character
return temporary.toString();
} // end method toString
} // end class LinearArray
// Fig 16.3.: LinearSearchTest.java from Deitel
// Sequentially search an array for an item.
import java.util.Scanner;
public class LinearSearchTest
{
public static void main( String args[] )
{
// create Scanner object to input data
Scanner input = new Scanner( System.in );
int searchInt; // search key
int position; // location of search key in array
// create array and output it
LinearArray searchArray = new LinearArray( 10 );
System.out.println( searchArray ); // print array
// get input from user
System.out.print(
"Please enter an integer value (-1 to quit): " );
searchInt = input.nextInt(); // read first int from user
// repeatedly input an integer; -1 terminates the program
while ( searchInt != -1 )
{
// perform linear search
position = searchArray.linearSearch( searchInt );
if ( position == -1 ) // integer was not found
System.out.println( "The integer " + searchInt +
" was not found.\n" );
else // integer was found
System.out.println( "The integer " + searchInt +
" was found in position " + position + ".\n" );
// get input from user
System.out.print(
"Please enter an integer value (-1 to quit): " );
searchInt = input.nextInt(); // read next int from user
} // end while
} // end main
2
} // end class LinearSearchTest
Note the use of the Random class. All objects of the LinearArray class refer to the same
(static) copy of the random number generator. The nextInt( 90 ) method returns an int
from 0 to 89 (inclusive); adding 10 shifts the values in the array to [10, 99].
Note the use of the enhanced for loop (a Java 5 feature):
for (declaration : expression)
{
statement
}
Here declaration is a variable of the same type as the elements stored in expression. Thus
// iterate through array
for ( int element : data )
temporary.append( element + " " );
is equivalent to:
// iterate through array
for ( int i = 0; i < data.length; i++ )
temporary.append( data[i] + " " );
Assignment 1: Modify the above programs to sort an array of words (type String).
Hint: Here is a code snippet to generate random six character long words.
private static Random rand = new Random();
private static char random() {
return (char) ('A' + rand.nextInt(52));
}
// generate "random" word of 6 characters
public static void fill(String[] words) {
for (int i = 0; i < words.length; i++) {
StringBuffer b = new StringBuffer();
for (int j = 0; j < 6; j++)
b.append((char) random());
words[i] = b.toString();
}
}
3
Binary Search
This is a much faster sorting algorithm, but your data must first be sorted. The search
compares the search key to the item in the middle of the data list. If it does not match, it
divides the list in half, continuing to search only in the appropriate half of the (sorted)
list. For example, if the search key is smaller than the middle data item, it would continue
searching only the half of the list "left" of the middle element. How many comparisons
must be made in the worst case? Divide the number of data elements by 2 repeatedly,
rounding down since we remove the middle item. When you reach 0, count the number of
times you divided by 2 - that is the number of "passes" the search may have to make
through the data. Thus we need the exponent of the first power of 2 bigger than the
number n of data elements, or log2n. Since all logs grow at about the same rate, we say
the run time or this search method is O(log n) or logarithmic run time. But the data must
first be sorted for this to work!
// Fig 16.4: BinaryArray.java from Deitel
// Class that contains an array of random integers and a method
// that uses binary search to find an integer.
import java.util.Random;
import java.util.Arrays;
public class BinaryArray
{
private int[] data; // array of values
private static Random generator = new Random();
// create array of given size and fill with random integers
public BinaryArray( int size )
{
data = new int[ size ]; // create space for array
// fill array with random ints in range 10-99
for ( int i = 0; i < size; i++ )
data[ i ] = 10 + generator.nextInt( 90 );
Arrays.sort( data );
} // end BinaryArray constructor
// perform a binary search on the data
public int binarySearch( int searchElement )
{
int low = 0; // low end of the search area
int high = data.length - 1; // high end of the search area
int middle = ( low + high + 1 ) / 2; // middle element
int location = -1; // return value; -1 if not found
do // loop to search for element
{
// print remaining elements of array
System.out.print( remainingElements( low, high ) );
// output spaces for alignment
for ( int i = 0; i < middle; i++ )
System.out.print( "
" );
System.out.println( " * " ); // indicate current middle
4
// if the element is found at the middle
if ( searchElement == data[ middle ] )
location = middle; // location is the current middle
// middle element is too high
else if ( searchElement < data[ middle ] )
high = middle - 1; // eliminate the higher half
else // middle element is too low
low = middle + 1; // eliminate the lower half
middle = ( low + high + 1 ) / 2; // recalculate the middle
} while ( ( low <= high ) && ( location == -1 ) );
return location; // return location of search key
} // end method binarySearch
// method to output certain values in array
public String remainingElements( int low, int high )
{
StringBuffer temporary = new StringBuffer();
// output spaces for alignment
for ( int i = 0; i < low; i++ )
temporary.append( "
" );
// output elements left in array
for ( int i = low; i <= high; i++ )
temporary.append( data[ i ] + " " );
temporary.append( "\n" );
return temporary.toString();
} // end method remainingElements
// method to output values in array
public String toString()
{
return remainingElements( 0, data.length - 1 );
} // end method toString
} // end class BinaryArray
// Fig 16.5: BinarySearchTest.java from Deitel
// Use binary search to locate an item in an array.
import java.util.Scanner;
public class BinarySearchTest
{
public static void main( String args[] )
{
// create Scanner object to input data
Scanner input = new Scanner( System.in );
int searchInt; // search key
int position; // location of search key in array
// create array and output it
BinaryArray searchArray = new BinaryArray( 15 );
System.out.println( searchArray );
// get input from user
System.out.print(
"Please enter an integer value (-1 to quit): " );
5
searchInt = input.nextInt(); // read an int from user
System.out.println();
// repeatedly input an integer; -1 terminates the program
while ( searchInt != -1 )
{
// use binary search to try to find integer
position = searchArray.binarySearch( searchInt );
// return value of -1 indicates integer was not found
if ( position == -1 )
System.out.println( "The integer " + searchInt +
" was not found.\n" );
else
System.out.println( "The integer " + searchInt +
" was found in position " + position + ".\n" );
// get input from user
System.out.print(
"Please enter an integer value (-1 to quit): " );
searchInt = input.nextInt(); // read an int from user
System.out.println();
} // end while
} // end main
} // end class BinarySearchTest
Note the line "Arrays.sort( data );". This uses the Arrays class (note "import
java.util.Arrays;" built-in sort method to assure the random list of integers data is sorted
before the search begins. Most programmers will use the built-in sort (there is also a
binarySearch( ) method!) and not write their own sort or search method. The sort is a
variation of the Quick sort discussed below, working in n*log(n) time, which is must
faster for large n than the O(n2) time required for simple sorts.
Assignment 2: Run this for 15 sorted items. How much longer do you think it would take
to search 1,048,575 already sorted items? Try it and report your results. What if the items
were not sorted to at the outset? How about linear search?
6
Bubble Sort
void BubbleSort(int a[])
{
int i,j;
for (i=MAXLENGTH; --i >=0;) {
swapped = 0;
for (j=0; j<i;j++) {
if (a[j]>a[j+1]) {
Swap[a[j],a[j+1]);
swapped=1;
}
}
if (!swapped) return;
}
}
This is the quickest version of a bubble sort, where the big, heavy numbers sink to the
bottom of the list and the light, small numbers bubble to the top. Note it does not
compare the final numbers in the data set after they have settled into their resting place
(the inner loop only goes to i, which gets one smaller on each pass). It also uses a flag
variable (swapped) to indicate if a swap was made on a given pass. If an entire pass goes
by without a swap, the method ends, perhaps before completing the worst case n - 1
passes through the n data elements. Still, this is a very slow O(n2) sort. It is quick and
easy, but in part because better methods exist, it is not covered on the AP exam.
Quick Sort
This is quick, and variations of this are among the fastest of all sorts: O(n*log(n)).
Following is a listing of this recursive sort. This is not covered on the AP exam. (A
merge sort is similar and is on the AP exam). First introduced 1960.
int FindPivot(int A[],int l, int r)
{
switch (choice) {
case 1: return l;
case 2: return pivot2(A,l,h)
case 3: return l+random(r-l);
}
}
int partition(int A[], int l, int r)
{
int i,pivot, pivotpos;
pivotpos
= FindPivot(A,l,r);
swap(&A[l],&A[pivotpos]);
pivotpos = l;
pivot = A[pivotpos];
for (i = l+1; i <= r; i++) {
7
if (A[i] < pivot) {
pivotpos++;
swap(&A[pivotpos],&A[i]);
}
}
swap(&A[l],&A[pivotpos]);
return pivotpos;
}
void QuickSort(int A[], int l,int r,
int threshold)
{
int i, pivot;
if (r-l>threshold) {
delay(CompareDelay);
pivot = partition(A,l,r);
QuickSort(A,l,pivot-1,threshold);
QuickSort(A,pivot+1,r,threshold);
}
}
int pivot2(int A[], int l, int r)
{
int i = (r+l)/2;
if ((A[l]
return
if ((A[r]
return
if ((A[r]
return
if ((A[i]
return
if ((A[l]
return
if ((A[i]
return
<=
i;
<=
i;
<=
l;
<=
l;
<=
r;
<=
r;
A[i]) && (A[i] <= A[r]))
A[i]) && (A[i] <= A[l]))
A[l]) && (A[l] <= A[i]))
A[l]) && (A[l] <= A[r]))
A[r]) && (A[r] <= A[i]))
A[r]) && (A[r] <= A[l]))
}
To learn more about this sort, see: http://maven.smith.edu/~thiebaut/java/sort/demo.html
or http://www.cs.oswego.edu/~mohammad/classes/csc241/samples/sort/Sort2-E.html.
8
Selection Sort
This is easy to understand, very predictable, but slow. Find the smallest item in the list
and put it first. Find the smallest item of the remaining unsorted items and swap with the
second item in the list. Continue until you find the smallest item of a small list and swap
with the next to last item. The largest item is left at the end.
For example, starting with: 34 56 04 10 77 51 93 30 05 52
Find smallest item. 04, swap with item at start of list (index or subscript 0). Thus:
04 56 34 10 77 51 93 30 05 52 after pass 1 (underline denotes finished part of list;
bold, swapped items).
Start with the 56 in list (subscript or index 1) and find smallest item in list to right; swap
with the 56. Thus:
04 05 34 10 77 51 93 30 56 52 after pass 2
Assignment 3: Consider the following array of integers.
25 16 49 36 81 64 33 11 22 55 By hand, follow the code and indicate the step by
step output of the sort. Compare with the output obtained by modifying the code so the
data array is not random, but contains the numbers above.
// Fig 16.6: SelectionSort.java from Deitel
import java.util.Random;
public class SelectionSort
{
private int[] data; // array of values
private static Random generator = new Random();
// create array of given size and fill with random integers
public SelectionSort( int size )
{
data = new int[ size ]; // create space for array
// fill array with random ints in range 10-99
for ( int i = 0; i < size; i++ )
data[ i ] = 10 + generator.nextInt( 90 );
} // end SelectionSort constructor
// sort array using selection sort
public void sort()
{
int smallest; // index of smallest element
// loop over data.length - 1 elements
for ( int i = 0; i < data.length - 1; i++ )
{
smallest = i; // first index of remaining array
// loop to find index of smallest element
for ( int index = i + 1; index < data.length; index++ )
if ( data[ index ] < data[ smallest ] )
smallest = index;
swap( i, smallest ); // swap smallest element into position
printPass( i + 1, smallest ); // output pass of algorithm
} // end outer for
} // end method sort
9
// helper method to swap values in two elements
public void swap( int first, int second )
{
int temporary = data[ first ]; // store first in temporary
data[ first ] = data[ second ]; // replace first with second
data[ second ] = temporary; // put temporary in second
} // end method swap
// print a pass of the algorithm
public void printPass( int pass, int index )
{
System.out.print( String.format( "after pass %2d: ", pass ) );
// output elements till selected item
for ( int i = 0; i < index; i++ )
System.out.print( data[ i ] + " " );
System.out.print( data[ index ] + "* " ); // indicate swap
// finish outputting array
for ( int i = index + 1; i < data.length; i++ )
System.out.print( data[ i ] + " " );
System.out.print( "\n
" ); // for alignment
// indicate amount of array that is sorted
for( int j = 0; j < pass; j++ )
System.out.print( "-- " );
System.out.println( "\n" ); // add endline
} // end method printPass
// method to output values in array
public String toString()
{
StringBuffer temporary = new StringBuffer();
// iterate through array
for ( int element : data )
temporary.append( element + "
" );
temporary.append( "\n" ); // add endline character
return temporary.toString();
} // end method toString
} // end class SelectionSort
// Fig 16.7: SelectionSortTest.java
public class SelectionSortTest
{
public static void main( String[] args )
{
// create object to perform selection sort
SelectionSort sortArray = new SelectionSort( 10 );
System.out.println( "Unsorted array:" );
System.out.println( sortArray ); // print unsorted array
sortArray.sort(); // sort array
System.out.println( "Sorted array:" );
System.out.println( sortArray ); // print sorted array
} // end main
} // end class SelectionSortTest
10
Insertion Sort
This works quickly for arrays that are almost in order. Start with the second data item and
compare it to the first. If out of order, swap. On the next pass, look at the third data item;
insert it into the correct position with respect to the first two items. After i passes, the first
i data items will be sorted.
If the original array is:
34 56 04 10 77 51 93 30 05 52
Comparing the first two items, leave them alone as already in order.
After pass 1, we have:
34 56* 04 10 77 51 93 30 05 52
The asterisk marks the item inserted, bold items are in order.
Consider the third item, 04. It is less than 56. Temporarily store the 04 and shift 56 one
spot right. Compare 04 and 34 - we need to swap, so shift the 34 right one space. Place
the 04 at the start of the list. We have:
04* 34 56 10 77 51 93 30 05 52
Now put the 10 into temporary storage. Comparing to 56, we move 56 one step right.
Comparing 10 to 34, we move 34 one step right. Comparing to 04, we put the 10 into
"second position" in the list. We have:
04 10* 34 56 77 51 93 30 05 52
The following code from Deitel puts dashes under the sorted portion of the list, and
places an asterisk by the element inserted into place on a given pass.
// Fig 16.8: InsertionSort.java from Deitel
// Class that creates an array filled with random integers.
// Provides a method to sort the array with insertion sort.
import java.util.Random;
public class InsertionSort
{
private int[] data; // array of values
private static Random generator = new Random();
// create array of given size and fill with random integers
public InsertionSort( int size )
{
data = new int[ size ]; // create space for array
// fill array with random ints in range 10-99
for ( int i = 0; i < size; i++ )
data[ i ] = 10 + generator.nextInt( 90 );
} // end InsertionSort constructor
// sort array using insertion sort
public void sort()
{
int insert; // temporary variable to hold element to insert
// loop over data.length - 1 elements
for ( int next = 1; next < data.length; next++ )
{
// store value in current element
insert = data[ next ];
// initialize location to place element
11
int moveItem = next;
// search for place to put current element
while ( moveItem > 0 && data[ moveItem - 1 ] > insert )
{
// shift element right one slot
data[ moveItem ] = data[ moveItem - 1 ];
moveItem--;
} // end while
data[ moveItem ] = insert; // place inserted element
printPass( next, moveItem ); // output pass of algorithm
} // end for
} // end method sort
// print a pass of the algorithm
public void printPass( int pass, int index )
{
System.out.print( String.format( "after pass %2d: ", pass ) );
// output elements till swapped item
for ( int i = 0; i < index; i++ )
System.out.print( data[ i ] + " " );
System.out.print( data[ index ] + "* " ); // indicate swap
// finish outputting array
for ( int i = index + 1; i < data.length; i++ )
System.out.print( data[ i ] + " " );
System.out.print( "\n
" ); // for alignment
// indicate amount of array that is sorted
for( int i = 0; i <= pass; i++ )
System.out.print( "-- " );
System.out.println( "\n" ); // add endline
} // end method printPass
// method to output values in array
public String toString()
{
StringBuffer temporary = new StringBuffer();
// iterate through array
for ( int element : data )
temporary.append( element + "
" );
temporary.append( "\n" ); // add endline character
return temporary.toString();
} // end method toString
} // end class InsertionSort
// Fig 16.9: InsertionSortTest.java
// Test the insertion sort class.
public class InsertionSortTest
{
public static void main( String[] args )
{
// create object to perform insertion sort
InsertionSort sortArray = new InsertionSort( 10 );
System.out.println( "Unsorted array:" );
12
System.out.println( sortArray ); // print unsorted array
sortArray.sort(); // sort array
System.out.println( "Sorted array:" );
System.out.println( sortArray ); // print sorted array
} // end main
} // end class InsertionSortTest
Assignment 4: Consider the following array of integers.
25 16 49 36 81 64 33 11 22 55
By hand, follow the code and indicate the step by step output of the sort.
Compare with the output obtained by modifying the code so the data array is not random,
but contains the numbers above.
13
Merge Sort
Split the data array in half; sort each subarray, then merge into one larger array. The
following method is recursive; it stops (the base case) when arrays have a size of 1 (and
must be sorted) and calls itself to sort the subarrays.
Consider the data array:
75 56 85 90 49 26 12 48 40 47
Split in half:
75 56 85 90 49 26 12 48 40 47
75 56 85 90 49
26 12 48 40 47
Again:
75 56 85 90 49
75 56 85
90 49
Again:
75 56 85
75 56
85
Again:
75 56
75
56
Merge:
75
note the "splits" are unequal
56
56 75
Continue
Assignment 5: Continue the above sort by hand and compare to the output when the
program is run. Follow the code and be sure you understand how the split and merge
functions are accomplished.
// Figure 16.10: MergeSort.java from Deitel
// Class that creates an array filled with random integers.
// Provides a method to sort the array with merge sort.
import java.util.Random;
public class MergeSort
{
private int[] data; // array of values
private static Random generator = new Random();
// create array of given size and fill with random integers
public MergeSort( int size )
{
data = new int[ size ]; // create space for array
// fill array with random ints in range 10-99
14
for ( int i = 0; i < size; i++ )
data[ i ] = 10 + generator.nextInt( 90 );
} // end MergeSort constructor
// calls recursive split method to begin merge sorting
public void sort()
{
sortArray( 0, data.length - 1 ); // split entire array
} // end method sort
// splits array, sorts subarrays and merges subarrays into sorted array
private void sortArray( int low, int high )
{
// test base case; size of array equals 1
if ( ( high - low ) >= 1 ) // if not base case
{
int middle1 = ( low + high ) / 2; // calculate middle of array
int middle2 = middle1 + 1; // calculate next element over
// output split step
System.out.println( "split:
System.out.println( "
System.out.println( "
System.out.println();
" + subarray( low, high ) );
" + subarray( low, middle1 ) );
" + subarray( middle2, high ) );
// split array in half; sort each half (recursive calls)
sortArray( low, middle1 ); // first half of array
sortArray( middle2, high ); // second half of array
// merge two sorted arrays after split calls return
merge ( low, middle1, middle2, high );
} // end if
} // end method split
// merge two sorted subarrays into one sorted subarray
private void merge( int left, int middle1, int middle2, int right )
{
int leftIndex = left; // index into left subarray
int rightIndex = middle2; // index into right subarray
int combinedIndex = left; // index into temporary working array
int[] combined = new int[ data.length ]; // working array
// output two subarrays before merging
System.out.println( "merge:
" + subarray( left, middle1 ) );
System.out.println( "
" + subarray( middle2, right ) );
// merge arrays until reaching end of either
while ( leftIndex <= middle1 && rightIndex <= right )
{
// place smaller of two current elements into result
// and move to next space in arrays
if ( data[ leftIndex ] <= data[ rightIndex ] )
combined[ combinedIndex++ ] = data[ leftIndex++ ];
else
combined[ combinedIndex++ ] = data[ rightIndex++ ];
} // end while
// if left array is empty
if ( leftIndex == middle2 )
// copy in rest of right array
while ( rightIndex <= right )
combined[ combinedIndex++ ] = data[ rightIndex++ ];
else // right array is empty
15
// copy in rest of left array
while ( leftIndex <= middle1 )
combined[ combinedIndex++ ] = data[ leftIndex++ ];
// copy values back into original array
for ( int i = left; i <= right; i++ )
data[ i ] = combined[ i ];
// output merged array
System.out.println( "
System.out.println();
} // end method merge
" + subarray( left, right ) );
// method to output certain values in array
public String subarray( int low, int high )
{
StringBuffer temporary = new StringBuffer();
// output spaces for alignment
for ( int i = 0; i < low; i++ )
temporary.append( "
" );
// output elements left in array
for ( int i = low; i <= high; i++ )
temporary.append( " " + data[ i ] );
return temporary.toString();
} // end method subarray
// method to output values in array
public String toString()
{
return subarray( 0, data.length - 1 );
} // end method toString
} // end class MergeSort
// Figure 16.11: MergeSortTest.java
// Test the merge sort class.
public class MergeSortTest
{
public static void main( String[] args )
{
// create object to perform merge sort
MergeSort sortArray = new MergeSort( 10 );
// print unsorted array
System.out.println( "Unsorted:" + sortArray + "\n" );
sortArray.sort(); // sort array
// print sorted array
System.out.println( "Sorted:
} // end main
} // end class MergeSortTest
" + sortArray );
16