数据结构之“堆”

  • 堆是什么?
  • JS中的堆
  • 堆的应用
  • 第K个最大元素
  • LeetCode:215.数组中的第K个最大元素
  • LeetCode:347.前K个高频元素
  • LeetCode:23.合并K个排序链表
  • 思考题

堆是什么?


堆是一种特殊的完全二叉树
所有的节点都大于等于(最大堆)或小于等于(最小堆)它的子节点

JS中的堆

JS中通常用数组表示堆
左侧子节点的位置是2 * index + 1
右侧子节点的位置是2 * index + 2
父节点位置是( index - 1 ) / 2

堆的应用

堆能高效、快速地找出最大值和最小值,时间复杂度:O(1)
找出第K个最大(最小)元素

第K个最大元素

构建一个最小堆,并将元素依次插入堆中
当堆的容量超过K,就删除堆顶
插入结束后,堆顶就是第K个最大元素

实现步骤
在类里,生命一个数组,用来装元素
主要方法:插入、删除堆顶、获取堆顶、获取堆大小
插入
将值插入堆的底部,即数组的尾部
然后上移:将这个值和它的父节点进行交换,直到父节点小于等于这个插入的值
大小为k的堆中插入元素的时间复杂度为O(logk)
删除堆顶
用数组尾部元素替换堆顶(直接删除堆顶会破坏堆结构)
然后下移:将新堆顶和它的子节点进行交换,直到子节点大于等于这个新堆顶
大小为k的堆中删除堆顶的时间复杂度为O(logk)
获取堆顶和堆的大小
获取堆顶:返回数组的头部
获取堆的大小:返回数组的长度

