Array#sort()ฟังก์ชันJavaScript ใดที่ใช้อัลกอริทึม ฉันเข้าใจว่ามันสามารถใช้การโต้แย้งและฟังก์ชั่นในการดำเนินการประเภทต่าง ๆ ได้ฉันสนใจในอัลกอริธึมที่การเรียงลำดับวานิลลาใช้
Array#sort()ฟังก์ชันJavaScript ใดที่ใช้อัลกอริทึม ฉันเข้าใจว่ามันสามารถใช้การโต้แย้งและฟังก์ชั่นในการดำเนินการประเภทต่าง ๆ ได้ฉันสนใจในอัลกอริธึมที่การเรียงลำดับวานิลลาใช้
คำตอบ:
หากคุณดูที่ข้อผิดพลาด224128นี้ดูเหมือนว่า Mozilla จะถูกใช้งาน MergeSort
ฉันเพิ่งได้ดู WebKit ที่ (Chrome, Safari ... ) แหล่งที่มาแหล่งที่มาขึ้นอยู่กับประเภทของอาเรย์จะใช้วิธีการเรียงลำดับที่แตกต่างกัน:
อาร์เรย์ที่เป็นตัวเลข (หรืออาร์เรย์ของชนิดดั้งเดิม) จะถูกจัดเรียงโดยใช้ฟังก์ชันไลบรารีมาตรฐาน C ++ std::qsortซึ่งใช้การเปลี่ยนแปลงบางอย่างของ quicksort (โดยปกติแล้วจะเป็นintrosort )
อาร์เรย์ที่ต่อเนื่องกันของประเภทที่ไม่ใช่ตัวเลขจะมีการทำให้เป็นสตริงและเรียงลำดับโดยใช้การผสานถ้ามี (เพื่อให้ได้การเรียงที่เสถียร) หรือqsortผสานหากไม่มีการเรียงแบบผสาน
สำหรับประเภทอื่น ๆ (อาเรย์ที่ไม่ต่อเนื่องกันและน่าจะเป็นอาเรย์แบบเชื่อมโยง) WebKit ใช้การเรียงลำดับการเลือกอย่างใดอย่างหนึ่ง(ซึ่งเรียกว่าการเรียงลำดับ "ต่ำสุด") ) หรือในบางกรณีมันเรียงลำดับผ่านแผนผัง 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).
- เราหวังว่าผู้ที่ "แก้ไข" จริง ๆ แล้วสิ่งนี้จะมีความเข้าใจที่ดีขึ้นเกี่ยวกับการทำงานของ asymptotic รันไทม์มากกว่าผู้เขียนความคิดเห็นนี้และตระหนักว่าการเรียงลำดับของ radix นั้นมีคำอธิบายรันไทม์ที่ซับซ้อนเล็กน้อยกว่า O (N)
(ขอบคุณ phsource ที่ชี้ให้เห็นข้อผิดพลาดในคำตอบเดิม)
ไม่มีข้อกำหนดแบบร่างสำหรับ JS เพื่อใช้การจัดเรียง algorthim เฉพาะ ดังที่หลายคนกล่าวถึงที่นี่ Mozilla ใช้การผสานการเรียงลำดับอย่างไรก็ตามในซอร์สโค้ด v8 ของ Chrome ณ วันนี้มันใช้ QuickSort และ InsertionSort สำหรับอาร์เรย์ขนาดเล็ก
จากสาย 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 ใช้ TimSort ขอบคุณ @celwell แหล่ง
มาตรฐาน ECMAscript ไม่ได้ระบุอัลกอริทึมการเรียงลำดับที่จะใช้ เบราว์เซอร์ที่แตกต่างกันนั้นมีอัลกอริทึมการเรียงลำดับที่แตกต่างกัน ตัวอย่างเช่นการเรียงลำดับของ Mozilla / Firefox () ไม่เสถียร (ในแง่การเรียงลำดับของคำ) เมื่อเรียงลำดับแผนที่ การจัดเรียงของ IE () มีเสถียรภาพ
ฉันคิดว่ามันจะขึ้นอยู่กับการใช้งานเบราว์เซอร์ที่คุณอ้างถึง
เบราว์เซอร์ทุกประเภทมีเครื่องมือติดตั้งจาวาสคริปต์เป็นของตัวเอง คุณสามารถตรวจสอบซอร์สโค้ด repos สำหรับ Mozilla และ Webkit / Khtml สำหรับการใช้งานที่แตกต่างกัน
อย่างไรก็ตาม IE เป็นแหล่งปิดดังนั้นคุณอาจต้องถามใครสักคนที่ microsoft
ตั้งแต่ V8 v7.0 / Chrome 70 V8 ใช้TimSortซึ่งเป็นอัลกอริธึมในการเรียงของ Python Chrome 70 วางจำหน่ายในวันที่ 13 กันยายน 2018
ดูโพสต์ในบล็อกของนักพัฒนา V8สำหรับรายละเอียดเกี่ยวกับการเปลี่ยนแปลงนี้ นอกจากนี้คุณยังสามารถอ่านรหัสที่มาหรือแก้ไข 1186801
ฟังก์ชัน Array.sort () ของ JavaScript มีกลไกภายในเพื่อเลือกอัลกอริทึมการเรียงลำดับที่ดีที่สุด (QuickSort, MergeSort และอื่น ๆ ) บนพื้นฐานของประเภทข้อมูลขององค์ประกอบอาร์เรย์
ลองใช้การเรียงลำดับด่วน:
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);
}