用快速排序实现javascript 中数组的Array.sort() 方法

快速排序是数组常用的排序算法,采用分而治之的思想,需要用到递归,故需要先了解递。

  • Array.prototype.sort(callback)接受一个 回调函数 比如
    testArr.sort((a,b) => a-b) 正在研究中
    那sort用的是什么排序算法呢?那就要看Chrome V8引擎的源码了。

sort方法源码

DEFINE_METHOD(
  GlobalArray.prototype,
  sort(comparefn) {
    CHECK_OBJECT_COERCIBLE(this, "Array.prototype.sort");

    if (!IS_UNDEFINED(comparefn) && !IS_CALLABLE(comparefn)) {
      throw %make_type_error(kBadSortComparisonFunction, comparefn);
    }

    var array = TO_OBJECT(this);
    var length = TO_LENGTH(array.length);
    return InnerArraySort(array, length, comparefn);
  }
);

InnerArraySort方法源码

function InnerArraySort(array, length, comparefn) {
  // In-place QuickSort algorithm.
  // For short (length <= 10) arrays, insertion sort is used for efficiency.

  if (!IS_CALLABLE(comparefn)) {
    comparefn = function (x, y) {
      if (x === y) return 0;
      if (%_IsSmi(x) && %_IsSmi(y)) {
        return %SmiLexicographicCompare(x, y);
      }
      x = TO_STRING(x);
      y = TO_STRING(y);
      if (x == y) return 0;
      else return x < y ? -1 : 1;
    };
  }
  function InsertionSort(a, from, to) {
    ...
  };
 ...
  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;
      }
    }
  };

  ...

  QuickSort(array, 0, num_non_undefined);
 ...
  return array;
}
  • 这一步最重要的是QuickSort,从代码和注释中可以看出sort使用的是插入排序和快速排序结合的排序算法。数组长度不超过10时,使用插入排序。长度超过10使用快速排序。在数组较短时插入排序更有效率。

自己实现的mysort() 方法

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>冒泡排序</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    header {
      text-align: center;
      font-size: 30px;
      font-weight: 900;
      line-height: 100px;
      width: 100%;
      height: 100px;
      background-color: #888;
      border-bottom: 1px solid #000;
      color: #fff;
      box-sizing: border-box;
    }

    aside {
      position: absolute;
      padding-left: 10px;
      top: 100px;
      left: 0;
      bottom: 0;
      width: 250px;
      background-color: #ddd;
      box-sizing: border-box;
      border: 1px solid #000;
      border-top: 0;
    }

    main {
      position: absolute;
      top: 100px;
      right: 0;
      left: 250px;
      bottom: 0;
      background-color: #fff;
    }

    #algorithm,
    #data_structure {
      margin-left: 60px;
    }

    form {
      width: 95%;
      height: 300px;
      margin: 20px auto;
      border: 1px solid #000;
    }

    #array_info {
      display: block;
    }

    input {
      width: 99%;
      height: 30px;
      border: 1px solid #000;
      margin: 5px auto;
      font-size: 20px;

    }

    #result_info {
      display: block;
    }

    #sortButton {
      background-color: royalblue;
      width: 200px;
      height: 40px;
      border-radius: 5px;
    }

    h3 {
      margin-bottom: 10px;
    }
  </style>
</head>

<body>
  <!-- 布局容器 -->

  <!-- 头部区域 -->
  <header>
    数据结构与算法
  </header>
  <!-- 侧边栏 -->
  <aside>
    <h3>*******数据结构*******</h3>
    <ol id="data_structure">
      <li>数组</li>
      <li>栈</li>
      <li>队列和双端队列</li>
      <li>链表</li>
      <li>集合</li>
      <li>字典和散列表</li>
      <li>树</li>
      <li>二叉堆</li>
      <li>图</li>
    </ol>
    <h3>*******算法*******</h3>
    <ol id="algorithm">
      <li>排序</li>
      <li>递归</li>
      <li>搜索</li>
    </ol>
  </aside>
  <!-- 主体 -->
  <main>
    <h3>这是前段程序员必须掌握的排序算法</h3>
    请输入你要排序的数组,主要需要用英文逗号分隔,中文排序不生效。 例如:3,4,5,10,1,2,3,56,6,7,7
    <input type="text" id="array_info">
    排序后的结果
    <input type="text" id="result_info">
    <input type="button" id="sortButton" value="点击开始快速排序">
  </main>
  <script>
    // 快速排序的调用函数
    Array.prototype.mysort =  function ( left = 0, right = this.length -1) {
      if (this.length === 0) return this
      let index = partition(this, left, right)
      if (left < index - 1) this.mysort( left, index - 1)
      if (index < right) this.mysort(index, right)
      return this
      // partition是一个策略函数,传进 数组和左右指针了,可以进行划分排序,返回划分关键节点位置,以便下一次递归调用时候传参
      function partition(arr, left, right) {
        const pivot = arr[Math.floor((left + right) / 2)]
        while (left <= right) {
          while (arr[left] < pivot) {
          left++
          }
          while (arr[right] > pivot) {
            right--
          }
          if (left <= right) {
            ;[arr[left], arr[right]] = [arr[right], arr[left]]
            left++;
            right--;
          }
        } 
        return left
      }
    }
    const btn = document.querySelector('#sortButton')
    btn.addEventListener('click', function () {
      const array_info = document.querySelector('#array_info').value
      const testArr = array_info.split(',')
      document.querySelector('#result_info').value = testArr.mysort()
    })
  </script>
</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容