class MinHeap {constructor() {this.heap = [];}swap(i1, i2) {const temp = this.heap[i1];this.heap[i1] = this.heap[i2];this.heap[i2] = temp;}getParentIndex(i) {//return Math.floor((i - 1) / 2);return (i - 1) >> 1;}getLeftIndex(i) {return i * 2 + 1;}getRightIndex(i) {return i * 2 + 2;}shiftUp(index) {if (index == 0) { return; }const parentIndex = this.getParentIndex(index);if (this.heap[parentIndex] > this.heap[index]) {this.swap(parentIndex, index);this.shiftUp(parentIndex);}}shiftDown(index) {const leftIndex = this.getLeftIndex(index);const rightIndex = this.getRightIndex(index);if (this.heap[leftIndex] < this.heap[index]) {this.swap(leftIndex, index);this.shiftDown(leftIndex);}if (this.heap[rightIndex] < this.heap[index]) {this.swap(rightIndex, index);this.shiftDown(rightIndex);}}//插入insert(value) {this.heap.push(value);this.shiftUp(this.heap.length - 1);}//删除堆顶pop() {this.heap[0] = this.heap.pop();this.shiftDown(0);}//获取堆顶peek() {return this.heap[0];}//获取堆的大小size() {return this.heap.length;}
}const h = new MinHeap();
h.insert(3);
h.insert(2);
h.insert(1);
h.pop();

LeetCode:215.数组中的第K个最大元素

解题思路
看到“第K个最大元素”
考虑选择使用最小堆
解题步骤
构建一个最小堆,并依次把数组的值插入堆中
当堆的容量超过K,就删除堆顶
插入结束后,堆顶就是第K个最大元素

时间复杂度O(n * logk),空间复杂度O(k)

LeetCode:347.前K个高频元素


法一:

时间复杂度O(n * logn)

法二

class MinHeap {constructor() {this.heap = [];}swap(i1, i2) {const temp = this.heap[i1];this.heap[i1] = this.heap[i2];this.heap[i2] = temp;}getParentIndex(i) {//return Math.floor((i - 1) / 2);return (i - 1) >> 1;}getLeftIndex(i) {return i * 2 + 1;}getRightIndex(i) {return i * 2 + 2;}shiftUp(index) {if (index == 0) { return; }const parentIndex = this.getParentIndex(index);if (this.heap[parentIndex] && this.heap[parentIndex].value > this.heap[index].value) {this.swap(parentIndex, index);this.shiftUp(parentIndex);}}shiftDown(index) {const leftIndex = this.getLeftIndex(index);const rightIndex = this.getRightIndex(index);if (this.heap[leftIndex] && this.heap[leftIndex].value < this.heap[index].value) {this.swap(leftIndex, index);this.shiftDown(leftIndex);}if (this.heap[rightIndex] && this.heap[rightIndex].value < this.heap[index].value) {this.swap(rightIndex, index);this.shiftDown(rightIndex);}}//插入insert(value) {this.heap.push(value);this.shiftUp(this.heap.length - 1);}//删除堆顶pop() {this.heap[0] = this.heap.pop();this.shiftDown(0);}//获取堆顶peek() {return this.heap[0];}//获取堆的大小size() {return this.heap.length;}
}

时间O(n * logk),空间O(n)

LeetCode:23.合并K个排序链表


解题思路
新链表的下一个节点一定是k个链表头中的最小节点
考虑选择使用最小堆
解题步骤
构建一个最小堆,并依次把链表头插入堆中
弹出堆顶接到输出链表,并将堆顶所在链表的新链表头插入堆中
等堆元素全部弹出,合并工作就完成了

class MinHeap {constructor() {this.heap = [];}swap(i1, i2) {const temp = this.heap[i1];this.heap[i1] = this.heap[i2];this.heap[i2] = temp;}getParentIndex(i) {//return Math.floor((i - 1) / 2);return (i - 1) >> 1;}getLeftIndex(i) {return i * 2 + 1;}getRightIndex(i) {return i * 2 + 2;}shiftUp(index) {if (index == 0) { return; }const parentIndex = this.getParentIndex(index);if (this.heap[parentIndex] && this.heap[parentIndex].val> this.heap[index].val) {this.swap(parentIndex, index);this.shiftUp(parentIndex);}}shiftDown(index) {const leftIndex = this.getLeftIndex(index);const rightIndex = this.getRightIndex(index);if (this.heap[leftIndex] && this.heap[leftIndex].val< this.heap[index].val) {this.swap(leftIndex, index);this.shiftDown(leftIndex);}if (this.heap[rightIndex] && this.heap[rightIndex].val< this.heap[index].val) {this.swap(rightIndex, index);this.shiftDown(rightIndex);}}//插入insert(value) {this.heap.push(value);this.shiftUp(this.heap.length - 1);}//删除堆顶pop() {if(this.size() === 1) return this.heap.shift();const top =  this.heap[0]this.heap[0] = this.heap.pop();this.shiftDown(0);return top;}//获取堆顶peek() {return this.heap[0];}//获取堆的大小size() {return this.heap.length;}
}


时间复杂度O(n * logk),n是所有链表的节点数之和,k是排序链表数,空间复杂度是O(k)

思考题

1、请用堆画出一场比赛的运动员排名情况,无需 Coding。
2、在 LeetCode 找到一道堆的题目,并通过测试

(十)数据结构之“堆”相关推荐

  1. 算法(4)数据结构:堆

    1.0 问题描述 实现数据结构:堆. 2.0 问题分析 堆一般使用数组来表示,其中某个节点下标i的两个子节点的下标为 2i+1 和 2i+2.堆是一棵完全二叉树. 堆有3种基本操作:创建,插入,删除. ...

  2. 数据结构,堆和栈和队列的概念

    数据结构,堆和栈和队列的概念 1 什么是数据结构 数据结构是计算机存储,组织数据的反复改.数据结构是指相互之间存在的一种或多种特定关系的数据元素集合. 2 数据结构的逻辑结构 1 集合结构,元素都是孤 ...

  3. 数据结构之堆的插入、取值、排序(细致讲解+图片演示)

