Швидка стабільна реалізація алгоритму сортування в JavaScript


104

Я хочу сортувати масив з приблизно 200-300 об'єктів, сортувати за певним ключем та заданим порядком (asc / desc). Порядок результатів повинен бути послідовним та стабільним.

Який найкращий алгоритм використовувати, і чи можете ви навести приклад його реалізації у javascript?

Дякую!


6
Оскільки принаймні сортування масиву Chrome не здається стабільним, покладатися на вбудований сортування масиву не є для вас варіантом.
Носредна

Підводячи підсумок: я перейшов з ручним прокатом сортування злиття через невідповідності стабільності Array.sort між сучасними браузерами (в основному хром не застосовував стабільний сорт під час цього коментаря). Дякуємо всім за допомогу!
Вільям Касарін

Що ми маємо на увазі під "стабільним" сортом?
mowwwalker

2
@mowwwalker Stable sort - це вид, у якому всі елементи з тим же значенням сортування залишаються в тому ж порядку, що і в оригінальній колекції. en.wikipedia.org/wiki/Sorting_algorithm#Stability
Kornelije Petak

Щоб відповісти "який найкращий алгоритм використовувати", ми повинні знати, чи є якась основна структура ваших даних. Багато відповідей нижче просто говорять про використання сортування злиття або швидкого сортування, насправді це залежить від даних. Це не проста проблема, щоб просто відповісти, я б не сказав. Google декілька алгоритмів сортування та прочитав про них, щоб побачити, що я маю на увазі. TimSort та Radix Sort - це два хороших приклади, про які я рекомендую читати.
буде

Відповіді:


114

Можна отримати стабільне сортування з нестабільної функції сортування.

Перед сортуванням ви отримуєте положення всіх елементів. У вашому стані сортування, якщо обидва елементи рівні, ви сортуєте за позицією.

Тада! У вас стабільний сорт.

Я написав статтю про це у своєму блозі, якщо ви хочете дізнатися більше про цю техніку та як її реалізувати: http://blog.vjeux.com/2010/javascript/javascript-sorting-table.html


32
Чи можете ви надати відповідь тут замість публікації та посилання на свій блог! Спасибі
Мохаммед Кермані

4
Посилання на рішення вітається, але будь ласка, переконайтеся, що ваша відповідь корисна без неї: додайте контекст навколо посилання, щоб ваші колеги користувачі мали уявлення про те, що це таке і чому воно є, а потім наведіть найвідповіднішу частину сторінки, яку ви ' повторне посилання на випадок, якщо цільова сторінка недоступна. Відповіді, які є трохи більше ніж посилання, можуть бути видалені.
Самуель Liew

@Vjeux, оскільки це стає популярним, чи не проти вставити відповідний код у цю відповідь? Це б дуже допомогло! Дякую!
Вільям Касарін

34

Оскільки ви шукаєте щось стабільне, сортування злиття має зробити.

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;
}

Редагувати:

Відповідно до цієї публікації , схоже на Array.Sort в деяких реалізаціях використовує сортування злиття.


++ Сортування сортів - це мій улюблений. Це просто і стабільно, без гірших випадків.
Майк Данлаве

Посилання на веб-сайт вниз :(
ahitt6345

знайшов новий веб-сайт для прикладу.
kemiller2002

7
Примітка: Array#shiftможе спрацювати в O (n) час, і так mergeв O (n * n).
4esn0k

22

Дещо коротша версія тієї ж речі, що використовує функції 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 }
]

Потім сортуйте за heightдопомогою stableSort:

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 }
]

Однак сортування того ж inputмасиву за допомогою вбудованого Array.sort()(у Chrome / NodeJS):

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 використовував нестабільний QuickSort для масивів з більш ніж 10 елементами. Тепер ми використовуємо стабільний алгоритм TimSort.

джерело


1
stableSortФункція дійсно відмінне рішення!
lhermann

16

