【问题标题】:Fast stable sorting algorithm implementation in javascriptjavascript中的快速稳定排序算法实现
【发布时间】:2010-11-28 11:53:29
【问题描述】:

我希望对大约 200-300 个对象的数组进行排序,按特定键和给定顺序 (asc/desc) 进行排序。结果的顺序必须一致且稳定。

什么是最好的算法,你能提供一个在 javascript 中实现的例子吗?

谢谢!

【问题讨论】:

  • 由于至少 Chrome 的数组排序似乎不稳定,所以依赖内置数组排序不是你的选择。
  • 总结一下:由于现代浏览器之间的 Array.sort 稳定性不一致(主要是 chrome 在发表此评论时未实现稳定排序),我使用了手动合并排序。感谢大家的帮助!
  • 我们所说的“稳定”排序是什么意思?
  • @mowwwalker 稳定排序是一种排序,其中具有相同排序值的所有项目都以与原始集合中相同的顺序保留。 en.wikipedia.org/wiki/Sorting_algorithm#Stability
  • 除 Internet Explorer 外,Array.sort 在标准规定的 November 2018 之后的所有浏览器中都是稳定的。 Browser compatibility

标签: javascript algorithm sorting


【解决方案1】:

可以从不稳定的排序函数中获得稳定的排序。

在排序之前,你会得到所有元素的位置。 在您的排序条件下,如果两个元素相等,则按位置排序。

多田!你有一个稳定的排序。

如果您想了解更多关于这种技术以及如何实现它的信息,我已经在我的博客上写了一篇关于它的文章:http://blog.vjeux.com/2010/javascript/javascript-sorting-table.html

【讨论】:

  • 能否请您在此处提供答案,而不是发布和链接到您的博客!谢谢
  • 欢迎提供解决方案链接,但请确保您的答案在没有它的情况下有用:add context around the link 这样您的其他用户就会知道它是什么以及为什么会出现,然后引用最相关的您链接到的页面的一部分,以防目标页面不可用。 Answers that are little more than a link may be deleted.
  • @Vjeux 因为这越来越流行,您介意将相关代码粘贴到此答案中吗?这会有很大帮助!谢谢!
  • Array.sort 在标准规定的November 2018 之后的所有浏览器中都是稳定的。 Browser compatibility
【解决方案2】:

由于您正在寻找稳定的东西,因此应该使用归并排序。

http://www.stoimen.com/blog/2010/07/02/friday-algorithms-javascript-merge-sort/

代码可以在上面的网站找到:

function mergeSort(arr)
{
    if (arr.length < 2)
        return arr;

    var middle = parseInt(arr.length / 2);
    var left   = arr.slice(0, middle);
    var right  = arr.slice(middle, arr.length);

    return merge(mergeSort(left), mergeSort(right));
}

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

    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }

    while (left.length)
        result.push(left.shift());

    while (right.length)
        result.push(right.shift());

    return result;
}

编辑:

根据这个post,看起来 Array.Sort 在某些实现中使用了合并排序。

