绝对记得住的各种排序算法(下)

190 阅读3分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

前言

每天至少一道算法题,死磕算法

我们讲一个知识点,要想想如何才能使你看过,认真学过这个知识点后,再过100天以后,你依然不忘呢,所以只有讲的通俗易懂,生动形象,才能更让现在屏幕前的你所接受,记忆才能更深刻,刻在你的脑子里

今天我们就讲一个排序算法,堆排序

首先先来几个概念,什么是完全二叉树,什么是堆

什么是完全二叉树

完全二叉树需要同时满足以下两个条件

  • 从第一层到倒数第二层,每一层都是满的,也就是达到了当前层的最大值
  • 最后一层的排列是从左到右排列的,中间不能跳跃

图片.png

向以上这种就属于完全二叉树

规律这里是重点,下面我们写代码的时候用的到

  • i 结点的父结点 par = floor((i-1)/2) 「向下取整」
  • i 结点的左子结点 2 * i +1
  • i 结点的右子结点 2 * i + 2

什么是堆

堆是完全二叉树的一种特例。堆分为以下两种

  • 大顶堆
  • 小顶堆

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

图片.png

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

图片.png

如何创建堆

大顶堆和小顶堆除了约束条件的规则相反之外,其他都是一样的,所以我们接下来以大顶堆为例

完成大顶堆需要分两步走

我们以数组

const arr = [4, 9, 2, 10, 7];

为例

他对应的数结构为这个样子

图片.png

  • 第一步:从顶部开始,以每三个数为一颗树,构成一个堆结构(递归)
/**
* @description: 向下堆化
* @param {*} nums 数组
* @param {*} n 数组个数
* @param {*} i 父节点
* @return {*}
* @author: ws
*/

const heapify = function (nums, n, i) {
    // 递归出口
    if (i >= n) {
        return;
    }
    // 先求出子节点
    let child1 = i * 2 + 1;
    let child2 = i * 2 + 2;
    // 设置哨兵,当前最大值序号
    let max = i;
    // 获取最大值序号,加一个判断条件,就是child1和child2是否存在
    if (child1<n && nums[child1] > nums[max]) {
        max = child1;
    }
    if (child2<n && nums[child2] > nums[max]) {
        max = child2;
    }
    if (max !== i) {
        // 做交换,此时这三个数就变成了一个堆结构
        [nums[max], nums[i]] = [nums[i], nums[max]];
        
        // 递归孩子
        heapify(nums, n, max);
    }
}

结果就会为这个样子

图片.png

经过这个过程以后,我们发现除了最后三个数为一个大顶堆以后,其他的都不是,那怎么办呢?

我们可以从叶子节点的父节点开始,倒序遍历每一个节点,让他们也都具有大顶堆的结构

所以

  • 第二步:从叶子节点的父节点开始,倒序遍历每一个节点,重复第一步的过程
const buildHeap = function (nums) {
    // 求最后一个节点的父节点
    let last_parent = Math.floor((nums.length - 1) / 2);
    const length = arr.length;
    // 倒序遍历
    for (let i = last_parent; i >= 0; i--){
        heapify(nums, length, i)
    }
}

堆排序

如何排序,其实就是把堆顶的数拿出来,和最后一个值交换,然后在heapify一次,保持是大顶堆,重复以上过程

const heapSort = function (nums) {
    let length = nums.length;
    buildHeap(nums);
    // 从最后一个数开始交换
    for (let i = length - 1; i >= 0; i--){
        //和大顶堆的第一个数开始交换
        [nums[i], nums[0]] = [nums[0], nums[i]];
        heapify(nums, i, 0);
    }
}

参考