JavaScript之堆排序

堆排序说起来比较抽象,所以我特地把它抽出来单独讲讲。但如果理解好了就会觉得很简单。
要实现堆排序我们得先要弄懂什么是完全二叉树和小顶堆、大顶堆的概念。这都是数据结构的基础的知识就不细讲了。

完成二叉树: 除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐。
在这里插入图片描述
大顶堆:每个结点的值都大于或等于其左右孩子结点的值。
小顶堆:每个结点的值都小于或等于其左右孩子结点的值。
在这里插入图片描述
我们直奔正题 堆排序。
堆排序:说简单点就是先构建好一个大顶堆,然后把根结点拿出来,将最后一个叶子结点替换上去再构建成一个大顶堆,再拿出根节点,然后把最后一个叶子结点替换上去,依次类推,直到只剩一个结点为止。(听上去好像还是很难理解,直接一步步说吧)

1.构建大顶堆
在这里插入图片描述
每次构建大顶堆都是从非叶子结点的最后一个结点开始。然后逐步向根节点构建。

 
2.堆排序
在这里插入图片描述
如果构建好大顶堆的话,实现堆排序可以说轻而易举,堆排序就是每次将大顶堆的根源是拿出来,然后将剩下的元素再构成大顶堆,直到剩下最后一个元素为止。如上图。

直接上代码吧,结合代码和上述描述更容易理解一点。

// 交换两个节点
function swap(A, i, j) {
    let temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}

// 将 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]) {
            swap(A, i, j) // 如果父节点小于子节点:交换;否则跳出
            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); //A 1 4
    }
    console.log(A);
    // 排序,每一次for循环找出一个当前最大值,数组长度减一
    for (let i = Math.floor(A.length - 1); i > 0; i--) {
        swap(A, 0, i); // 根节点与最后一个节点交换
        shiftDown(A, 0, i); // 从根节点开始调整,并且最后一个结点已经为当
        // 前最大值,不需要再参与比较,所以第三个参数
        // 为 i,即比较到最后一个结点前一个即可
    }
}

let Arr = [4, 6, 8, 5, 9, 1, 2, 5, 3, 2];
heapSort(Arr);
console.log(Arr);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值