Javascript Array.sort uygulaması?


236

JavaScript Array#sort()işlevi hangi algoritmayı kullanır? Farklı türlerde şeyler yapmak için her türlü argüman ve işlevi alabileceğini anlıyorum, sadece vanilya türünün hangi algoritmayı kullandığıyla ilgileniyorum.


Verilenlerden alternatif bir çözüm düşünmelisiniz.
Anthony

Yanıtlar:


77

Bu hata 224128'e bakarsanız, MergeSort'un Mozilla tarafından kullanıldığı anlaşılıyor.


3
Sadece belirli bir uygulama için bir algoritma belirtmesi de yanlıştır. Spesifikasyon böyle bir iddiada bulunmaz ve diğer uygulamalar başka algoritmalar kullanır, bu yüzden bu oldukça yanıltıcıdır.
Patrick Roberts

292

WebKit (Chrome, Safari…) kaynağına bir göz attım . Dizi türüne bağlı olarak farklı sıralama yöntemleri kullanılır:

Sayısal diziler (veya ilkel tip diziler), std::qsortbazı hızlı sıralama çeşitlerini (genellikle introsort ) uygulayan C ++ standart kitaplık işlevi kullanılarak sıralanır .

Sayısal olmayan türdeki bitişik diziler , varsa (sabit bir sıralama elde etmek için) veya qsortbirleştirme sıralaması yoksa , mergesort kullanılarak dizilir ve sıralanır .

Diğer türler için (bitişik olmayan diziler ve büyük olasılıkla ilişkilendirilebilir diziler için) WebKit, seçim sıralaması kullanır ( "min" sıralama olarak adlandırır ) veya bazı durumlarda bir AVL ağacı aracılığıyla sıralar. Ne yazık ki, buradaki belgeler oldukça belirsizdir, bu nedenle hangi sıralama yönteminin kullanıldığını görmek için kod yollarını izlemeniz gerekir.

Ve sonra bu yorum gibi taşlar var :

// FIXME: Since we sort by string value, a fast algorithm might be to use a
// radix sort. That would be O(N) rather than O(N log N).

- Sadece bunu kim düzeltirse, bunun asimptotik çalışma zamanını bu yorumun yazarından daha iyi anladığını ve sayı tabanı sıralamasının sadece O (N) 'den biraz daha karmaşık çalışma zamanı açıklamasına sahip olduğunu fark edelim .

(Orijinal yanıttaki hatayı işaret ettiği için phsource sayesinde.)


46

JS'nin belirli bir sıralama algorthim kullanması için taslak şartı yoktur. Birçok kişinin burada belirttiği gibi, Mozilla birleştirme sıralaması kullanır.

V8 Motor Kaynağı

Satırlardan 807-891

  var QuickSort = function QuickSort(a, from, to) {
    var third_index = 0;
    while (true) {
      // Insertion sort is faster for short arrays.
      if (to - from <= 10) {
        InsertionSort(a, from, to);
        return;
      }
      if (to - from > 1000) {
        third_index = GetThirdIndex(a, from, to);
      } else {
        third_index = from + ((to - from) >> 1);
      }
      // Find a pivot as the median of first, last and middle element.
      var v0 = a[from];
      var v1 = a[to - 1];
      var v2 = a[third_index];
      var c01 = comparefn(v0, v1);
      if (c01 > 0) {
        // v1 < v0, so swap them.
        var tmp = v0;
        v0 = v1;
        v1 = tmp;
      } // v0 <= v1.
      var c02 = comparefn(v0, v2);
      if (c02 >= 0) {
        // v2 <= v0 <= v1.
        var tmp = v0;
        v0 = v2;
        v2 = v1;
        v1 = tmp;
      } else {
        // v0 <= v1 && v0 < v2
        var c12 = comparefn(v1, v2);
        if (c12 > 0) {
          // v0 <= v2 < v1
          var tmp = v1;
          v1 = v2;
          v2 = tmp;
        }
      }
      // v0 <= v1 <= v2
      a[from] = v0;
      a[to - 1] = v2;
      var pivot = v1;
      var low_end = from + 1;   // Upper bound of elements lower than pivot.
      var high_start = to - 1;  // Lower bound of elements greater than pivot.
      a[third_index] = a[low_end];
      a[low_end] = pivot;

      // From low_end to i are elements equal to pivot.
      // From i to high_start are elements that haven't been compared yet.
      partition: for (var i = low_end + 1; i < high_start; i++) {
        var element = a[i];
        var order = comparefn(element, pivot);
        if (order < 0) {
          a[i] = a[low_end];
          a[low_end] = element;
          low_end++;
        } else if (order > 0) {
          do {
            high_start--;
            if (high_start == i) break partition;
            var top_elem = a[high_start];
            order = comparefn(top_elem, pivot);
          } while (order > 0);
          a[i] = a[high_start];
          a[high_start] = element;
          if (order < 0) {
            element = a[i];
            a[i] = a[low_end];
            a[low_end] = element;
            low_end++;
          }
        }
      }
      if (to - high_start < low_end - from) {
        QuickSort(a, high_start, to);
        to = low_end;
      } else {
        QuickSort(a, from, low_end);
        from = high_start;
      }
    }
  };

