内置排序慢于手工排序?

时间:2015-11-07 11:07:56

标签: javascript sorting firefox chromium heapsort

我手工制作的heapsort似乎比JavaScript的内置排序例程更快,在Chromium 45.02454.101和Firefox 41.0.2中,在Intel i5上运行在Ubuntu 14.04 LTS上

由于我怀疑自己已经实施了世界级的排序程序,因此我不清楚其原因可能是什么。

为了允许再现这种现象,这里所有的代码都是:

<!doctype html>
<html>
<head>
  <title>Sorting Runtime</title>
  <meta charset="utf-8">
  <style>
  #output {
      background-color: #EEEEEE;
      padding: 1ex;
  }
  #output p {
      font-family: monospace;
      margin: 0;
  }
  </style>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
  <script>
  "use strict";


  var actualCode = function () {
     var ary;

     var dataSizes = [1000, 2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000];
     var sortingFunctions = [
        { name: "built-in sort", fn: function (ary) { ary.sort (); } },
        { name: "heapsort", fn: function (ary) { heapsort (ary); } }
     ];
     var runsPerDataSize = 10;

     sortingFunctions.forEach (function (f) {
        print (f.name);
        var s = f.fn;
        dataSizes.forEach (function (dataSize) {
           var nRun, ary;
           var masterAry = buildAry (dataSize);
           var profilingStart = new Date().getTime();
           for (nRun = 0; nRun < runsPerDataSize; ++nRun) {
              ary = masterAry.slice (); // copy
              s (ary); // sort
              if (!checkSorted(ary)) { print ("Not sorted!"); }
           }
           var profilingElapsed = new Date().getTime() - profilingStart;
           print ("Number of items: " + dataSize + " -- Time needed (in milliseconds): " + profilingElapsed / runsPerDataSize);
        })
     });


     function heapify (ary) {
        var i;
        var arylen = ary.length;
        for (i = 1; i < arylen; ++i) {
           repairUpwards (ary, i);
        }
     }

     function fillVacancy (ary, arylen) {
        var first, second;
        var i = 0;
        while (true) {
           first = (i << 1) + 1;
           second = first + 1;
           if (first >= arylen) { return i; }
           if (second >= arylen) {
              ary [i] = ary [first];
              return first;
           }
           if (ary [first] > ary [second]) {
              ary [i] = ary [first];
              i = first;
           } else {
              ary [i] = ary [second];
              i = second;
           }
        }
     }

     function repairUpwards (ary, fromIndex) {
        var parent, tmp;
        var i = fromIndex;
        while (i > 0) {
           parent = (i-1) >> 1;
           if (ary [parent] < ary [i]) {
              tmp = ary [parent]; ary [parent] = ary [i]; ary [i] = tmp;
           } else {
              return;
           }
           i = parent;
        }
     }

     function heapsort (ary) {
        var tmplast, newVacancy;

        heapify (ary);
        var arylen = ary.length;
        var nRemaining = arylen;

        while (nRemaining > 1) {
           tmplast = ary [nRemaining - 1];
           ary [nRemaining - 1] = ary [0];
           newVacancy = fillVacancy (ary, nRemaining - 1);
           ary [newVacancy] = tmplast;
           repairUpwards (ary, newVacancy);
           --nRemaining;
        } 
     }

     function checkSorted (ary) {
        var i;
        for (i = ary.length - 1; i > 0; --i) {
           if (ary [i] < ary [i-1]) { return false; }
        }
        return true;
     }

     function buildAry (dataSize) {
        var ary = [];
        var i;
        for (i = dataSize - 1; i >= 0; --i) ary.push (Math.random ());
        return ary;
     }
  };

  // user interface
  var outputDivLogger = {
    reset : function () { $('#output').empty (); },

    log : function (msg) {
        var p = $('<p />').text (msg);
        $('#output').append (p);
    }   
  };

  var print = function (msg) {
     outputDivLogger.log (msg);
  };

  var run = function () {
     outputDivLogger.reset ();
     try {
        actualCode ();
     } catch (e) {
        outputDivLogger.log (String(e));
     }
  };


  $(document).ready (function () {
      $("#btnStart").click (function () {
          run ();
      });

      outputDivLogger.log ("[No output yet.]")
  });
  </script>
</head>
<body>
    <h2>Measuring Sorting Speed</h2>
    <div class="content">
        <form>
            <p><input type="button" id="btnStart" value="Run"></p>
        </form>
    </div>
    <h3>Output</h3>
    <div class="content">
        <div id="output"></div>
    </div>
</body>
</html>

示例输出(Firefox):

built-in sort

Number of items: 1000 -- Time needed (in milliseconds): 0.8
Number of items: 2000 -- Time needed (in milliseconds): 1.5
Number of items: 4000 -- Time needed (in milliseconds): 2.8
Number of items: 8000 -- Time needed (in milliseconds): 4.9
Number of items: 16000 -- Time needed (in milliseconds): 8.5
Number of items: 32000 -- Time needed (in milliseconds): 14.9
Number of items: 64000 -- Time needed (in milliseconds): 31.3
Number of items: 128000 -- Time needed (in milliseconds): 68.9
Number of items: 256000 -- Time needed (in milliseconds): 168.7

