Optimized Bubble Sort
Asked Answered
S

13

16

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, 1, 5, 6] --> [2, 3, 1, **4, 5, 6**]

We observe that [4,5,6] are already in sorted order, how can I modify my code so that it overlooks this 3 elements in the next pass? Which means the sort would be more efficient? Do you suggest a recursive method?

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; j++) {
            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;
    }
}
Sabadell answered 24/4, 2013 at 14:48 Comment(0)
S
28

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;
        // skip the already sorted largest elements
        for (int j = 0; j < a.length - i; j++) {
            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.

Sucker answered 24/4, 2013 at 15:31 Comment(3)
appreciate your detailed explanation as well as spotting that jarring error of mine!Sabadell
it is a bit cleaner/more clear to use a while loop for the outer loop and check the currentSwap variable.Davidoff
I did not know the last optimization for the long ordered tail, thanks.Anatollo
L
1

you should use a variable "size" for the inner loop and change it to the latest swapped element in each cycle.This way your inner loop goes up to the latest "swapped" element and passes the rest that are unswapped (aka in their correctplace). i.e

do {
    int newsize = 0;
    for (int i = 1; i < size; i++) {
        if (a[i - 1] > a[i]) {
            int temp;
            temp = a[i - 1];
            a[i - 1] = a[i];
            a[i] = temp;
            newsize = i;
        }
    }
    size = newsize;
} while (size > 0);
Lisk answered 19/10, 2014 at 14:19 Comment(1)
This won't sort completlyHolmen
S
1
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;
}
Swart answered 11/6, 2015 at 4:4 Comment(1)
This is not optimized. You are only going in reverse and showing the time taken for the operation.Vespasian
E
1
public static void BubbleSorter(params int[] input) {
    int newSize = input.Length - 1, size = 0;
    bool swap;
    do {
        swap = false;
        for (int j = 0; j < newSize; j++) {
            if (input[j] > input[j + 1]) {
                int temp = input[j + 1];
                input[j + 1] = input[j];
                input[j] = temp;
                swap = true;
                size = j;
            }
        }
        newSize = size;
    } while (swap);
    DisplayArrayElements(input);
}
Edenedens answered 1/11, 2015 at 5:10 Comment(0)
M
0

You can use a single do-while-loop instead of two nested for-loops and move the logic into the internal if-statement. Subsequent passes are shorter by the pass index.

public static void bubbleSort(int[] arr) {
    boolean swapped = false;
    int i = 0, pass = 0;
    do {
        if (i < arr.length - 1 - pass) {
            if (arr[i] > arr[i + 1]) {
                int temp = arr[i];
                arr[i] = arr[i + 1];
                arr[i + 1] = temp;
                swapped = true;
            }
            i++;
        } else {
            i = 0;
            pass++;
            swapped = false;
        }
    } while (i < arr.length - 1 - pass || swapped);
}
public static void main(String[] args) {
    int[] arr = {6, 1, 5, 8, 4, 3, 9, 2, 0, 7};
    System.out.println(Arrays.toString(arr));
    bubbleSort(arr);
    System.out.println(Arrays.toString(arr));
}

Output:

[6, 1, 5, 8, 4, 3, 9, 2, 0, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

See also: Bubble sort output is incorrect

Mccray answered 24/4, 2013 at 14:49 Comment(0)
V
0

I devised a method that reduces the number of iterations by excluding parts at the beginning and end of the array that have been ordered in previous loops.

static int[] bubbleSortOptimized(int arr[]) {
    int start = 0, stop = arr.length - 1, control = 0;
    boolean ordered, nsCaught;
    while (true) {
        ordered = true;
        nsCaught = false;
        for (int i = start; i < stop; i++) {
            if (i > 1) {
                if (!nsCaught && arr[i - 2] > arr[i - 1]) {
                    ordered = false;
                    start = i - 2;
                    nsCaught = true;
                }
            }
            if (arr[i] > arr[i + 1]) {
                int hold = arr[i];
                arr[i] = arr[i + 1];
                arr[i + 1] = hold;
                control = i;
            }
        }
        System.out.println(Arrays.toString(arr));
        if (ordered) return arr;
        stop = control;
    }
}

But as @Daniel Fischer said in an earlier answer, it doesn't do a lot with larger arrays.

Vespasian answered 27/10, 2017 at 10:40 Comment(0)
C
0

In the above example, the array got sorted after 3rd pass, but we will still continue with the 4th, 5th pass. Suppose if the array is already sorted, then there will be no swapping (because adjacent elements are always in order), but still we will continue with the passes and there will still be (n-1) passes.

If we can identify, that the array is sorted, then we should stop execution of further passes. This is the optimization over the original bubble sort algorithm.

If there is no swapping in a particular pass, it means the array has become sorted, so we should not perform the further passes. For this we can have a flag variable which is set to true before each pass and is made false when a swapping is performed.

void bubbleSort(int *arr, int n) {
    for (int i = 0; i < n; i++) {
        bool flag = false;
        for (int j = 0; j < n - i - 1; j++) {
            if (array[j] > array[j + 1]) {
                flag = true;
                int temp = array[j + 1];
                array[j + 1] = array[j];
                array[j] = temp;
            }
        }
        // No Swapping happened, array is sorted
        if (!flag) {
            return;
        }
    }
}
Contemplation answered 20/5, 2018 at 18:35 Comment(0)
S
0
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 "+j+" :"+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;
    }
}

