优化BubbleSort

时间:2018-08-06 05:42:32

标签: java sorting bubble-sort

请帮助我理解优化气泡排序的这两种方法背后的逻辑:

方法1

public static void MyBubbleSort()
{

    for (int i=0; i<list.length; i++)
    {
        boolean is_sorted = true;
        for (int j=0; j<list.length-1; j++)
        {
            if (list[j]>list[j+1])

            {

                    int a = list[j];
                    list[j]=list[j+1];
                    list[j+1]=a;
                    is_sorted = false;
                System.out.println ("Ascending order:"+Arrays.toString(list))} 

方法2

在这里,我不知道-i在内部循环中正在做什么。

 public static void MyBubbleSort()
{

    for (int i=0; i<list.length; i++)
    {

        for (int j=0; j<list.length-1-i; j++) // <-- here
        {
            if (list[j]>list[j+1])

            {

                    int a = list[j];
                    list[j]=list[j+1];
                    list[j+1]=a;

                System.out.println ("Ascending order:"+Arrays.toString(list));

2 个答案:

答案 0 :(得分:0)

在冒泡排序中,在每次迭代结束时,剩余的最大元素到达其最终位置。例如,在以下数组中。

6 2 5 3 8 7 1

第一次迭代后,8将是数组中的最后一个元素,这是它的最终位置。

在第二次迭代结束时,7是数组中的倒数第二个元素,这是它的最终位置。

因此,在每次迭代之后,我们不需要比较已达到其最终位置的元素。

因此,在第一次迭代之后,我们只需要比较长度-1(这里i = 1)个元素。在第二次迭代结束时,我们只需要比较长度-2(i = 2)个元素。

请在https://en.wikipedia.org/wiki/Bubble_sort链接上查看动画。这将有助于提高清晰度。

答案 1 :(得分:0)

Bubble sort通过比较在数组上移的相邻元素来工作。在一个简单的示例[3, 2, 1]中,内部(j-index)循环中的第一个比较是3到2之间; 3次“获胜”并与2交换。然后将3和1相比较,再将3次“获胜”,并位于数组的最后一个索引中,该索引在此第一遍之后为[2, 1, 3]

有效地,内部(j-index)循环的目的是将最大的元素移到数组的后面。最大的要素将一路“赢得”所有比较。

因此,在运行完外部循环之后,最后一个元素肯定会被排序,是最大元素,并且处于最终位置,因此无需重新检查。经过两次外部循环后,最后两个元素就位于其最终位置,并且无需重新检查。按照这种逻辑,我们可以在end - i - 1处停止内部循环以保存毫无意义的比较。

如果您不确定,请在每次内循环运行后使用玩具示例打印整个数组:

import static java.lang.System.out;

class Main {
    public static void bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j+1]) {
                    int t = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = t;
                }
            }

            print(arr, i);
        }
    }

    public static void print(int[] arr, int p) {
        int i = 0;
        out.print(
            "after " + (p + 1) + (p + 1 == 1 ? 
            " pass:   " : " passes: ") + "[ "
        );

        while (i < arr.length - 1 - p) {
            out.print(arr[i++] + ", ");
        }

        out.print("(");

        while (i < arr.length - 1) {
            out.print(arr[i++] + ", ");
        }

        out.println(arr[i] + ") ]");
    }

    public static void main(String[] args) {
        int[] arr = {9,5,7,1,4,7,2};
        bubbleSort(arr);
    }
}

输出

after 1 pass:   [ 5, 7, 1, 4, 7, 2, (9) ]
after 2 passes: [ 5, 1, 4, 7, 2, (7, 9) ]
after 3 passes: [ 1, 4, 5, 2, (7, 7, 9) ]
after 4 passes: [ 1, 4, 2, (5, 7, 7, 9) ]
after 5 passes: [ 1, 2, (4, 5, 7, 7, 9) ]
after 6 passes: [ 1, (2, 4, 5, 7, 7, 9) ]
after 7 passes: [ (1, 2, 4, 5, 7, 7, 9) ]

处于最终位置且无需触摸的元素由括号定界。您可以看到它们始终排在最下面。如果您对此感到好奇,请尝试使用此repl。尝试反向排序并使用各种输入。

附带地,还有其他优化。请注意,在上面的示例中,经过5次之后,数组被完全排序。添加一个布尔标志来确定是否在给定的传递中执行了交换,这使您可以提早纾困并跳过最后的迭代。但是,这些改进都无法解决 O(n 2 时间复杂度的问题-排序所花费的时间与输入大小成比例增长。