【问题标题】:Why is my Shell Sort so slow?为什么我的 Shell 排序这么慢?
【发布时间】:2014-02-28 20:28:24
【问题描述】:

我正在尝试在 JavaScript 中实现一堆排序算法,但我不明白为什么我的 shell 排序这么慢。它比我的合并排序慢 6 倍,并且只比我的插入排序快一点。我在网上看到了另一种实现,但我更专注于使其清晰易读(因为我有一个新手博客),而且更快的实现对于我的目的来说太简洁了。关于如何保持总体计划但加快进度的任何想法?

  var shellSort = function( list ) {
    var gapSize = Math.floor( list.length / 2 );

    while( gapSize > 0 ) {
      _shellInsertionSort( list, gapSize );
      gapSize = Math.floor( gapSize / 2 );
    }

    return list;
  };

  function _shellInsertionSort( list, gapSize ) {
    var temp, i, j;

    for( i = gapSize; i < list.length; i += gapSize ) {
      j = i;
      while( j > 0 && list[ j - gapSize ] > list[j] ) {
        temp = list[j];
        list[j] = list[ j - gapSize ];
        list[ j - gapSize ] = temp;
        j -= gapSize;
      }
    }
  };

我的归并排序:

  var mergeSort = function( list ) {
    if ( list.length <= 1 ) {
      return list;
    }

    var left = [],
        right = [],
        middle = Math.floor( list.length / 2 ),
        i;

    for( i = 0; i < middle; i++ ) {
      left.push( list[i] );
    }

    for( ; i < list.length; i++ ) {
      right.push( list[i] );
    }

    left = mergeSort( left );
    right = mergeSort( right );

    return _merge( left, right );
  };

  function _merge( left, right ) {
    var result = [];

    // Should be able to just get rid of arguments in while loop
    while( left.length || right.length ) {
      if( left.length > 0 && right.length > 0 ) {
        if( left[0] <= right[0] ) {
          result.push( left.shift() );
        } else {
          result.push( right.shift() );
        }
      } 
      else if( left.length ) {
        return result.concat( left );
      } 
      else {
        return result.concat( right );
      }
    }
  }

我的测试:

  var testSpeed = function( testSize, rounds ) {
    var testArrays = [],
        algorithms = Array.prototype.slice.call( arguments, 2 ),
        results = [],
        i, j;

    for( i = 0; i < rounds; i++ ) {
      testArrays[i] = [];
      for( j = 0; j < testSize; j++ ) {
        testArrays[i].push( Math.ceil( Math.random() * testSize ));
      }
    }

    for( i = 0; i < algorithms.length; i++ ) {
      for( j = 0; j < rounds; j++ ) {
        if( !results[i] ) {
          results[i] = [];
        }
        results[i].push( testAlgorithm( algorithms[i], testArrays[j] ));
      }
    }

    return results;
  };

  var testAlgorithm = function( algorithm, set ) {
    var clone = set.slice(),
        start = new Date().getTime(),
        end;

    algorithm( clone );

    end = new Date().getTime();

    return end - start;
  };

【问题讨论】:

  • 这可能更适合codereview.stackexchange.com
  • Shell 排序在您的间隙序列最坏的情况下是二次方的,那么您为什么认为它应该比归并排序慢?
  • 虽然我根本没有彻底检查你的代码(而且 codereview 可能是要求进行代码审查的更好地方),但我相信你使用的间隙序列不是很好;与其他间隙序列不同,它的最坏情况时间复杂度为 O(N^2)。
  • @NiklasB.:这取决于您使用的间隔序列。有关复杂性结果的调查,请参阅 Sedgewick 1996 (citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.101.9061)。
  • @rici 我考虑了间隙序列,这里选择的特别差。但即使有一个好的间隙序列,你也不太可能渐近地击败归并排序

标签: javascript algorithm performance sorting shellsort


【解决方案1】:

我将您的算法放在一起,创建了一个简单地对其进行采样的函数,记录时间(使用 millis() 而不是我不理解的测试方式)并输出平均时间。对于 100 个数字的数组,Shell 排序为 0.02 毫秒。不考虑到大多数毫秒记录都使用 Shell 排序(因为它有时为 0)。我对合并排序做了同样的事情,它是 0.21 毫秒。希望这能回答它https://www.khanacademy.org/computer-programming/sort-algorithms/6199294078746624

【讨论】:

    猜你喜欢
    • 2011-06-02
    • 2022-07-21
    • 1970-01-01
    • 2021-12-09
    • 2011-07-06
    • 1970-01-01
    • 2012-09-01
    • 1970-01-01
    • 2013-07-26
    相关资源
    最近更新 更多