Output:

Before Sorting: [1, 9, 2, 3, 4, 5, 6]
Iteration 0 :[1, 9, 2, 3, 4, 5, 6]
Iteration 1 :[1, 2, 9, 3, 4, 5, 6]
Iteration 2 :[1, 2, 3, 9, 4, 5, 6]
Iteration 3 :[1, 2, 3, 4, 9, 5, 6]
Iteration 4 :[1, 2, 3, 4, 5, 9, 6]
Iteration 5 :[1, 2, 3, 4, 5, 6, 9]
Suffuse answered 26/7, 2018 at 7:24 Comment(0)
F
0

I think this is what you need. The key is to consider the array only till the index where last swap occurred (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;
}
Fleet answered 30/6, 2019 at 19:59 Comment(0)
P
0

Here is the simplest, best and optimal Bubble Sort Algorithm using a while loop. It sorts the numbers in the given array form left to right in ascending order. It is very simple to understand and easy to implement.

private static int[] bubbleSort(int[] array) {
    int length = array.length - 1;
    int index = 0;

    while (index < length) {
        if (array[index] > array[index + 1]) {
            swap(array, index, index + 1);
        }
        index++;

        if (index == length) {
            index = 0;
            length--;
        }
    }
    return array;
}

private static void swap(int[] array, int index1, int index2) {
    int temp = array[index1];
    array[index1] = array[index2];
    array[index2] = temp;
}
public static void main(String[] args) {
    int[] arr = {4, 2, 3, 1, 5, 6};
    System.out.println(Arrays.toString(arr));
    bubbleSort(arr);
    System.out.println(Arrays.toString(arr));
}

Output:

[4, 2, 3, 1, 5, 6]
[1, 2, 3, 4, 5, 6]
Palaver answered 23/7, 2019 at 10:58 Comment(0)
V
0

I don't have code, but you could use n bits to keep track of where swaps were performed in the last pass. Or, less effectively, use a single variable to track where the first swap was performed. We don't need to re-compare elements that were not swapped - they are the same elements in the same order, so we know the comparisons will be the same, and we can safely skip them.

Intuitively I feel, even with the above optimization, bubble sort would still not beat the comparisons of a binary insertion sort, and would introduce a lot more branch logic (on top of the auxiliary space) to keep track of the swaps. So this is probably not worth investigating, unless someone is curious.

Volauvent answered 6/10, 2021 at 20:2 Comment(1)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewAlgernon
N
0

You can optimize the bubble sort algorithm by adding a flag to check any elements swapped during pass. If no elements swapped, the array is already sorted and you can exit.

Nawab answered 30/7, 2024 at 3:52 Comment(0)
L
-1

Optimized bubble sort with just 1 for Loop

/*Advanced BUBBLE SORT with ONE PASS*/
/*Authored by :: Brooks Tare  AAU*/
public class Bubble {
    public int[] bubble(int b[]) {
        int temp, temp1;
        for (int i = 0; i < b.length - 1; i++) {
            if (b[i] > b[i + 1]) {
                ///swap(b[i],b[i+1]);
                temp = b[i];
                b[i] = b[i + 1];
                b[i + 1] = temp;
                
                // Checking if there is any number(s) greater
                // than the current number. If there is swap them.
                while (i > 0) {
                    if (b[i] < b[i - 1]) {
                        ///swap(b[i]<b[i-1])
                        temp1 = b[i];
                        b[i] = b[i - 1];
                        b[i - 1] = temp1;
                        i--;
                    } else if (b[i] > b[i - 1]) {
                        i--;
                    }
                }
            } else {
                continue;
            }
        }
        return b;
    }

    ///the following is a function to display the Array 
    public void see(int[] a) {
        for (int j = 0; j < a.length; j++) {
            System.out.print(a[j] + ",");
        }
    }

    public static void main(String[] args) {
        ///You can change the Array to your preference..
        // u can even make it dynamic
        int b[] = {5, 1, 4, 2, 0, 3};
        int v[] = new int[100];
        Bubble br = new Bubble();
        v = br.bubble(b);
        br.see(v);
    }
}
Loan answered 17/8, 2018 at 15:1 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.