十大排序算法(JavaScript实现 )- 堆排序 Heap Sort

246 阅读3分钟
  1. 十大排序算法(JavaScript实现 )- 冒泡排序 Bubble Sort

  2. 十大排序算法(JavaScript实现 )- 选择排序 Selection Sort

  3. 十大排序算法(JavaScript实现 )- 插入排序 Insertion Sort

  4. 十大排序算法(JavaScript实现 )- 希尔排序 Shell Sort

  5. 十大排序算法(JavaScript实现 )- 快速排序 Quick Sort

  6. 十大排序算法(JavaScript实现 )- 归并排序  Merge Sort

  7. 十大排序算法(JavaScript实现 )- 计数排序 Count Sort

  8. 十大排序算法(JavaScript实现 )- 桶排序 Bucket Sort

  9. 十大排序算法(JavaScript实现 )- 基数排序 Radix Sort

  10. 十大排序算法(JavaScript实现 )- 堆排序 Heap Sort

概念

大顶堆和小顶堆

  • 大顶堆:每个结点的值都大于或等于其左右孩子结点的值
  • 小顶堆:每个结点的值都小于或等于其左右孩子结点的值

堆排序的基本思想是:
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值,

算法原理

构造大顶堆

首先,将一个数组(二叉树),调整成一个大顶堆。该树满足左右子树是一个大顶堆。

图片.png

  1. 当前节点(下标i)为temp=arr[i]=arr[0]
  2. 第一循环取子左节点k=2*i+1=1,与右子节点k+1比较,如果右子节点>左子节点,k++;
  3. 如果arr[k]>temp,则arr[i]=arr[k],i=k;否则,则表示当前树已经大顶堆,退出循环。
  4. 继续循环取左子节点k=2*k+1,重复以上1-3。
  5. 循环结束(k>=length),arr[i]=temp

第一轮循环

图片.png

第二轮循环

图片.png

接着退出循环

图片.png

代码如下:

/**
 * 将一个数组(二叉树),调整成一个大顶堆
 * @param {number[]} arr 待调整数组
 * @param {number} i 非叶子节点索引
 * @param {number} length 数组长度
 */
function adjustHeap(arr, i, length) {
  let temp = arr[i]
  // 开始调整, k = i * 2 + 1 k指向i的左子节点
  for (let k = i * 2 + 1; k < length; k = k * 2 + 1) {
    if(k+1 < length && arr[k] < arr[k+1]) { // 左子节点 < 右子节点
      k++ // 指向右子节点
    }
    if (arr[k] > temp) { // 子节点大于父节点
      arr[i] = arr[k]
      i = k // i指向k,继续循环比较
    } else {
      break
    }
  }
  // for循环结束后,已i为父节点的树的最大值,放到了最顶
  arr[i] = temp
}

堆排序

  1. 先n个元素的无序序列,构建成大顶堆。建立最大堆时是从最后一个非叶子节点(length/2-1)开始从下往上调整的。
  2. 将堆顶元素与末尾元素交换,将最大元素“沉”到数组末端。
  3. 交换过后可能不再满足大顶堆的条件,所以需要将剩下的n-1个元素重新构建成大顶堆(从堆顶元素开始即可)。
  4. 重复第二步、第三步直到整个数组排序完成。
/**
 * 堆排序
 * @param {number[]} arr 
 */
function heapSort(arr) {
  // 将无序序列构建成一个大顶堆。建立最大堆时是从最后一个非叶子节点开始从下往上调整的
  for (let i = ~~(arr.length / 2 - 1); i >= 0; i--) {
    adjustHeap(arr, i, arr.length)
  }

  // 将堆顶元素与末尾元素交换,将最大元素“沉”到数组末端
  for (let j = arr.length - 1; j >=0; j--) {
    let temp = arr[j]
    arr[j] = arr[0]
    arr[0] = temp

    // 交换过后可能不再满足大顶堆的条件,所以需要将剩下的n-1个元素重新构建成大顶堆
    adjustHeap(arr, 0, j)
  }
}