I would like to know how else I can optimize bubble sort so that it overlooks elements that have already been sorted, even after the first pass.
Eg. [4, 2, 3
First of all, you have an out-of-bounds access:
for(int j=0; j<a.length; j++) {
if(a[j] > a[j+1]) {
for j == a.length-1
, so the loop condition should rather be j < a.length-1
.
But, in Bubble sort, you know that after k
passes, the largest k
elements are sorted at the k
last entries of the array, so the conventional Bubble sort uses
public static void bubblesort(int[] a) {
for(int i=1; i<a.length; i++) {
boolean is_sorted = true;
for(int j=0; j < a.length - i; j++) { // skip the already sorted largest elements
if(a[j] > a[j+1]) {
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
is_sorted = false;
}
}
if(is_sorted) return;
}
}
Now, that would still do a lot of unnecessary iterations when the array has a long sorted tail of largest elements, say you have k,k-1,...,1
as the first k
elements and k+1
to 100000000
in order after that. The standard Bubble sort will pass k
times through (almost) the entire array.
But if you remember where you made your last swap, you know that after that index, there are the largest elements in order, so
public static void bubblesort(int[] a) {
int lastSwap = a.length-1;
for(int i=1; i<a.length; i++) {
boolean is_sorted = true;
int currentSwap = -1;
for(int j=0; j < lastSwap; j++) {
if(a[j] > a[j+1]) {
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
is_sorted = false;
currentSwap = j;
}
}
if(is_sorted) return;
lastSwap = currentSwap;
}
}
would sort the above example with only one pass through the entire array, and the remaining passes only through a (short) prefix.
Of course, in general, that won't buy you much, but then optimising a Bubble sort is a rather futile exercise anyway.
public class Tester {
static boolean bubbleFlag = true;
public static void main(String[] args) {
int array[] = new int[] {
1,
9,
2,
3,
4,
5,
6
};
bubbleSort(array);
}
private static void bubbleSort(int...array) {
System.out.println("Before Sorting: " + Arrays.toString(array));
for (int i = 0; i < array.length - 1; i++) {
if (i > 0) if (bubbleFlag) break;
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) array = swap(j, j + 1, array);
System.out.println("Iteration " + i + " :" + Arrays.toString(array));
}
bubbleFlag = true;
}
}
private static int[] swap(int i1, int i2, int...is) {
bubbleFlag = false;
is[i1] = is[i1] + is[i2];
is[i2] = is[i1] - is[i2];
is[i1] = is[i1] - is[i2];
return is;
}
}
public static Integer[] optimizedbubbleSort(Integer[] input){
long startTime = System.nanoTime();
boolean swapped = true;
for(int pass=input.length-1; pass>=0 && swapped; pass--){
swapped = false;
for(int i=0; i<pass; i++){
if(input[i]>input[i+1]){
int temp = input[i];
input[i] = input[i+1];
input[i+1] = temp;
swapped = true;
}
}
}
System.out.println("Time taken for OPTIMIZED bubbleSort: "+(System.nanoTime() - startTime));
return input;
}
I think this is what you need. The key is to consider the array only till the index where last swap occured(newn).
public static void bubblesort(int[] a) {
int i, n, newn;
n = a.length;
while (n > 0) {
newn = 0;
for (i = 1; i < n; i++) {
if (a[i - 1] > a[i]) {
temp = a[i];
a[i] = a[i - 1];
a[i - 1] = temp;
newn = i;
}
}
n = newn;
}
return a;
}