【讨论】:

  • ++ 合并排序是我的最爱。它简单稳定,没有最坏的情况。
  • 网站链接失效:(
  • 为示例找到了一个新网站。
  • 注意:Array#shift 可能在 O(n) 时间内工作,因此您的 merge 在 O(n*n) 时间内工作。
【解决方案3】:

使用 ES2017 功能(如箭头函数和解构)的相同事物的较短版本:

功能

var stableSort = (arr, compare) => arr
  .map((item, index) => ({item, index}))
  .sort((a, b) => compare(a.item, b.item) || a.index - b.index)
  .map(({item}) => item)

它接受输入数组和比较函数:

stableSort([5,6,3,2,1], (a, b) => a - b)

它还返回新数组,而不是像内置的 Array.sort() 函数那样进行就地排序。

测试

如果我们取以下input数组,最初按weight排序:

// sorted by weight
var input = [
  { height: 100, weight: 80 },
  { height: 90, weight: 90 },
  { height: 70, weight: 95 },
  { height: 100, weight: 100 },
  { height: 80, weight: 110 },
  { height: 110, weight: 115 },
  { height: 100, weight: 120 },
  { height: 70, weight: 125 },
  { height: 70, weight: 130 },
  { height: 100, weight: 135 },
  { height: 75, weight: 140 },
  { height: 70, weight: 140 }
]

然后使用stableSortheight排序:

stableSort(input, (a, b) => a.height - b.height)

结果:

// Items with the same height are still sorted by weight 
// which means they preserved their relative order.
var stable = [
  { height: 70, weight: 95 },
  { height: 70, weight: 125 },
  { height: 70, weight: 130 },
  { height: 70, weight: 140 },
  { height: 75, weight: 140 },
  { height: 80, weight: 110 },
  { height: 90, weight: 90 },
  { height: 100, weight: 80 },
  { height: 100, weight: 100 },
  { height: 100, weight: 120 },
  { height: 100, weight: 135 },
  { height: 110, weight: 115 }
]

但是,使用内置的 Array.sort()(在 Chrome/NodeJS 中)对相同的 input 数组进行排序:

input.sort((a, b) => a.height - b.height)

返回:

var unstable = [
  { height: 70, weight: 140 },
  { height: 70, weight: 95 },
  { height: 70, weight: 125 },
  { height: 70, weight: 130 },
  { height: 75, weight: 140 },
  { height: 80, weight: 110 },
  { height: 90, weight: 90 },
  { height: 100, weight: 100 },
  { height: 100, weight: 80 },
  { height: 100, weight: 135 },
  { height: 100, weight: 120 },
  { height: 110, weight: 115 }
]

资源

更新

Array.prototype.sort 现已稳定在 V8 v7.0 / Chrome 70 中!

以前,V8 对超过 10 个元素的数组使用不稳定的快速排序。现在,我们使用稳定的 TimSort 算法。

source

【讨论】:

  • stableSort 函数是一个非常棒的解决方案!
【解决方案4】:

我知道这个问题已经回答了一段时间了,但是我的剪贴板中恰好有一个很好的稳定的 Array 和 jQuery 合并排序实现,所以我会分享它,希望将来的一些搜索者可能会找到它有用。

它允许您指定自己的比较函数,就像普通的Array.sort 实现一样。

实施

// Add stable merge sort to Array and jQuery prototypes
// Note: We wrap it in a closure so it doesn't pollute the global
//       namespace, but we don't put it in $(document).ready, since it's
//       not dependent on the DOM
(function() {

  // expose to Array and jQuery
  Array.prototype.mergeSort = jQuery.fn.mergeSort = mergeSort;

  function mergeSort(compare) {

    var length = this.length,
        middle = Math.floor(length / 2);

    if (!compare) {
      compare = function(left, right) {
        if (left < right)
          return -1;
        if (left == right)
          return 0;
        else
          return 1;
      };
    }

    if (length < 2)
      return this;

    return merge(
      this.slice(0, middle).mergeSort(compare),
      this.slice(middle, length).mergeSort(compare),
      compare
    );
  }

  function merge(left, right, compare) {

    var result = [];

    while (left.length > 0 || right.length > 0) {
      if (left.length > 0 && right.length > 0) {
        if (compare(left[0], right[0]) <= 0) {
          result.push(left[0]);
          left = left.slice(1);
        }
        else {
          result.push(right[0]);
          right = right.slice(1);
        }
      }
      else if (left.length > 0) {
        result.push(left[0]);
        left = left.slice(1);
      }
      else if (right.length > 0) {
        result.push(right[0]);
        right = right.slice(1);
      }
    }
    return result;
  }
})();

示例用法

var sorted = [
  'Finger',
  'Sandwich',
  'sandwich',
  '5 pork rinds',
  'a guy named Steve',
  'some noodles',
  'mops and brooms',
  'Potato Chip Brand® chips'
].mergeSort(function(left, right) {
  lval = left.toLowerCase();
  rval = right.toLowerCase();

  console.log(lval, rval);
  if (lval < rval)
    return -1;
  else if (lval == rval)
    return 0;
  else
    return 1;
});

sorted == ["5 pork rinds", "a guy named Steve", "Finger", "mops and brooms", "Potato Chip Brand® chips", "Sandwich", "sandwich", "some noodles"];

【讨论】:

  • 请注意,这与原生排序不一致,后者在 in 位置有效,这意味着不能直接放入。
  • 可能稳定,但这种方法比原生 array.sort20 倍,请参阅此处对字符串和整数的测试 -> jsfiddle.net/QC64j
  • 当然它比原生排序慢——它不是原生的。这不可能。它也确实没有进行就地排序。这也是不可能的(最好的情况是您创建一个副本然后覆盖原件)。此外,尽管 JavaScript 有自己的原生排序行为,但返回排序后的副本更像是 JavaScript-y。该函数也称为mergeSort 而不是sort,因此它不打算作为替代品。有时你只需要一个稳定的归并排序,例如按列对表格进行排序时。
  • 错了,Node的Native排序是用javascript写的。用 javascript 编程的算法完全有可能超过本机排序。我完全在 javascript(一种自适应合并排序)中构建了一个排序算法,即 Kremes/creams/Kreams 节点中的本机快速排序。这条评论的重点是表明原生在 javascript 的情况下无关紧要,因为排序算法是用 javascript 编写的,而不是用 c++ 等高级语言编写的。证明在这里:github.com/nodejs/node/blob/master/deps/v8/src/js/array.js
  • 对于任何想要一个比此实施快得多的就地、插入式解决方案的人,check out my answer
【解决方案5】:

您可以使用以下函数来执行稳定排序,而不管本机实现如何,基于作出的断言in this answer

请注意as of ECMAScript 2019, the specification requires that the builtin sort() method perform a stable sort。考虑到这一点,如果您需要支持不符合规范的旧浏览器,那么像下面这样的显式稳定排序功能仍然是相关的。

// ECMAScript 5 implementation
function stableSort(array, compareFunction) {
  'use strict';

  var length = array.length;
  var indices = new Uint32Array(length);
  var i;
  var slice;

  // reference values by indices
  for (i = 0; i < length; ++i) {
    indices[i] = i;
  }

  // sort with fallback based on indices
  indices.sort(function stableCompareFunction(compareFunction, a, b) {
    var order = Number(compareFunction(this[a], this[b]));
    return order || a - b;
  }.bind(array, compareFunction));

  slice = array.slice();

  // re-order original array to stable sorted values
  for (i = 0; i < length; ++i) {
    array[i] = slice[indices[i]];
  }

  return array;
}

// usage
const array = Array(500000).fill().map(() => Number(Math.random().toFixed(4)));

const alwaysEqual = () => 0;
const isUnmoved = (value, index) => value === array[index];

// not guaranteed to be stable before ES2019
console.log(
  'sort() stable?',
  array.slice().sort(alwaysEqual).every(isUnmoved)
);
// guaranteed to be stable
console.log(
  'stableSort() stable?',
  stableSort(array.slice(), alwaysEqual).every(isUnmoved)
);

// performance using realistic scenario with unsorted big data
function time(arraySlice, algorithm, compare) {
  var start;
  var stop;

  start = performance.now();
  algorithm(arraySlice, compare);
  stop = performance.now();

  return stop - start;
}

const ascending = (a, b) => a - b;

const msSort = time(array.slice(), (array, compare) => array.sort(compare), ascending);
const msStableSort = time(array.slice(), (array, compare) => stableSort(array, compare), ascending);

console.log('sort()', msSort.toFixed(3), 'ms');
console.log('stableSort()', msStableSort.toFixed(3), 'ms');
console.log('sort() / stableSort()', (100 * msSort / msStableSort).toFixed(3) + '%');

运行上面实现的性能测试,stableSort() 在 Google Chrome 和 Microsoft Edge 88 版上的运行速度似乎是sort() 的 72%。

stableSort() 内的内联函数上使用.bind(),通过避免每次调用中不需要的范围引用来显着提高相对性能。

实际上,这不再产生影响,因为现代引擎现在会自动执行此优化,但无论如何仍保留在实现中,以便继续提高未附带此优化的旧浏览器的性能。

【讨论】:

    【解决方案6】:

    以下对提供的数组进行排序,通过应用提供的比较函数,当比较函数返回0时返回原始索引比较:

    function stableSort(arr, compare) {
        var original = arr.slice(0);
    
        arr.sort(function(a, b){
            var result = compare(a, b);
            return result === 0 ? original.indexOf(a) - original.indexOf(b) : result;
        });
    
        return arr;
    }
    

    以下示例按姓氏对名称数组进行排序,保留相同姓氏的顺序:

    var names = [
    	{ surname: "Williams", firstname: "Mary" },
    	{ surname: "Doe", firstname: "Mary" }, 
    	{ surname: "Johnson", firstname: "Alan" }, 
    	{ surname: "Doe", firstname: "John" }, 
    	{ surname: "White", firstname: "John" }, 
    	{ surname: "Doe", firstname: "Sam" }
    ]
    
    function stableSort(arr, compare) {
        var original = arr.slice(0);
    
        arr.sort(function(a, b){
            var result = compare(a, b);
            return result === 0 ? original.indexOf(a) - original.indexOf(b) : result;
        });
    	
        return arr;
    }
    
    stableSort(names, function(a, b) { 
    	return a.surname > b.surname ? 1 : a.surname < b.surname ? -1 : 0;
    })
    
    names.forEach(function(name) {
    	console.log(name.surname + ', ' + name.firstname);
    });

    【讨论】:

    • 对于原始类型或数组中的重复元素不稳定。 jQuery.expando.split( "" ).sort( ( a, b ) =&gt; 0 ).join( "" ) === jQuery.expando
    【解决方案7】:

    这是一个稳定的实现。它通过使用本机排序工作,但在元素比较相等的情况下,您使用原始索引位置打破平局。

    function stableSort(arr, cmpFunc) {
        //wrap the arr elements in wrapper objects, so we can associate them with their origional starting index position
        var arrOfWrapper = arr.map(function(elem, idx){
            return {elem: elem, idx: idx};
        });
    
        //sort the wrappers, breaking sorting ties by using their elements orig index position
        arrOfWrapper.sort(function(wrapperA, wrapperB){
            var cmpDiff = cmpFunc(wrapperA.elem, wrapperB.elem);
            return cmpDiff === 0 
                 ? wrapperA.idx - wrapperB.idx
                 : cmpDiff;
        });
    
        //unwrap and return the elements
        return arrOfWrapper.map(function(wrapper){
            return wrapper.elem;
        });
    }
    

    一个不彻底的测试

    var res = stableSort([{a:1, b:4}, {a:1, b:5}], function(a, b){
        return a.a - b.a;
    });
    console.log(res);
    

    another answer 提到了这一点,但没有发布代码。

    但是,根据我的benchmark,它并不快。我修改了merge sort impl 以接受自定义比较器功能,而且速度要快得多。

    【讨论】:

    • 您的基准测试是否正确?似乎,您的“stableSort”不会修改输入数组,其他排序 - 做,并且由于您在“设置”期间没有重新创建“arr”,其他排序对已经排序的数组进行排序....
    • @4esn0k 你读错了吗?我说我的 stableSort 函数不快。
    • @gota,啊,对不起
    【解决方案8】:

    您也可以使用 Timsort。这是一个非常复杂的算法(400 多行,因此这里没有源代码),所以请参阅 Wikipedia's description 或使用现有的 JavaScript 实现之一:

    GPL 3 implementation。打包为 Array.prototype.timsort。似乎是对 Java 代码的精确重写。

    Public domain implementation作为教程,示例代码只展示了它与整数的使用。

    Timsort 是合并排序和随机排序的高度优化混合,是 Python 和 Java (1.7+) 中的默认排序算法。这是一个复杂的算法,因为它对许多特殊情况使用不同的算法。但因此,它在各种情况下都非常快。

    【讨论】:

      【解决方案9】:

      一个简单的来自http://www.stoimen.com/blog/2010/07/02/friday-algorithms-javascript-merge-sort/的mergeSort

      var a = [34, 203, 3, 746, 200, 984, 198, 764, 9];
      
      function mergeSort(arr)
      {
          if (arr.length < 2)
               return arr;
      
          var middle = parseInt(arr.length / 2);
          var left   = arr.slice(0, middle);
          var right  = arr.slice(middle, arr.length);
      
          return merge(mergeSort(left), mergeSort(right));
      }
      
      function merge(left, right)
      {
           var result = [];
      
          while (left.length && right.length) {
               if (left[0] <= right[0]) {
                   result.push(left.shift());
               } else {
                  result.push(right.shift());
               }
          }
      
          while (left.length)
              result.push(left.shift());
      
          while (right.length)
              result.push(right.shift());
      
          return result;
      }
      
      console.log(mergeSort(a));
      

      【讨论】:

        【解决方案10】:

        我必须按任意列对多维数组进行排序,然后再按另一个列。我用这个函数来排序:

        function sortMDArrayByColumn(ary, sortColumn){
        
            //Adds a sequential number to each row of the array
            //This is the part that adds stability to the sort
            for(var x=0; x<ary.length; x++){ary[x].index = x;}
        
            ary.sort(function(a,b){
                if(a[sortColumn]>b[sortColumn]){return 1;}
                if(a[sortColumn]<b[sortColumn]){return -1;}
                if(a.index>b.index){
                    return 1;
                }
                return -1;
            });
        }
        

        请注意,ary.sort 永远不会返回零,这是“排序”函数的某些实现做出可能不正确的决定的地方。

        这也太快了。

        【讨论】:

          【解决方案11】:

          这里介绍了如何使用 MERGE SORT 使用原型方法扩展 JS 默认 Array 对象。此方法允许对特定键(第一个参数)和给定顺序('asc'/'desc' 作为第二个参数)进行排序

          Array.prototype.mergeSort = function(sortKey, direction){
            var unsortedArray = this;
            if(unsortedArray.length < 2) return unsortedArray;
          
            var middle = Math.floor(unsortedArray.length/2);
            var leftSubArray = unsortedArray.slice(0,middle).mergeSort(sortKey, direction);
            var rightSubArray = unsortedArray.slice(middle).mergeSort(sortKey, direction);
          
            var sortedArray = merge(leftSubArray, rightSubArray);
            return sortedArray;
          
            function merge(left, right) {
              var combined = [];
              while(left.length>0 && right.length>0){
                var leftValue = (sortKey ? left[0][sortKey] : left[0]);
                var rightValue = (sortKey ? right[0][sortKey] : right[0]);
                combined.push((direction === 'desc' ? leftValue > rightValue : leftValue < rightValue) ? left.shift() : right.shift())
              }
              return combined.concat(left.length ? left : right)
            }
          }

          你可以自己测试一下,把上面的 sn-p 放到你的浏览器控制台中,然后尝试:

          var x = [2,76,23,545,67,-9,12];
          x.mergeSort(); //[-9, 2, 12, 23, 67, 76, 545]
          x.mergeSort(undefined, 'desc'); //[545, 76, 67, 23, 12, 2, -9]
          

          或根据对象数组中的特定字段排序:

          var y = [
            {startTime: 100, value: 'cat'},
            {startTime: 5, value: 'dog'},
            {startTime: 23, value: 'fish'},
            {startTime: 288, value: 'pikachu'}
          ]
          y.mergeSort('startTime');
          y.mergeSort('startTime', 'desc');
          

          【讨论】:

            【解决方案12】:

            所以我需要为我的 React+Redux 应用程序提供一个稳定的排序,而 Vjeux 在这里的回答帮助了我。但是,我的(通用)解决方案似乎与到目前为止我在这里看到的其他解决方案不同,所以我分享它以防其他人有匹配的用例:

            • 我真的只想拥有类似于sort() API 的东西,我可以在其中传递一个比较器函数。
            • 有时我可以就地排序,有时我的数据是不可变的(因为 Redux),我需要一个排序的副本。所以我需要为每个用例提供一个稳定的排序功能。
            • ES2015.

            我的解决方案是创建一个indices 的类型化数组,然后使用比较函数根据待排序数组对这些索引 进行排序。然后我们可以使用已排序的indices 对原始数组进行排序或在单次传递中创建已排序的副本。如果这令人困惑,请这样想:通常会在其中传递比较函数,例如:

            (a, b) => { 
              /* some way to compare a and b, returning -1, 0, or 1 */ 
            };
            

            您现在改为使用:

            (i, j) => { 
              let a = arrayToBeSorted[i], b = arrayToBeSorted[j]; 
              /* some way to compare a and b, returning -1 or 1 */
              return i - j; // fallback when a == b
            }
            

            速度不错;基本上就是内置的排序算法,加上最后的两次线性遍历,以及一层额外的指针间接开销。

            很高兴收到有关此方法的反馈。这是我对它的完整实现:​​

            /**
             * - `array`: array to be sorted
             * - `comparator`: closure that expects indices `i` and `j`, and then
             *   compares `array[i]` to `array[j]` in some way. To force stability,
             *   end with `i - j` as the last "comparison".
             * 
             * Example:
             * ```
             *  let array = [{n: 1, s: "b"}, {n: 1, s: "a"}, {n:0, s: "a"}];
             *  const comparator = (i, j) => {
             *    const ni = array[i].n, nj = array[j].n;
             *    return ni < nj ? -1 :
             *      ni > nj ? 1 :
             *        i - j;
             *  };
             *  stableSortInPlace(array, comparator);
             *  // ==> [{n:0, s: "a"}, {n:1, s: "b"}, {n:1, s: "a"}]
             * ```
             */
            function stableSortInPlace(array, comparator) {
              return sortFromIndices(array, findIndices(array, comparator));
            }
            
            function stableSortedCopy(array, comparator){
              let indices = findIndices(array, comparator);
              let sortedArray = [];
              for (let i = 0; i < array.length; i++){
                sortedArray.push(array[indices[i]]);
              }
              return sortedArray;
            }
            
            function findIndices(array, comparator){
              // Assumes we don't have to worry about sorting more than 
              // 4 billion elements; if you know the upper bounds of your
              // input you could replace it with a smaller typed array
              let indices = new Uint32Array(array.length);
              for (let i = 0; i < indices.length; i++) {
                indices[i] = i;
              }
              // after sorting, `indices[i]` gives the index from where
              // `array[i]` should take the value from, so to sort
              // move the value at at `array[indices[i]]` to `array[i]`
              return indices.sort(comparator);
            }
            
            // If I'm not mistaken this is O(2n) - each value is moved
            // only once (not counting the vacancy temporaries), and 
            // we also walk through the whole array once more to check
            // for each cycle.
            function sortFromIndices(array, indices) {
              // there might be multiple cycles, so we must
              // walk through the whole array to check.
              for (let k = 0; k < array.length; k++) {
                // advance until we find a value in
                // the "wrong" position
                if (k !== indices[k]) {
                  // create vacancy to use "half-swaps" trick,
                  // props to Andrei Alexandrescu
                  let v0 = array[k];
                  let i = k;
                  let j = indices[k];
                  while (j !== k) {
                    // half-swap next value
                    array[i] = array[j];
                    // array[i] now contains the value it should have,
                    // so we update indices[i] to reflect this
                    indices[i] = i;
                    // go to next index
                    i = j;
                    j = indices[j];
                  }
                  // put original array[k] back in
                  // and update indices
                  array[i] = v0;
                  indices[i] = i;
                }
              }
              return array;
            }
            

            【讨论】:

              【解决方案13】:

              我知道这已经得到了很多回答。我只是想为任何登陆这里寻找的人发布一个快速的 TS 实现。

              export function stableSort<T>( array: T[], compareFn: ( a: T, b: T ) => number ): T[] {
                  const indices = array.map( ( x: T, i: number ) => ( { element: x, index: i } ) );
              
                  return indices.sort( ( a, b ) => {
                      const order = compareFn( a.element, b.element );
                      return order === 0 ? a.index - b.index : order;
                  } ).map( x => x.element );
              }
              

              该方法不再像本机排序那样就地运行。我还想指出,它不是最有效的。它添加了两个 O(n) 阶的循环。虽然排序本身很可能是 O(n log(n)) 所以它比那个少。

              提到的一些解决方案性能更高,认为这可能是更少的代码,也使用内部Array.prototype.sort

              (对于 Javascript 解决方案,只需删除所有类型)

              【讨论】:

                【解决方案14】:

                根据v8 dev blogcaniuse.com Array.sort 已经按照现代浏览器的规范要求稳定,因此您无需推出自己的解决方案。 我能看到的唯一例外是 Edge,它应该很快就会转向 Chromium 并支持它。

                【讨论】:

                  【解决方案15】:

                  function sort(data){
                      var result=[];
                      var array = data;
                      const array2=data;
                      const len=array2.length;
                      for(var i=0;i<=len-1;i++){
                      var min = Math.min.apply(Math,array)
                      result.push(min);
                      var index=array.indexOf(min)
                      array.splice(index,1);
                      }
                      return result;
                  }   
                  sort([9,8,5,7,9,3,9,243,4,5,6,3,4,2,4,7,4,9,55,66,33,66]);

                  【讨论】:

                    【解决方案16】:

                    计数排序比归并排序更快(它在 O(n) 时间内执行)并且它旨在用于整数。

                    Math.counting_sort = function (m) {
                        var i
                        var j
                        var k
                        var step
                        var start
                        var Output
                        var hash
                        k = m.length
                        Output = new Array ()
                        hash = new Array ()
                        // start at lowest possible value of m
                        start = 0
                        step = 1
                        // hash all values
                        i = 0
                        while ( i < k ) {
                            var _m = m[i]
                            hash [_m] = _m
                            i = i + 1
                        }
                        i = 0
                        j = start
                        // find all elements within x
                        while ( i < k ) {
                            while ( j != hash[j] ) {
                                j = j + step
                            }
                            Output [i] = j
                            i = i + 1
                            j = j + step
                        }
                        return Output
                    }
                    

                    例子:

                    var uArray = new Array ()<br/>
                    var sArray = new Array ()<br/><br/>
                    uArray = [ 10,1,9,2,8,3,7,4,6,5 ]<br/>
                    sArray = Math.counting_sort ( uArray ) // returns a sorted array
                    

                    【讨论】:

                    • 有几点要说: 1.计数排序只在密集的数字空间中工作得很好。 (尝试对数组进行排序 [1, 2e9, 1e9]) 2. 不要将 for 循环写成 while 循环。 3. 不要随意往 Math 命名空间中添加东西。 4. 你不妨考虑用分号交朋友。
                    • 另外,如果数组有重复值,它将永远运行。例如,array [3, 1, 3] 散列为 [undefined, 1, undefined, 3]。我们得到两个未定义的值,而算法预计会有三个。
                    猜你喜欢
                    • 2022-06-21
                    • 2015-06-02
                    • 2016-06-23
                    • 2023-03-30
                    • 1970-01-01
                    • 2015-12-16
                    • 2023-01-31
                    • 2018-09-20
                    • 2019-05-01
                    相关资源
                    最近更新 更多