整理完了归并排序和快速排序,现在就是来把三种常用排序的剩下的堆排序,进行一个整理总结。堆排序中的堆调整又分为大顶堆和小顶堆。
   顾名思义,大顶堆就是最大的在顶端,小顶堆则是最小值在顶端,堆排序的要点都是在堆的调整,以及排序时的下标需要注意一些边界。考试,面试等都比较常考。

大顶堆的一趟排序过程

大顶堆的一趟排序过程


# 1. 大顶堆

# C Solution
//向下调整
#include <stdio.h>
#include <stdlib.h>

void max_heapify_downJust(int *arr, int start, int end) {
    int dad = start;
    int son = dad * 2 + 1;

    while (son <= end){   //注意边界及找到左右结点较大的那个
        if (son + 1 <= end && arr[son] < arr[son + 1])
            son++;

        if (arr[dad] > arr[son])   //如果父节点比子节点大,跳出
            return;
        else{
            int temp = arr[dad];
            arr[dad] = arr[son];	//父结点与子节点较大的进行交换
            arr[son] = temp;

            dad = son;
            son = dad * 2 + 1;
        }
    }
}


void heap_sort(int *arr, int len) {
    int i;
    //初始建立一个大顶堆
    for (i = len / 2 - 1; i >= 0; i--){
        max_heapify_downJust(arr, i, len - 1);
    }

	//排序一趟,交换根结点与最后一个结点,下次调堆及排序不算入该结点
    for (i = len - 1; i > 0; i--){
        int temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;
        max_heapify_downJust(arr, 0, i - 1);
    }
}


int main(){
    int arr[] = {5,3,8,1,6};

    int len = sizeof(arr) / sizeof(int);  //c语言中求数组长度

    heap_sort(arr, len);	//堆排序过程

    for (int i = 0; i < len; i++){
        printf("%d ", arr[i]);
    }

    printf("\n");
    return 0;
}

参考Ariest

# JavaScript Solution
/** 将 i 结点以下的堆整理为大顶堆,注意这一步实现的基础实际上是:
假设 结点 i 以下的子堆已经是一个大顶堆,shiftDown函数实现的
功能是实际上是:找到 结点 i 在包括结点 i 的堆中的正确位置。后面
将写一个 for 循环,从第一个非叶子结点开始,对每一个非叶子结点
都执行 shiftDown操作,所以就满足了结点 i 以下的子堆已经是一大
顶堆 **/
function shiftDown(A, i, length) {
  let temp = A[i]; // 当前父节点
  // j<length 的目的是对结点 i 以下的结点全部做顺序调整
  for (let j = 2 * i + 1; j < length; j = 2 * j + 1) {
    temp = A[i]; // 将 A[i] 取出,整个过程相当于找到 A[i] 应处于的位置
    if (j + 1 < length && A[j] < A[j + 1]) {
      j++; // 找到两个孩子中较大的一个,再与父节点比较
    }
    if (temp < A[j]) {
      [A[i], A[j]] = [A[j], A[i]]; // 如果父节点小于子节点:交换;否则跳出
      i = j; // 交换后,temp 的下标变为 j
    } else {
      break;
    }
  }
}

// 堆排序
function heapSort(A) {
  // 初始化大顶堆,从第一个非叶子结点开始
  for (let i = Math.floor(A.length / 2 - 1); i >= 0; i--) {
    shiftDown(A, i, A.length);
  }
  // 排序,每一次for循环找出一个当前最大值,数组长度减一
  for (let i = Math.floor(A.length - 1); i > 0; i--) {
    [A[0], A[i]] = [A[i], A[0]];
    shiftDown(A, 0, i); /** 从根节点开始调整,并且最后一个结点已经为当
                         前最大值,不需要再参与比较,所以第三个参数
                         为 i,即比较到最后一个结点前一个即可 **/
  }
}

let Arr = [4, 6, 8, 5, 9, 1, 2, 5, 3, 2];
heapSort(Arr);
for (let i in Arr) {
  console.log(Arr[i] + ' ');
}

# 2. 小顶堆

# C Solution

# JavaScript Solution