前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • 前端算法面试

    • 快速上手——从0到1掌握算法面试需要的数据结构(一)
    • 快速上手——从0到1掌握算法面试需要的数据结构(二)
    • 快速上手——从0到1掌握算法面试需要的数据结构(三)
    • 递归初相见——二叉树递归遍历的三种姿势
    • 算法的衡量——轻松理解时间复杂度与空间复杂度
    • 数组的应用——真题归纳与解读
    • 字符串的应用——真题归纳与解读
    • 链表的应用——真题归纳与解读
    • 快慢指针与多指针——玩转链表复杂操作
    • 姿势特别的链表——环形链表专题
    • 栈与队列怎么玩(上)
    • 栈与队列怎么玩(下)
    • 遍历专题 DFS 与 BFS
    • 场景化解读递归与回溯思想在真题中的应用
    • 二叉树真题归纳与解读
    • 特殊的二叉树——二叉搜索树专题
    • 特殊的二叉树——平衡二叉树专题
    • 特殊的二叉树——堆结构及其在排序中的应用
      • 前置知识:完全二叉树
      • 什么是堆
      • 堆的基本操作:以大顶堆为例
        • 取出堆顶元素
        • 往堆里追加一个元素
      • 堆结构在排序中的应用——优先队列
      • 编码复盘
    • 排序算法专题(上)
    • 排序算法专题(下)
    • 普通人也能吃透的动态规划思想专题(上)
    • 普通人也能吃透的动态规划思想专题(下)
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

# 前置知识:完全二叉树

完全二叉树是指同时满足下面两个条件的二叉树:

  • 从第一层到倒数第二层,每一层都是满的,也就是说每一层的结点数都达到了当前层所能达到的最大值
  • 最后一层的结点是从左到右连续排列的,不存在跳跃排列的情况(也就是说这一层的所有结点都集中排列在最左边)。

完全二叉树可以是这样的:

也可以是这样的:

但不能是这样的:

更不能是这样的:

注意,完全二叉树中有着这样的索引规律:假如我们从左到右、从上到下依次对完全二叉树中的结点从0开始进行编码:

那么对于索引为 n 的结点来说:

  • 索引为 (n-1)/2 的结点是它的父结点
  • 索引 2*n+1 的结点是它的左孩子结点
  • 索为引 2*n+2 的结点是它的右孩子结点

# 什么是堆

堆是完全二叉树的一种特例。根据约束规则的不同,堆又分为两种:

  • 大顶堆
  • 小顶堆

如果对一棵完全二叉树来说,它每个结点的结点值都不小于其左右孩子的结点值,这样的完全二叉树就叫做“大顶堆”:

若树中每个结点值都不大于其左右孩子的结点值,这样的完全二叉树就叫做“小顶堆”

# 堆的基本操作:以大顶堆为例

大顶堆和小顶堆除了约束条件中的大小关系规则完全相反以外,其它方面都保持高度一致。现在我们以大顶堆为例,一起来看看堆结构有哪些玩法。

这里我给出一个现成的大顶堆:

很多时候,为了考察你对完全二叉树索引规律的掌握情况,题目中与堆结构同时出现的,还有它的层序遍历序列:

[9, 8, 6, 3, 1]
@前端进阶之旅: 代码已经复制到剪贴板

我们需要关注的动作有两个:

  • 如何取出堆顶元素(删除操作)
  • 往堆里追加一个元素(插入操作)

至于堆的初始化,也只不过是从空堆开始,重复执行动作2而已。因此,上面这两个动作就是堆操作的核心。

# 取出堆顶元素

取出元素本身并不难,难的是如何在删除元素的同时,保持住队的“大顶”结构特性。为了做到这点,我们需要执行以下操作:

  • 用堆里的最后一个元素(对应图中的数字1)替换掉堆顶元素。
  • 对比新的堆顶元素(1)与其左右孩子的值,如果其中一个孩子大于堆顶元素,则交换两者的位置:

交换后,继续向下对比1与当前左右孩子的值,如果其中一个大于1,则交换两者的位置:

重复这个向下对比+交换的过程,直到无法继续交换为止,我们就得到了一个符合“大顶”原则的新的堆结构:

上述这个反复向下对比+交换的过程,用编码实现如下(仔细看注释):

// 入参是堆元素在数组里的索引范围,low表示下界,high表示上界
function downHeap(low, high) {
    // 初始化 i 为当前结点,j 为当前结点的左孩子
    let i=low,j=i*2+1 
    // 当 j 不超过上界时,重复向下对比+交换的操作
    while(j <= high) {
        // 如果右孩子比左孩子更大,则用右孩子和根结点比较
        if(j+1 <= high && heap[j+1] > heap[j]) {
            j = j+1
        }
        
        // 若当前结点比孩子结点小,则交换两者的位置,把较大的结点“拱上去”
        if(heap[i] < heap[j]) {
            // 交换位置
            const temp = heap[j]  
            heap[j] = heap[i]  
            heap[i] = temp
            
            // i 更新为被交换的孩子结点的索引
            i=j  
            // j 更新为孩子结点的左孩子的索引
            j=j*2+1
        } else {
  
fe
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • 前端算法面试

    • 快速上手——从0到1掌握算法面试需要的数据结构(一)
    • 快速上手——从0到1掌握算法面试需要的数据结构(二)
    • 快速上手——从0到1掌握算法面试需要的数据结构(三)
    • 递归初相见——二叉树递归遍历的三种姿势
    • 算法的衡量——轻松理解时间复杂度与空间复杂度
    • 数组的应用——真题归纳与解读
    • 字符串的应用——真题归纳与解读
    • 链表的应用——真题归纳与解读
    • 快慢指针与多指针——玩转链表复杂操作
    • 姿势特别的链表——环形链表专题
    • 栈与队列怎么玩(上)
    • 栈与队列怎么玩(下)
    • 遍历专题 DFS 与 BFS
    • 场景化解读递归与回溯思想在真题中的应用
    • 二叉树真题归纳与解读
    • 特殊的二叉树——二叉搜索树专题
    • 特殊的二叉树——平衡二叉树专题
    • 特殊的二叉树——堆结构及其在排序中的应用
      • 前置知识:完全二叉树
      • 什么是堆
      • 堆的基本操作:以大顶堆为例
        • 取出堆顶元素
        • 往堆里追加一个元素
      • 堆结构在排序中的应用——优先队列
      • 编码复盘
    • 排序算法专题(上)
    • 排序算法专题(下)
    • 普通人也能吃透的动态规划思想专题(上)
    • 普通人也能吃透的动态规划思想专题(下)