Я знаю, що на це питання вже давно відповідали, але у мене буває хороша стабільна реалізація сортування злиття для 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"];

4
Зауважте, що це суперечить рідному роду, який працює на місці, це означає, що цього просто не можна скинути.
Ерік,

3
Можливо, стабільний, але цей метод приблизно в 20 разів повільніше, ніж рідний array.sort, дивіться тут тест як для рядків, так і для цілих чисел -> jsfiddle.net/QC64j
davidkonrad

2
Звичайно, це повільніше, ніж рідне - це не рідне. Це неможливо. Це також правда, що це не робить на місці сортування. Це теж неможливо (у кращому випадку ви створюєте копію, а потім перезаписуєте оригінал). Крім того, повернення відсортованої копії - це більше JavaScript-y, незважаючи на власну поведінку сортування JavaScript. Функція також називається, mergeSortа не sort, тому вона не задумується як падіння заміни. Іноді потрібно просто стабільне сортування злиття, наприклад, при сортуванні таблиць за стовпцями.
Джастін Форс

1
Неправильно, рідний сорт Node написаний на JavaScript. Це цілком можливо для алгоритму, запрограмованого в javascript, щоб випереджати натив. Я побудував алгоритм сортування повністю в javascript (тип адаптивного сортування злиття), що Kremes / creams / Kreams Народний швидкохідний вузол у вузлі. Сенс цього коментаря полягає в тому, щоб показати, що рідне значення не має у випадку javascript, оскільки алгоритм сортування написаний на JavaScript, а не на деяких вищих мовах, таких як c ++. Доказ є тут: github.com/nodejs/node/blob/master/deps/v8/src/js/array.js
ahitt6345,

2
Для всіх, хто хоче рішення, що працює на місці, яке набагато швидше, ніж ця реалізація, ознайомтеся з моєю відповіддю .
Патрік Робертс

10

Ви можете використовувати наступний поліфайл, щоб реалізувати стабільний сорт незалежно від нативної реалізації, виходячи із твердження, висловленого у цій відповіді :

// ECMAScript 5 polyfill
Object.defineProperty(Array.prototype, 'stableSort', {
  configurable: true,
  writable: true,
  value: function stableSort (compareFunction) {
    'use strict'

    var length = this.length
    var entries = Array(length)
    var index

    // wrap values with initial indices
    for (index = 0; index < length; index++) {
      entries[index] = [index, this[index]]
    }

    // sort with fallback based on initial indices
    entries.sort(function (a, b) {
      var comparison = Number(this(a[1], b[1]))
      return comparison || a[0] - b[0]
    }.bind(compareFunction))

    // re-map original array to stable sorted values
    for (index = 0; index < length; index++) {
      this[index] = entries[index][1]
    }
    
    return this
  }
})

// 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
console.log('sort() stable?', array
  .slice()
  .sort(alwaysEqual)
  .every(isUnmoved)
)
// guaranteed to be stable
console.log('stableSort() stable?', array
  .slice()
  .stableSort(alwaysEqual)
  .every(isUnmoved)
)

// performance using realistic scenario with unsorted big data
function time(arrayCopy, algorithm, compare) {
  var start
  var stop
  
  start = performance.now()
  algorithm.call(arrayCopy, compare)
  stop = performance.now()
  
  return stop - start
}

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

const msSort = time(array.slice(), Array.prototype.sort, ascending)
const msStableSort = time(array.slice(), Array.prototype.stableSort, 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()здається, працює на швидкості 57% від sort()версії 59-61 Chrome.

Використання .bind(compareFunction)в обгорнутій анонімній функції в межах stableSort()збільшило цю відносну продуктивність приблизно на 38%, уникаючи непотрібного посилання compareFunctionна кожен виклик, призначаючи замість цього контекст.

Оновлення

Змінився потрійний оператор на логічне коротке замикання, яке, як правило, в середньому працює краще (схоже, що на 2-3% різниця в ефективності).


5

Далі сортує наданий масив, застосовуючи надану функцію порівняння, повертаючи початкове порівняння індексу, коли функція порівняння повертає 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 ) => 0 ).join( "" ) === jQuery.expando
марсіан

