Javascript Array.sort triển khai?


236

Array#sort()Hàm JavaScript sử dụng thuật toán nào ? Tôi hiểu rằng nó có thể sử dụng tất cả các cách lập luận và hàm để thực hiện các loại sắp xếp khác nhau, tôi chỉ đơn giản quan tâm đến thuật toán mà loại vanilla sử dụng.


Bạn nên xem xét một giải pháp thay thế từ những người đưa ra.
Anthony

Câu trả lời:


77

Nếu bạn nhìn vào lỗi này 224128 , có vẻ như MergeSort đang được Mozilla sử dụng.


3
Vâng, nó cũng sai ở chỗ nó chỉ nêu một thuật toán để thực hiện cụ thể. Đặc tả này không đưa ra các tuyên bố như vậy và các triển khai khác sử dụng các thuật toán khác, vì vậy điều này khá sai lệch.
Patrick Roberts

292

Tôi vừa mới có một cái nhìn tại các WebKit (Chrome, Safari ...) nguồn . Tùy thuộc vào loại mảng, các phương pháp sắp xếp khác nhau được sử dụng:

Mảng số (hoặc mảng kiểu nguyên thủy) được sắp xếp bằng hàm thư viện chuẩn C ++ std::qsort, thực hiện một số biến thể của quicksort (thường là introsort ).

Các mảng liền kề của loại không số được sắp xếp theo chuỗi và được sắp xếp bằng cách sử dụng phép hợp nhất, nếu có (để có được sự sắp xếp ổn định) hoặc qsortnếu không có sắp xếp hợp nhất.

Đối với các loại khác (mảng không liền kề và có lẽ là cho mảng kết hợp) WebKit sử dụng loại sắp xếp lựa chọn (mà chúng gọi là sắp xếp kiểu min min ) hoặc, trong một số trường hợp, nó sắp xếp thông qua cây AVL. Thật không may, tài liệu ở đây khá mơ hồ nên bạn phải theo dõi các đường dẫn mã để thực sự xem loại phương thức sắp xếp nào được sử dụng.

Và sau đó có những viên đá quý như bình luận này :

// 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).

- Chúng ta chỉ hy vọng rằng bất cứ ai thực sự khắc phục lỗi này, điều này có sự hiểu biết tốt hơn về thời gian chạy không có triệu chứng so với người viết nhận xét này và nhận ra rằng loại radix có mô tả thời gian chạy phức tạp hơn một chút so với O (N).

(Cảm ơn phsource đã chỉ ra lỗi trong câu trả lời ban đầu.)


46

Không có yêu cầu dự thảo nào cho JS để sử dụng một algorthim sắp xếp cụ thể. Như nhiều người đã đề cập ở đây, Mozilla sử dụng sắp xếp hợp nhất. Tuy nhiên, trong mã nguồn v8 của Chrome, tính đến ngày hôm nay, nó sử dụng QuickSort và InsertsSort, cho các mảng nhỏ hơn.

Nguồn động cơ V8

Từ dòng 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;
      }
    }
  };

Cập nhật Kể từ năm 2018 V8 sử dụng TimSort, cảm ơn @celwell. Nguồn


9
Tôi tin rằng V8 hiện đang sử dụng TimSort: github.com/v8/v8/blob/78f2610345fdd14ca401d920c140f8f461b631d1/ từ
celwell

24

Tiêu chuẩn ECMAscript không chỉ định thuật toán sắp xếp nào sẽ được sử dụng. Thật vậy, các trình duyệt khác nhau có các thuật toán sắp xếp khác nhau. Ví dụ: sort () của Mozilla / Firefox không ổn định (theo nghĩa sắp xếp của từ) khi sắp xếp bản đồ. Sắp xếp của IE () ổn định.


15
Cập nhật: Firefox gần đây có ổn định Array.sort; thấy câu hỏi này .
skagedal

Vấn đề là thuật toán sắp xếp phụ thuộc vào việc thực hiện.
sean

Đối với người tò mò, tiêu chuẩn ECMAscript được tìm thấy ở đây: tc39.github.io/ecma262/#sec-array.prototype.sort
Benjamin

10

Sau một số nghiên cứu khác, nó xuất hiện, đối với Mozilla / Firefox, Array.sort () sử dụng phép hợp nhất. Xem mã ở đây .


8

Tôi nghĩ rằng điều đó sẽ phụ thuộc vào việc bạn thực hiện trình duyệt nào.

Mỗi loại trình duyệt có triển khai công cụ javascript riêng, do đó, nó phụ thuộc. Bạn có thể kiểm tra repos mã nguồn cho Mozilla và Webkit / Khtml để biết các triển khai khác nhau.

Tuy nhiên IE là nguồn đóng, vì vậy bạn có thể phải hỏi ai đó tại microsoft.


Các thông dịch viên khác nhau có thể làm những việc khác nhau theo nghĩa là họ có lỗi (nghĩa là nó không nhằm mục đích) hoặc họ thêm hoặc lấy đi các tính năng. Phương thức sort () là một phần tiêu chuẩn của Core JavaScript và sẽ được xác định theo tiêu chuẩn mà trình duyệt muốn theo.
Jason Bunting

2
@JasonBunting nếu chức năng được triển khai thực hiện những gì cần làm theo quy định trong đặc tả, các nhà phát triển trình duyệt có thể tự do thực hiện chức năng theo ý muốn: có thể là bong bóng hoặc sắp xếp nhanh. Thông số kỹ thuật ECMA không xác định thuật toán sắp xếp sẽ được sử dụng.
Damir Zekić


0

Hàm Array.sort () của JavaScript có các cơ chế bên trong để chọn thuật toán sắp xếp tốt nhất (QuickSort, MergeSort, v.v.) trên cơ sở kiểu dữ liệu của các phần tử mảng.


0

thử điều này với sắp xếp nhanh chóng:

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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.