Elementary sorting methods; Merge sort
Elementary sorting methods; Merge sort
We consider the problem of sorting an array of objects. Sorting is a problem that has been much studied and analyzed. There are many, many sorting algorithms. We will look at some elementary sorting algorithms and then consider three fast sorting algorithms: merge sort, heapsort, and quicksort.
Elementary sorting methods
Bubble sort
Basic idea:- Make several passes over the data. On each pass, compare adjacent elements. If they are out of order, interchange them.
- After the first pass, the largest element will be at the end of the array.
- After the second pass, the second largest element will be in the second-last position
- After n-1 passes, the array is sorted.
void bubbleSort(Comparable[] array){
int n = array.length;
for(pass=0; pass<(n-1); pass++)
for(k=0; k<(n-1-pass); k++)
if(array[k].compareTo(array[k+1])>0){
Comparable temp = array[k];
array[k] = array[k+1];
array[k+1] = temp;
}
}
Selection sort
Basic idea:
- Find the smallest element in the array. Interchange it with the element in slot 0.
- Find the smallest element between slot 1 and the end of the array. Interchange it with the element in slot 1.
- Find the smallest element between slot 2 and the end of the array. Interchange it with the element in slot 2.
- Continue until reaching the end of the array. The array is now sorted.
void selectionSort(Comparable[] array){
int n = array.length;
for(int slot=0; slot<(n-1); slot++){
int minindex = slot;
for(int k = slot+1; k<n; k++)
if(array[k].compareTo(array[minindex])<0)
minindex=k;
Comparable temp = array[slot];
array[slot] = array[minindex];
array[minindex] = temp;
}
}
Selection sort can also be described recursively. To sort the elements in slots 0 through n-1,
- Find the smallest element in the array. Interchange it with the element in slot 0.
- Apply selection sort to the elements in slots 1 through n-1.
Insertion sort
Basic idea:- Interchange elements 0 and 1 if they are out of order.
- Elements 0 through 1 form a sorted list. Insert element 2 into this sorted list.
- Elements 0 through 2 form a sorted list. Insert element 3 into this sorted list.
- Elements 0 through 3 form a sorted list. Insert element 4 into this sorted list.
- Continue until the (n-1)st element has been inserted.
void insertionSort(Comparable[] array){
int n = array.length;
for(k=1; k<n; k++){
Comparable temp = array[k];
int next = k-1;
while(next>=0 && array[next].compareTo(temp)>0){
array[next+1]=array[next];
--next;
}
array[next+1] = temp;
}
}
Recursive formulation:
- Apply insertion sort to elements 0 through n-2.
- Insert element n-1 into this sorted list.
void insertionSort(Comparable[] array, int start, int length){ // sort a subarray of array
if(length>1){
insertionSort(array, start, length-1);
Comparable temp = array[length-1];
int next = length-2;
while(next>=0 && array[next].compareTo(temp)>0){
array[next+1]=array[next];
--next;
}
array[next+1] = temp;
}
}
void insertionSort(Comparable[] array){
insertionSort(array, 0, array.length);
}
Q: What are the running times of bubble sort, selection sort, and insertion sort?
Merge sort
- The recursive formulations of selection sort and insertion sort apply their recursive calls to arrays with one fewer element than the original array.
- It works, but could we do better by dividing the array in half and making recursive calls to both halves?
- It worked well for binary search.
- We call this the "divide and conquer" approach.
- It is the principle behind merge sort and quicksort.
Basic idea:
- Split the given array in two halves, one with elements 0 through length/2-1, and the other with elements length/2 through length-1.
- Apply merge sort to each half. We now have two sorted subarrays.
- Merge the two sorted subarrays into a single array.
void mergeSort(Comparable[] array, int start, int length){
if(length>1){
int half = length/2;
mergeSort(array, 0, half);
mergeSort(array, half, length-half);
Comparable[] newArray = merge(array, 0, half, array, half, length-half);
for(int k = 0; k<length; k++)
array[k]=newArray[k];
}
}
void mergeSort(Comparable[] array){
mergeSort(array, 0, array.length);
}
Comparable[] merge(Comparable[] array0, int start0, int length0, Comparable[] array1, int start1, int length1){
Comparable[] result = new Comparable[length0+length1];
int i0 = start0;
int i1 = start1;
int iresult = 0;
while(i0<start0+length0 && i1<start1+length1)
if(array0[i0].compareTo(array1[i1])<0)
result[iresult++] = array0[i0++];
else
result[iresult++] = array1[i1++];
while(i0<start0+length0)
result[iresult++] = array0[i0++];
while(i1<start1+length1)
result[iresult++] = array1[i1++];
return result;
}
Q: What is the running time of merge sort?
We can derive the following recurrence relation:
T(1) = C1
T(n) = C2*n + 2*T(n/2)
Problem: Too much moving of the data, creating new arrays. It would be preferable to be able to sort "in place"; that is, in the original array.