【问题标题】:Why is selection sort faster than bubble sort? [duplicate]为什么选择排序比冒泡排序快? [复制]
【发布时间】:2019-02-26 09:22:13
【问题描述】:

我使用 Java 进行了一项实验,以确定哪种排序方法(冒泡或选择)的运行时间更快。程序提示用户输入一个数字n,这是要排序的数组中的项目数。然后它创建并排序 500 个这种大小的不同数组,并对运行时间进行排序,以获得使用这两种排序方法进行排序的平均时间。我使用 500、1000 和 2500 作为 n 的测试输入。我下面的结果表明,选择排序比冒泡排序运行得更快,但是这两种算法的时间复杂度都是 O(n^2),那么为什么选择排序运行得这么快呢?

TimeBubbleSort 类

public class TimeBubbleSort {
    public static void main(String[] args) {

        System.out.print("Enter a number of items in array: ");
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();

        long start_time = 0;
        long end_time = 0;
        long running_time = 0;
        long final_time = 0;
        BubbleSort bubbleSort = new BubbleSort();

        for(int i = 0; i < 500; i++) {
            int[] array = new int[n];
            for(int j = 0; j < array.length; j++) {
                array[j] = (int)(Math.random() * n) + 1;
            }
            start_time = System.nanoTime();
            bubbleSort.bubbleSort(array);
            end_time = System.nanoTime();
            running_time = end_time - start_time;
            final_time = final_time + running_time;
        }
        System.out.println("The average time of each array took " + 
(final_time / 500) + " nanoseconds");
    }
}

BubbleSort 类

public class BubbleSort {

    void bubbleSort(int[] arr) {
        int n = arr.length;
        int temp = 0;
        for (int i = 0; i < n; i++)
            for (int j = 1; j < (n - i); j++)
                if (arr[j - 1] > arr[j]) {
                    temp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = temp;
                }
    }

    void printArray(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n; ++i)
            System.out.print(arr[i] + " ");
        System.out.println();
    }
}

TimeSelectionSort 类

public class TimeBubbleSort {
    public static void main(String[] args) {

        System.out.print("Enter a number of items in array: ");
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();

        long start_time = 0;
        long end_time = 0;
        long running_time = 0;
        long final_time = 0;
        SelectionSort selectionSort = new SelectionSort();

        for(int i = 0; i < 500; i++) {
            int[] array = new int[n];
            for(int j = 0; j < array.length; j++) {
                array[j] = (int)(Math.random() * n) + 1;
            }
            start_time = System.nanoTime();
            selectionSort.selectionSort(array);
            end_time = System.nanoTime();
            running_time = end_time - start_time;
            final_time = final_time + running_time;
        }
        System.out.println("The average time of each array took " + 
(final_time / 500) + " nanoseconds");
    }
}

SelectionSort 类

public class SelectionSort {
    void sort(int arr[]) {
        int n = arr.length;

        for (int i = 0; i < n - 1; i++) {
            int min_idx = i;
            for (int j = i + 1; j < n; j++)
                if (arr[j] < arr[min_idx])
                    min_idx = j;

            int temp = arr[min_idx];
            arr[min_idx] = arr[i];
            arr[i] = temp;
        }
    }

    void printArray(int arr[]) {
        int n = arr.length;
        for (int i=0; i<n; ++i)
            System.out.print(arr[i]+" ");
        System.out.println();
    }
}

使用冒泡排序的结果

数组大小为 500:耗时 284,979 纳秒

数组大小为 1000:耗时 960,067 纳秒

数组大小为 2500:耗时 7,448,865 纳秒

使用选择排序的结果

数组大小为 500:耗时 107,035 纳秒

数组大小为 100:耗时 342,464 纳秒

数组大小为 2500:耗时 1,880,215 纳秒

【问题讨论】:

  • 这不是一个准确的基准:stackoverflow.com/questions/504103/…
  • 如果两个算法都是O(n^2),那么它们的运行时间并不相同。一方面,O(n^2) 中固有的比例渐近常数会因算法及其实现的细节而异。
  • 哇,这可以追溯到 1980 年代教人们如何在 COBOL 中编写选择排序的回忆。

标签: java arrays sorting bubble-sort selection-sort


【解决方案1】:

首先,与系统时间进行比较并不是分析两种算法时间复杂度的正确方法,因为请记住 - 您的程序并不是系统上运行的唯一程序。因此即使算法和输入相同,两个运行时间也可能完全不同。

现在来回答您的问题,与选择排序相比,冒泡排序交换次数更多,我们在每次迭代中仅在最后一步交换。所以可能是这个原因。

并且具有相同时间复杂度的两种算法并不意味着它们的运行时间相同。首先,它们的时间复杂度是近似的,这是贡献最大的最大因素。在上述两种情况下,最大的因素是 n^2,但还有其他较小的 n 次方和常数会有所不同。

【讨论】:

  • 虽然使用系统计时器不是一个好习惯,但他会这样做 500 次,但应该平均下来。
  • 我就是这么说的。除此之外还有许多进程在运行,它们的调度和其他因素将永远不会相同
  • @KevinAnderson 否——请注意,他的终止条件是 n - i。这里的比较次数大致相同。
  • @KevinAnderson 冒泡排序中的比较也会减少。在冒泡排序的情况下,我们不会一直走到最后,而在选择排序中,我们不会从开始考虑元素
  • 不同之处在于,在升序(非降序)排序的情况下,我们将开始在选择排序中遗漏前几个元素,而在冒泡排序的情况下,我们将在最后一个。我希望你明白这几个人的意思
【解决方案2】:

虽然您在这里使用系统计时器是有问题的,但您是否进行了足够多的试验,我认为这不是罪魁祸首。我也很难相信交换消耗了 Brij Raj Kishore 的答案正确所需的总时间的近 2/3。

虽然你的循环结构并不完全相同,但它们都运行了大约 n^2/2 次,所以那里也不应该有任何大的差异。

因此,我认为应该进行更多挖掘。我不知道您的系统上有哪些可用的分析器,但除非有人在这里找到大的东西,否则这将是我的下一步。看看你的日常工作实际上是把时间花在了哪里。

【讨论】:

    猜你喜欢
    • 2021-11-24
    • 2018-03-28
    • 2017-03-18
    • 2021-05-13
    • 2011-11-30
    • 2015-09-13
    • 2015-09-12
    • 2015-02-14
    相关资源
    最近更新 更多