优化冒泡排序

Posted

技术标签:

【中文标题】优化冒泡排序【英文标题】:Optimized Bubble Sort 【发布时间】:2013-04-18 04:29:37 【问题描述】:

我想知道我还能如何,以便它忽略已经排序的元素,即使在第一次通过之后也是如此。

Eg. [4, 2, 3, 1, 5, 6] --> [2, 3, 1, **4, 5, 6**]

我们观察到[4,5,6] 已经按顺序排列,我该如何修改我的代码以便它在下一次传递中忽略这 3 个元素?这意味着排序会更有效?您是否建议使用递归方法?

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;
    

【问题讨论】:

【参考方案1】:

我没有代码,但您可以使用 n 位来跟踪在最后一次传递中执行交换的位置。或者,效率较低,使用单个变量来跟踪执行第一次交换的位置。我们不需要重新比较未交换的元素 - 它们是相同顺序的相同元素,因此我们知道比较将是相同的,我们可以安全地跳过它们。

直觉上我觉得,即使进行了上述优化,冒泡排序仍然无法击败二进制插入排序的比较,并且会引入更多的分支逻辑(在辅助空间之上)来跟踪交换。所以这可能不值得研究,除非有人好奇。

【讨论】:

这并没有提供问题的答案。一旦你有足够的reputation,你就可以comment on any post;相反,provide answers that don't require clarification from the asker。 - From Review【参考方案2】:

您应该为内部循环使用变量“大小”并将其更改为每个循环中最新的交换元素。这样,您的内部循环会上升到最新的“交换”元素并传递其余未交换的元素(又名在他们正确的地方)。即

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);

【讨论】:

【参考方案3】:

这里是使用while循环的最简单、最好和最优的冒泡排序算法。它按升序从左到右对给定数组形式中的数字进行排序。它非常易于理解且易于实施。

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));

输出:

[4, 2, 3, 1, 5, 6]
[1, 2, 3, 4, 5, 6]

【讨论】:

【参考方案4】:

我认为这就是你所需要的。关键是要考虑 数组只到最后一次交换发生的索引(新)。

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;

【讨论】:

【参考方案5】:

首先,你有一个越界访问:

for (int j = 0; j < a.length; j++) 
    if (a[j] > a[j + 1]) 

对于j == a.length-1,所以循环条件应该是j &lt; a.length-1

但是,在冒泡排序中,您知道在经过k 之后,最大的k 元素在数组的最后一个k 条目处排序,因此常规冒泡排序使用

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;
    

现在,当数组有一个长长的排序尾的最大元素时,这仍然会做很多不必要的迭代,比如你有 k,k-1,...,1 作为第一个 k 元素和 k+1100000000 的顺序之后那。标准冒泡排序将通过(几乎)整个数组传递k 次。

但是如果你记得你上次交换的位置,你就会知道在那个索引之后,有顺序最大的元素,所以

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;
    

将对上面的示例进行排序,其中只有一次通过整个数组,其余的仅通过(短)前缀。

当然,总的来说,这不会给你带来太多好处,但无论如何优化冒泡排序都是徒劳的。

【讨论】:

感谢您的详细解释以及发现我的不和谐错误! 对外部循环使用while循环并检查currentSwap变量会更清晰/更清晰。 不知道长尾的最后一次优化,谢谢。【参考方案6】:

我设计了一种方法,通过排除在先前循环中已排序的数组开头和结尾的部分来减少迭代次数。

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;
    

但正如@Daniel Fischer 在之前的回答中所说,it doesn't do a lot with larger arrays。

【讨论】:

【参考方案7】:
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;
    

输出:

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]

【讨论】:

【参考方案8】:
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;

【讨论】:

这不是优化的。您只是反向进行并显示操作所需的时间。【参考方案9】:

您可以使用单个 do-while-loop 而不是两个嵌套的 for-loop,并将逻辑移动到内部 if-statement时间>。后续的 pass 比 pass 索引更短。

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));

输出:

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

另见:Bubble sort output is incorrect

【讨论】:

【参考方案10】:

优化冒泡排序,只有 1 个 for 循环

/*Advanced BUBBLE SORT with ONE PASS*/
/*Authored by :: ***s 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);
    

【讨论】:

【参考方案11】:
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);

【讨论】:

【参考方案12】:

在上面的示例中,数组在第 3 遍后排序,但我们仍将继续第 4、第 5 遍。假设如果数组已经排好序了,那么就不会有交换(因为相邻元素总是按顺序排列的),但我们仍然会继续遍历,仍然会有 (n-1) 次遍历。

如果我们可以确定数组已排序,那么我们应该停止执行进一步的遍历。这是对原始冒泡排序算法的优化。

如果在特定的 pass 中没有交换,这意味着数组已经排序,所以我们不应该执行进一步的 pass。为此,我们可以有一个标志变量,在每次传递之前设置为 true,并在执行交换时设置为 false。

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;
        
    

【讨论】:

以上是关于优化冒泡排序的主要内容,如果未能解决你的问题,请参考以下文章

给自己五分钟,彻底搞懂并优化冒泡排序

冒泡排序,算法以及优化

冒泡排序及其优化

如何优化冒泡排序?

我知道你会冒泡排序,但是你会优化冒泡排序吗?

面试必考算法题之冒泡排序 (优化脱坑版)!