为什么我的选择排序比插入排序快? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
yusuzhan
V2EX    程序员

为什么我的选择排序比插入排序快?

  •  1
     
  •   yusuzhan 2019-07-02 15:24:14 +08:00 3987 次点击
    这是一个创建于 2294 天前的主题,其中的信息可能已经有所发展或是发生改变。

    刚刚开刷红宝书,好奇测了一下发现 Java 实现的选择排序比插入排序速度快,个人推测是 JVM 上交换位置操作比对比操作消耗大。 当然还是担心是我自己粗心导致的,请大家帮忙看下, tldr 的可以直接看最后面的运行结果。

    选择排序

    public static void sort(Comparable[] a) { int min = 0; for (int i = 0; i < a.length; i++) { min = i; for (int j = i + 1; j < a.length; j++) { if (less(a[j], a[min])) { min = j; } } exch(a, i, min); } } 

    插入排序

    public static void sort(Comparable[] a) { for (int i = 0; i < a.length - 1; i++) { for (int j = i + 1; j > 0; j--) { if (less(a[j], a[j-1])) { exch(a, j, j - 1); } else { break; } } } } 

    性能对比

    public static void timeTest(int n, int repeat) { double selectiOnSortTime= 0; long compareInSelection = 0; long swapInSelection = 0; double bubbleSortTime = 0; double insertiOnSortTime= 0; long compareInInsertion = 0; long swapInInsertion = 0; for (int i = 0; i < repeat; i++) { Integer[] arr0 = genRandomArray(n); Integer[] arr1 = copyArray(arr0); Integer[] arr2 = copyArray(arr0); Stopwatch stopwatch0 = new Stopwatch(); SelectionSort.sort(arr0); selectionSortTime += stopwatch0.elapsedTime(); compareInSelection += SelectionSort.compare; swapInSelection += SelectionSort.swap; Stopwatch stopwatch1 = new Stopwatch(); BubbleSort.sort(arr1); bubbleSortTime += stopwatch1.elapsedTime(); Stopwatch stopwatch2 = new Stopwatch(); InsertionSort.sort(arr2); insertionSortTime += stopwatch2.elapsedTime(); compareInInsertion += InsertionSort.compare; swapInInsertion += InsertionSort.swap; } StdOut.printf("algorithm avg compare swap\n"); StdOut.printf("SelectionSort %f %d %d\n", selectionSortTime / repeat, compareInSelection / repeat, swapInSelection / repeat); StdOut.printf("BubbleSort %f \n", bubbleSortTime / repeat); StdOut.printf("InsertionSort %f %d %d\n", insertionSortTime / repeat, compareInInsertion / repeat, swapInInsertion / repeat); } 

    打印结果

    algorithm avg compare swap SelectionSort 0.001032 499500 1000 BubbleSort 0.001788 InsertionSort 0.001293 250824 249831 
    20 条回复    2019-12-12 21:10:17 +08:00
    davie
        1
    davie  
       2019-07-02 15:27:43 +08:00 via Android
    数据量多大?
    yusuzhan
        2
    yusuzhan  
    OP
       2019-07-02 15:28:58 +08:00
    @davie 数组长度 1000,repeat 5000 次测平均值
    davie
        3
    davie  
       2019-07-02 15:42:00 +08:00 via Android
    随机性呢?
    yusuzhan
        4
    yusuzhan  
    OP
       2019-07-02 15:50:58 +08:00
    @davie 随机性用的红宝书里提供的库,描述是 uniformly

    ```
    /**
    * Rearranges the elements of the specified array in uniformly random order.
    *
    * @param a the array to shuffle
    * @throws IllegalArgumentException if {@code a} is {@code null}
    */
    public static void shuffle(Object[] a) {
    validateNotNull(a);
    int n = a.length;
    for (int i = 0; i < n; i++) {
    int r = i + uniform(n-i); // between i and n-1
    Object temp = a[i];
    a[i] = a[r];
    a[r] = temp;
    }
    }
    ```
    yusuzhan
        5
    yusuzhan  
    OP
       2019-07-02 15:52:18 +08:00
    @davie 在我的电脑上,临界点是 270,超过这个超度的数组,都是选择快
    AmmeLid
        6
    AmmeLid  
       2019-07-02 15:53:16 +08:00
    用数组来做插入排序,还要考虑插入后数据移动的开销吧。
    wutiantong
        7
    wutiantong  
       2019-07-02 16:00:32 +08:00
    很可能是 exch 引入了额外的开销
    yusuzhan
        8
    yusuzhan  
    OP
       2019-07-02 16:03:55 +08:00
    @wutiantong 真没啥,书里原文

    ```
    private static void exch(Comparable[] a, int i, int j) {
    swap++;
    final Comparable swap = a[i];
    a[i] = a[j];
    a[j] = swap;
    }
    ```
    xuwei0056
        9
    xuwei0056  
       2019-07-02 16:07:19 +08:00
    创建 Comparable 的开销大?
    jmc891205
        10
    jmc891205  
       2019-07-02 16:08:10 +08:00
    你再测一下 less 和 exch 的速度好了
    wutiantong
        11
    wutiantong  
       2019-07-02 16:14:53 +08:00
    @yusuzhan 排序算法的性能评估只看比较操作(less)的次数,交换操作(exch)则应尽量降低影响。

    你的这个 exch 恐怕比 less 还要慢一丢丢。
    lance6716
        12
    lance6716  
       2019-07-02 16:19:54 +08:00 via Android
    我咋记得插入排序不是这么写…一个一个往后移,而不是交换
    yusuzhan
        13
    yusuzhan  
    OP
       2019-07-02 16:30:19 +08:00
    @jmc891205 @wutiantong
    测了一下,exch 速度确实慢很多

    compareTime = 0.006
    exchTime = 1.306
    yusuzhan
        14
    yusuzhan  
    OP
       2019-07-02 16:31:42 +08:00
    @xuwei0056 用的 Integer 数组,创建的开销没算, 只统计的排序的速度。刚才看了一下, 确实是 exch 速度比 less 慢导致的。
    wizardoz
        15
    wizardoz  
       2019-07-02 17:24:27 +08:00
    选择排序移动很少,插入排序有很多移动
    算法书上的时间复杂度是以比较次数来计的。
    littlewing
        16
    littlewing  
       2019-07-03 02:27:39 +08:00 via Android
    复杂度低并不代表任何情况下速度就快,因为复杂度算得是极限
    capljf
        17
    capljf  
       2019-12-12 19:53:46 +08:00
    我的 mac pro 上也是选择排序比插入排序快,100 ~ 10000 个 double 随机数,用 StdRandom.shuffle 打乱了。100 ~ 10000 次都试了,都是选择比插入快。搞得我检查了好几遍代码是不是写反了,但代码确实没问题。还得继续找原因
    capljf
        18
    capljf  
       2019-12-12 19:58:26 +08:00
    我猜是插入排序没有做优化,因为每次比较都做了 exch,exch 比较耗时,我去按书上的优化一下,将较大元素都往右移动而不是总是 exch。访问数组的次数能减少一半
    capljf
        19
    capljf  
       2019-12-12 21:07:28 +08:00
    为啥回复不了了,提示验证手机号
    capljf
        20
    capljf  
       2019-12-12 21:10:17 +08:00
    好像我的回复有些词被 block 了。简单说下,刚刚是我的代码写得有问题,插入是比选择快的,优化后的代码 swap 次数确实比优化前少一半左右
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2735 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 12:29 PVG 20:29 LAX 05:29 JFK 08:29
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86