Güncelleme 2018 itibariyle V8, Timcelort kullanıyor, teşekkürler @celwell. Kaynak


9
V8'in şimdi TimSort kullandığını düşünüyorum: github.com/v8/v8/blob/78f2610345fdd14ca401d920c140f8f461b631d1/…
celwell

24

ECMAscript standardı hangi sıralama algoritmasının kullanılacağını belirtmez. Aslında, farklı tarayıcılarda farklı sıralama algoritmaları bulunur. Örneğin, bir haritayı sıralarken Mozilla / Firefox'un sort () yöntemi (kelimenin sıralama anlamında ) sabit değildir . IE'nin sort () yöntemi kararlıdır.


15
Güncelleme: Son Firefox'larda kararlı Array.sort; bu soruya bakın .
skagedal

Mesele, sıralama algoritmasının uygulamaya bağlı olmasıdır.
sean

Meraklı olmak için, ECMAscript standardı burada bulunur: tc39.github.io/ecma262/#sec-array.prototype.sort
Benjamin

10

Biraz daha araştırmadan sonra, Mozilla / Firefox için, Array.sort () öğesinin birleştirme kullandığı anlaşılıyor. Buradaki koda bakın .


8

Bu, hangi tarayıcı uygulamasından bahsettiğinize bağlı olacağını düşünüyorum.

Her tarayıcı türünün kendi javascript motoru uygulaması vardır, bu nedenle değişir. Mozilla için kaynak kodu depolarını ve farklı uygulamalar için Webkit / Khtml'yi kontrol edebilirsiniz.

IE kapalı kaynak kodludur, bu yüzden microsoft'ta birine danışmanız gerekebilir.


Farklı çevirmenler, buggy olmaları (yani amaçlı değildir) ya da özellik ekleyip almaları anlamında farklı şeyler yapabilirler. Sort () yöntemi, Core JavaScript'in standart bir parçasıdır ve tarayıcıların takip etmek istediği standart tarafından tanımlanır.
Jason Bunting

2
@JasonBunting işlev uygulanırsa ve spesifikasyonda tanımlandığı gibi yapması gerekiyorsa, tarayıcı geliştiricileri işlevi istedikleri gibi uygulamakta özgürdür: ister kabarcık ister hızlı sıralama olsun. ECMA teknik özellikleri, kullanılacak sıralama algoritmasını tanımlamaz.
Damir Zekić


0

JavaScript'in Array.sort () işlevi, dizi öğelerinin veri türüne göre en iyi sıralama algoritmasını (QuickSort, MergeSort, vb.) Seçmek için dahili mekanizmalara sahiptir.


0

hızlı sıralama ile deneyin:

function sort(arr, compareFn = (a, b) => a <= b) {

    if (!arr instanceof Array || arr.length === 0) {
        return arr;
    }

    if (typeof compareFn !== 'function') {
        throw new Error('compareFn is not a function!');
    }

    const partition = (arr, low, high) => {
        const pivot = arr[low];
        while (low < high) {
            while (low < high && compareFn(pivot, arr[high])) {
                --high;
            }
            arr[low] = arr[high];
            while (low < high && compareFn(arr[low], pivot)) {
                ++low;
            }
            arr[high] = arr[low];
        }
        arr[low] = pivot;
        return low;
    };

    const quickSort = (arr, low, high) => {
        if (low < high) {
            let pivot = partition(arr, low, high);
            quickSort(arr, low, pivot - 1);
            quickSort(arr, pivot + 1, high);
        }
        return arr;
    };

    return quickSort(arr, 0, arr.length - 1);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.