3

Ось стабільна реалізація. Це працює за допомогою нативного сортування, але у випадках, коли елементи порівнюються як рівні, ви розриваєте зв’язки, використовуючи вихідну позицію індексу.

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);

інша відповідь на це натякав, але не публікував кодексів.

але, це не швидко за моїм орієнтиром . Я змінив імпульсний сортуючий імпульс, щоб прийняти спеціальну функцію порівняння, і це було набагато швидше.


Чи правильний ваш орієнтир? Здається, ваш "stableSort" не модифікує вхідний масив, інші сорти - робити, і як ви не відтворили "arr" під час "налаштування", інші сортування сортували вже відсортовані масиви ....
4esn0k

@ 4esn0k ти неправильно читав? Я сказав, що мій стабільний функціонал НЕ швидкий.
коза

@gota, ах, пробач мене
4esn0k

3

Ви також можете використовувати Timsort. Це дійсно складний алгоритм (400+ рядків, отже, тут немає вихідного коду), тому дивіться опис Вікіпедії або використовуйте одну з існуючих реалізацій JavaScript:

GPL 3 здійснення . Упаковано як Array.prototype.timsort. Точне переписування коду Java.

Реалізація публічного домену Означається як підручник, зразок коду показує його використання лише з цілими числами.

Timsort - це високооптимізований гібрид сортування об'єднань та перетасовок, який є алгоритмом сортування за замовчуванням у Python та Java (1.7+). Це складний алгоритм, оскільки він використовує різні алгоритми для багатьох особливих випадків. Але в результаті це надзвичайно швидко за найрізноманітніших обставин.


1

Простий mergeSort з http://www.stoimen.com/blog/2010/07/02/friday-algorithms-javascript-merge-sort/

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));

0

Я повинен сортувати багатовимірні масиви за довільним стовпцем, а потім за іншим. Я використовую цю функцію для сортування:

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 ніколи не повертає нуль, саме там деякі реалізації функції "сортування" приймають рішення, які можуть бути неправильними.

Це також досить швидко прокляття.


0

Ось як можна розширити об'єкт масиву JS за замовчуванням методом прототипу, використовуючи MERGE SORT . Цей метод дозволяє сортувати за певним ключем (перший параметр) та заданим порядком ('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)
  }
}

Ви можете перевірити це самостійно, опустивши вказаний фрагмент у консоль браузера, а потім спробуйте:

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');

0

Тож мені потрібен був стабільний сорт для мого додатка 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;
}

0

Я знаю, що на це відповіли багато. Я просто хотів просунути пост швидкої реалізації 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 просто видаліть усі типи)


0

За даними блогу v8 dev і caniuse.com Array.sort вже стабільно, як того вимагає специфікація в сучасних браузерах, тому вам не потрібно прокручувати власне рішення. Єдиний виняток, який я бачу, - це Edge, який незабаром повинен перейти на хром і підтримати його.


0

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]);


-1

Підрахунок Сортування швидше, ніж сортування об'єднань (воно виконується за 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

12
Кілька речей, які слід сказати: 1. Підрахунок сортування працює добре лише у щільному просторі чисел. (Спробуйте сортувати масив [1, 2e9, 1e9]) 2. Не пишіть для циклів, як циклів. 3. Не додавайте випадково речі в простір імен Math. 4. Можливо, ви захочете подумати про дружбу з крапками з комою.
Домі

Крім того, у випадку, коли масив має повторювані значення, він буде працювати назавжди. Наприклад, array [3, 1, 3]хеши до [undefined, 1, undefined, 3]. Ми отримуємо два неозначених значення, тоді як алгоритм очікує, що їх буде три.
MKPS
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.