การใช้ Javascript Array.sort หรือไม่


236

Array#sort()ฟังก์ชันJavaScript ใดที่ใช้อัลกอริทึม ฉันเข้าใจว่ามันสามารถใช้การโต้แย้งและฟังก์ชั่นในการดำเนินการประเภทต่าง ๆ ได้ฉันสนใจในอัลกอริธึมที่การเรียงลำดับวานิลลาใช้


คุณควรพิจารณาทางเลือกอื่นจากทางที่ได้รับ
แอนโธนี

คำตอบ:


77

หากคุณดูที่ข้อผิดพลาด224128นี้ดูเหมือนว่า Mozilla จะถูกใช้งาน MergeSort


3
นอกจากนี้ยังผิดที่ระบุเพียงอัลกอริทึมสำหรับการใช้งานเฉพาะ ข้อมูลจำเพาะไม่มีการอ้างสิทธิ์ดังกล่าวและการนำไปใช้งานอื่น ๆ นั้นใช้อัลกอริธึมอื่น ๆ
Patrick Roberts

292

ฉันเพิ่งได้ดู 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 ที่ชี้ให้เห็นข้อผิดพลาดในคำตอบเดิม)


46

ไม่มีข้อกำหนดแบบร่างสำหรับ JS เพื่อใช้การจัดเรียง algorthim เฉพาะ ดังที่หลายคนกล่าวถึงที่นี่ Mozilla ใช้การผสานการเรียงลำดับอย่างไรก็ตามในซอร์สโค้ด v8 ของ Chrome ณ วันนี้มันใช้ 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 ใช้ TimSort ขอบคุณ @celwell แหล่ง


9
ฉันเชื่อว่า V8 กำลังใช้ TimSort: github.com/v8/v8/blob/78f2610345fdd14ca401d920c140f8f461b631d1/1
celwell

24

มาตรฐาน ECMAscript ไม่ได้ระบุอัลกอริทึมการเรียงลำดับที่จะใช้ เบราว์เซอร์ที่แตกต่างกันนั้นมีอัลกอริทึมการเรียงลำดับที่แตกต่างกัน ตัวอย่างเช่นการเรียงลำดับของ Mozilla / Firefox () ไม่เสถียร (ในแง่การเรียงลำดับของคำ) เมื่อเรียงลำดับแผนที่ การจัดเรียงของ IE () มีเสถียรภาพ


15
UPDATE: Firefoxes ล่าสุดมีเสถียรภาพArray.sort; ดูคำถามนี้
skagedal

ประเด็นก็คืออัลกอริทึมการเรียงลำดับนั้นขึ้นอยู่กับการนำไปใช้งาน
ฌอน

สำหรับผู้อยากรู้อยากเห็นมาตรฐาน ECMAscript อยู่ที่นี่: tc39.github.io/ecma262/#sec-array.prototype.sort
Benjamin

10

หลังจากการวิจัยเพิ่มเติมปรากฏว่าสำหรับ Mozilla / Firefox นั้น Array.sort () ใช้การผสานรวม ดูรหัสที่นี่


8

ฉันคิดว่ามันจะขึ้นอยู่กับการใช้งานเบราว์เซอร์ที่คุณอ้างถึง

เบราว์เซอร์ทุกประเภทมีเครื่องมือติดตั้งจาวาสคริปต์เป็นของตัวเอง คุณสามารถตรวจสอบซอร์สโค้ด repos สำหรับ Mozilla และ Webkit / Khtml สำหรับการใช้งานที่แตกต่างกัน

อย่างไรก็ตาม IE เป็นแหล่งปิดดังนั้นคุณอาจต้องถามใครสักคนที่ microsoft


ล่ามที่แตกต่างกันอาจทำสิ่งที่แตกต่างกันในแง่ที่ว่าพวกเขาเป็นรถ (เช่นมันไม่ได้อยู่ในวัตถุประสงค์) หรือพวกเขาเพิ่มหรือเอาคุณสมบัติ sort () วิธีการเป็นส่วนมาตรฐานของ Core JavaScript และจะถูกกำหนดโดยมาตรฐานซึ่งเบราว์เซอร์ที่ต้องการจะปฏิบัติตาม
เจสันตอม่อ

2
@ JasonBunting ถ้ามีการใช้งานฟังก์ชั่นและทำในสิ่งที่ควรทำตามที่กำหนดไว้ในสเปคผู้พัฒนาเบราว์เซอร์มีอิสระที่จะใช้ฟังก์ชั่นที่พวกเขาต้องการ: ไม่ว่าจะเป็นฟองหรือการเรียงลำดับอย่างรวดเร็ว รายละเอียด ECMA ไม่ได้กำหนดอัลกอริทึมการเรียงลำดับที่จะใช้
Damir Zekić

4

ตั้งแต่ V8 v7.0 / Chrome 70 V8 ใช้TimSortซึ่งเป็นอัลกอริธึมในการเรียงของ Python Chrome 70 วางจำหน่ายในวันที่ 13 กันยายน 2018

ดูโพสต์ในบล็อกของนักพัฒนา V8สำหรับรายละเอียดเกี่ยวกับการเปลี่ยนแปลงนี้ นอกจากนี้คุณยังสามารถอ่านรหัสที่มาหรือแก้ไข 1186801


0

ฟังก์ชัน Array.sort () ของ JavaScript มีกลไกภายในเพื่อเลือกอัลกอริทึมการเรียงลำดับที่ดีที่สุด (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.