자바 스크립트 Array.Sort 구현?


236

JavaScript Array#sort()함수 는 어떤 알고리즘을 사용합니까? 다른 종류의 정렬을 수행하는 데 모든 방식의 인수와 함수가 필요할 수 있음을 이해합니다. 바닐라 정렬이 사용하는 알고리즘에 관심이 있습니다.


주어진 것 중에서 다른 해결책을 고려해야합니다.
Anthony

답변:


77

이 버그 224128 을 보면 MergeSort가 Mozilla에서 사용중인 것 같습니다.


3
특정 구현에 대한 알고리즘 만 명시한다는 점도 잘못된 것입니다. 본 명세서는 그러한 주장을하지 않으며, 다른 구현은 다른 알고리즘을 사용하므로 이것은 오해의 소지가있다.
Patrick Roberts

292

방금 WebKit (Chrome, Safari…) 소스를 살펴 보았습니다 . 배열 유형에 따라 다른 정렬 방법이 사용됩니다.

숫자 형 배열 (또는 기본 유형의 배열)은 C ++ 표준 라이브러리 함수 std::qsort를 사용하여 정렬되어 퀵 정렬 (보통 introsort )의 변형을 구현 합니다.

숫자가 아닌 유형의 연속 배열은 사용 가능한 경우 (안정적인 정렬을 얻기 위해) 또는 qsort사용 가능한 병합 정렬이없는 경우 mergesort를 사용하여 문자열 화되고 정렬 됩니다.

다른 유형 (인접하지 않은 배열 및 아마도 연관 배열의 경우) WebKit은 선택 정렬 ( “min”sort이라고 함 )을 사용하거나 경우에 따라 AVL 트리를 통해 정렬합니다. 불행히도 여기 문서는 다소 모호하므로 실제로 어떤 종류의 정렬 방법이 사용되는지 코드 경로를 추적해야합니다.

그리고이 주석 과 같은 보석 이 있습니다 :

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

– 실제로 이것을 "수정"하는 사람이이 주석의 작성자보다 점근 적 런타임에 대해 더 잘 이해하고 기수 정렬이 단순히 O (N)보다 약간 더 복잡한 런타임 설명을 가지고 있음을 깨닫기를 바랍니다 .

(원래 답변의 오류를 지적한 phsource에게 감사합니다.)


46

JS가 특정 정렬 알고리즘을 사용해야하는 초안 요구 사항은 없습니다. 많은 사람들이 여기에서 언급했듯이 Mozilla는 병합 정렬을 사용하지만 오늘날 Chrome의 v8 소스 코드에서는 더 작은 배열에 QuickSort 및 InsertionSort를 사용합니다.

V8 엔진 소스

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

업데이트 2018 V8은 @celwell 덕분에 TimSort를 사용합니다. 출처


9
: 나는 V8 지금 TimSort 사용하고 생각 github.com/v8/v8/blob/78f2610345fdd14ca401d920c140f8f461b631d1/...
celwell

24

ECMAscript 표준은 사용할 정렬 알고리즘을 지정하지 않습니다. 실제로 브라우저마다 다른 정렬 알고리즘이 있습니다. 예를 들어, 지도를 정렬 할 때 Mozilla / Firefox의 sort ()는 단어의 정렬 의미에서 안정적 이지 않습니다 . IE의 sort ()는 안정적입니다.


15
업데이트 : 최근 Firefox는 안정적입니다 Array.sort. 이 질문을 참조하십시오 .
skagedal

요점은 정렬 알고리즘이 구현에 따라 다르다는 것입니다.
sean



8

나는 그것이 당신이 참조하는 브라우저 구현에 달려 있다고 생각합니다.

모든 브라우저 유형에는 자체 자바 스크립트 엔진 구현이 있으므로 다릅니다. 다양한 구현에 대해서는 Mozilla 및 Webkit / Khtml의 소스 코드 저장소를 확인할 수 있습니다.

그러나 IE는 비공개 소스이므로 Microsoft에 문의해야 할 수도 있습니다.


각기 다른 통역사는 버그가 있거나 (예 : 사용하지 않음) 기능을 추가하거나 제거한다는 점에서 다르게 작동 할 수 있습니다. sort () 메소드는 Core JavaScript의 표준 부분이며 표준에 의해 정의되며 브라우저에서 따르려고합니다.
Jason Bunting

2
@JasonBunting 함수가 구현 되고 사양에 정의 된대로 수행해야 할 경우 브라우저 개발자는 원하는대로 함수를 자유롭게 구현할 수 있습니다. 기포 또는 빠른 정렬입니다. ECMA 사양은 사용될 정렬 알고리즘을 정의하지 않습니다.
Damir Zekić


0

JavaScript의 Array.sort () 함수에는 배열 요소의 데이터 유형을 기반으로 최상의 정렬 알고리즘 (QuickSort, MergeSort 등)을 선택하는 내부 메커니즘이 있습니다.


0

빠른 정렬로 시도하십시오.

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);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.