    数据结构之堆(Heap):插入.取值.排序. 堆是一种数据结构,分为最小堆和最大堆,可以用二叉树来表示. 在二叉树的任意的一个三角结构中(一个父节点,两个子节点),需要满足以下两个条件: 1.父节点要 ...

  4. 【数据结构】堆、堆排序笔记

    [数据结构]堆.堆排序笔记 堆是一棵完全二叉树,树的每个结点的值都不小于(或者不大于)其左右孩子的值. 父亲结点大于等于孩子结点的值叫做大顶堆,反之叫做小顶堆 大顶堆的每个结点的值都是以它为根结点的子 ...

  5. 【数据结构】堆的实现

    [数据结构]堆--完全二叉树顺序存储实现 "我想要现实的真相和爱的幻想,做成精神的房梁,敷脊背的伤." --<我想要> ✨✨

  6. 数据结构:堆(Heap)

    堆就是用数组实现的二叉树,所有它没有使用父指针或者子指针.堆根据"堆属性"来排序,"堆属性"决定了树中节点的位置. 堆的常用方法: 构建优先队列 支持堆排序 快 ...

  7. 数据结构之堆Heap

    1. 概述 堆(也叫优先队列),是一棵完全二叉树,它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆).它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等. 2. 堆 ...

  8. 十四、堆(Heap)

    0. 堆(Heap) 堆排序是一种原地的.时间复杂度为O(nlogn)的排序算法. 引入:快速排序平均情况下,时间复杂度为O(nlogn),甚至堆排序比快速排序的时间复杂度还要稳定,但在实际中,快排性 ...

  9. codeforces 贪心+优先队列_算法与数据结构基础 - 堆(Heap)和优先级队列(Priority Queue)...

    堆基础 堆(Heap)是具有这样性质的数据结构:1/完全二叉树 2/所有节点的值大于等于(或小于等于)子节点的值:

最新文章

  1. [C#] 查标准正态分布表
  2. 谷歌浏览器禁止右滑返回历史_移动端h5禁用浏览器左滑右滑的前进后退功能
  3. vue-ueditor 后端配置项没有正常加载_当运营商遇上极简流畅的产商品配置体验
  4. Docker私有仓库搭建与配置
  5. 利用oc门或od门实现线与_景县专业门球场专用人造草坪甄选博翔远
  6. 计组之中央处理器:1、CPU的功能和基本结构
  7. CSS3动画 - title下划线的拉伸效果
  8. 10分钟教你用VS2017将代码上传到GitHub
  9. springboot做网站_Github点赞接近 100k 的Spring Boot学习教程+实战项目推荐!
  10. 查看mysql半杯_如何通过show slave status的输出使用change master to命令 | 半瓶
  11. (转)ETL利器Kettle实战应用解析系列一【Kettle使用介绍】
  12. phpdesigner8 php7.0,让getter和setter在phpDesigner8中运行
  13. ps3手柄在linux ubuntu 下的使用
  14. 精心收集17套电子课件
  15. 个人怎么开发APP?APP开发全流程解析!
  16. Flutter的原理及美团的实践(下,100%好评
  17. hansontable编辑器
  18. 爱一个人,爱到八分最相宜
  19. SQL获取某月第一天或最后一天
  20. 使用U盘安装Linux系统经验总结

热门文章

  1. Python爬虫大杀器之Requests快速入门
  2. 深入理解Spark 2.1 Core (四):运算结果处理和容错的原理与源码分析
  3. 自然语言处理-nltk学习(一)
  4. 步步深入MySQL:架构-查询执行流程-SQL解析顺序
  5. Spark Java API:broadcast、accumulator
  6. 在Dubbo中使用高效的Java序列化(Kryo和FST)
  7. Java多线程(十)之ReentrantReadWriteLock深入分析
  8. 如何利用TensorFlow.js部署简单AI版「你画我猜」
  9. leetcode-python-优先级队列与时间复杂度
  10. 使用反射代理类加载器的潜在内存使用问题