heapsort

Number of items: 1000 -- Time needed (in milliseconds): 0.2
Number of items: 2000 -- Time needed (in milliseconds): 0.2
Number of items: 4000 -- Time needed (in milliseconds): 0.4
Number of items: 8000 -- Time needed (in milliseconds): 0.8
Number of items: 16000 -- Time needed (in milliseconds): 1.6
Number of items: 32000 -- Time needed (in milliseconds): 3.5
Number of items: 64000 -- Time needed (in milliseconds): 7.6
Number of items: 128000 -- Time needed (in milliseconds): 16.5
Number of items: 256000 -- Time needed (in milliseconds): 34.9

编辑:在下面的一条评论中,有人指出

ary.sort ();

应替换为

ary.sort (function (a, b) { return a - b; });

这确实改善了内置排序的结果,但它仍然较慢:

火狐

built-in sort

Number of items: 1000 -- Time needed (in milliseconds): 0.3
Number of items: 2000 -- Time needed (in milliseconds): 0.4
Number of items: 4000 -- Time needed (in milliseconds): 0.8
Number of items: 8000 -- Time needed (in milliseconds): 1.8
Number of items: 16000 -- Time needed (in milliseconds): 3.5
Number of items: 32000 -- Time needed (in milliseconds): 6.5
Number of items: 64000 -- Time needed (in milliseconds): 10.9
Number of items: 128000 -- Time needed (in milliseconds): 21.8
Number of items: 256000 -- Time needed (in milliseconds): 49.9

heapsort

Number of items: 1000 -- Time needed (in milliseconds): 0.3
Number of items: 2000 -- Time needed (in milliseconds): 0.2
Number of items: 4000 -- Time needed (in milliseconds): 0.3
Number of items: 8000 -- Time needed (in milliseconds): 0.7
Number of items: 16000 -- Time needed (in milliseconds): 1.6
Number of items: 32000 -- Time needed (in milliseconds): 3.4
Number of items: 64000 -- Time needed (in milliseconds): 7.3
Number of items: 128000 -- Time needed (in milliseconds): 15.7
Number of items: 256000 -- Time needed (in milliseconds): 34.4

铬:

built-in sort
Number of items: 1000 -- Time needed (in milliseconds): 2.7
Number of items: 2000 -- Time needed (in milliseconds): 1.6
Number of items: 4000 -- Time needed (in milliseconds): 1.6
Number of items: 8000 -- Time needed (in milliseconds): 3.3
Number of items: 16000 -- Time needed (in milliseconds): 6.1
Number of items: 32000 -- Time needed (in milliseconds): 10.7
Number of items: 64000 -- Time needed (in milliseconds): 24.6
Number of items: 128000 -- Time needed (in milliseconds): 53.8
Number of items: 256000 -- Time needed (in milliseconds): 158

heapsort
Number of items: 1000 -- Time needed (in milliseconds): 0.3
Number of items: 2000 -- Time needed (in milliseconds): 0.1
Number of items: 4000 -- Time needed (in milliseconds): 0.4
Number of items: 8000 -- Time needed (in milliseconds): 0.8
Number of items: 16000 -- Time needed (in milliseconds): 2
Number of items: 32000 -- Time needed (in milliseconds): 4.1
Number of items: 64000 -- Time needed (in milliseconds): 8.9
Number of items: 128000 -- Time needed (in milliseconds): 19.6
Number of items: 256000 -- Time needed (in milliseconds): 62.4

1 个答案:

答案 0 :(得分:2)

免责声明:这不是一个完整的答案,但我认为值得发布。

我发现的一个问题是你认为要复制的元素便宜。如果我用String(Math.random())替换随机调用,我会在Firefox中获得这些结果:

built-in sort
Number of items: 1000 -- Time needed (in milliseconds): 0.6
Number of items: 2000 -- Time needed (in milliseconds): 1.2
Number of items: 4000 -- Time needed (in milliseconds): 2.5
Number of items: 8000 -- Time needed (in milliseconds): 5.6
Number of items: 16000 -- Time needed (in milliseconds): 12.5
Number of items: 32000 -- Time needed (in milliseconds): 31.4
Number of items: 64000 -- Time needed (in milliseconds): 77.8
Number of items: 128000 -- Time needed (in milliseconds): 171.9
Number of items: 256000 -- Time needed (in milliseconds): 384.9
heapsort
Number of items: 1000 -- Time needed (in milliseconds): 1
Number of items: 2000 -- Time needed (in milliseconds): 1.6
Number of items: 4000 -- Time needed (in milliseconds): 3.4
Number of items: 8000 -- Time needed (in milliseconds): 7.3
Number of items: 16000 -- Time needed (in milliseconds): 16.2
Number of items: 32000 -- Time needed (in milliseconds): 42
Number of items: 64000 -- Time needed (in milliseconds): 116.4
Number of items: 128000 -- Time needed (in milliseconds): 465.7
Number of items: 256000 -- Time needed (in milliseconds): 757.6

你的heapsort在Chrome中仍然更快。我想用字符串做得更好(引用计数?必须检查)。

值得注意的是,即使情况如此,对阵列进行线性扫描以确定使用哪种算法也是有意义的。