【算法】堆,堆排序

news/2024/11/15 4:02:36/

❤️ Author: 老九
☕️ 个人博客:老九的CSDN博客
🙏 个人名言:不可控之事 乐观面对
😍 系列专栏:

文章目录

  • 堆(优先队列)
    • 删除堆顶元素并调整堆中元素的位置的代码
    • 向堆中添加元素
    • 数组的堆化
    • 堆排序
    • 构造大顶堆类

堆(优先队列)

  • 堆可以用来排序,还可以用来解决“最值问题”,可以高效的处理动态集合的最值问题,这样就解决了排序的缺点。
  • 堆是一颗完全二叉树,且这颗树中,节点之间也有顺序,顺序:任何一个结点都比其两个子节点的值要大于等于,类比于BST中,左子树所有结点比根节点大,根节点比右子树中所有结点大
  • 由于它是一棵完全二叉树的特性,它一般是使用简单数据的形式进行存储,这样存储不会浪费一点空间,同时也依然很容易根据一个元素找到其父元素或子元素

删除堆顶元素并调整堆中元素的位置的代码

//从heap中删除堆顶元素并返回
//同时调整它让它继续满足堆的性质
//heap是一个数组
function 删除堆顶元素(heap) {if(heap.length <= 1{return heap.pop()}var result = heap[0]; // 取出堆定元素heap[0] = heap.pop(); // 将末尾元素放入堆定var idx = 0;while (true) {var leftIdx = idx * 2 + 1;var rightIdx = idx * 2 + 2;var maxIdx = idx; //先假设此时的根元素是最大的//左子结点存在并且大于当前最大元素if (leftIdx < heap.length && heap[leftIdx] > heap[maxIdx]) {maxIdx = leftIdx;}//右结点存在并且大于当前最大元素if (rightIdx < heap.length && heap[rightIdx] > heap[maxIdx]) {maxIdx = rightIdx;}if (maxIdx !== idx) {swap(heap, maxIdx, idx);idx = maxIdx; //从末尾上来的元素换到了哪里,哪里就是新的焦点} else {break;}}return result;
}function swap(array, i, j) {var t = array[i];array[i] = array[j];array[j] = t;
}

向堆中添加元素

function swap(array, i, j) {var t = array[i];array[i] = array[j];array[j] = t;
}function 向堆中添加元素(heap, val) {heap.push(val);heapUp(heap, heap.length - 1);return heap;
}function heapUp(heap, idx) {//除2取整while (idx > 0) {//计算出焦点元素父节点的位置var pIdx = (idx - 1) >> 1;if (heap[pIdx] < heap[idx]) {swap(heap, pIdx, idx);idx = pIdx;} else {break;}}
}

数组的堆化

function swap(array, i, j) {var t = array[i];array[i] = array[j];array[j] = t;
}
function heapDown(heap, idx) {while (true) {var leftIdx = idx * 2 + 1;var rightIdx = idx * 2 + 2;var maxIdx = idx; //先假设此时的根元素是最大的//左子结点存在并且大于当前最大元素if (leftIdx < heap.length && heap[leftIdx] > heap[maxIdx]) {maxIdx = leftIdx;}//右结点存在并且大于当前最大元素if (rightIdx < heap.length && heap[rightIdx] > heap[maxIdx]) {maxIdx = rightIdx;}if (maxIdx !== idx) {swap(heap, maxIdx, idx);idx = maxIdx; //从末尾上来的元素换到了哪里,哪里就是新的焦点} else {break;}}
}function heapify(array) {for (var i = array.length - 1; i >= 0; i--) {heapDown(array, i);}return array;
}

堆排序

  • 空间复杂度1,时间复杂度n * log(n)
function swap(array, i, j) {var t = array[i];array[i] = array[j];array[j] = t;
}
//最多调整到stop位置,不包含stop位置
function heapDown(heap, idx, stop = heap.length) {while (true) {var leftIdx = idx * 2 + 1;var rightIdx = idx * 2 + 2;var maxIdx = idx; //先假设此时的根元素是最大的//左子结点存在并且大于当前最大元素if (leftIdx < stop && heap[leftIdx] > heap[maxIdx]) {maxIdx = leftIdx;}//右结点存在并且大于当前最大元素if (rightIdx < stop && heap[rightIdx] > heap[maxIdx]) {maxIdx = rightIdx;}if (maxIdx !== idx) {swap(heap, maxIdx, idx);idx = maxIdx; //从末尾上来的元素换到了哪里,哪里就是新的焦点} else {break;}}
}
function heapify(array) {for (var i = array.length - 1; i >= 0; i--) {heapDown(array, i);}return array;
}
function heapSort(array) {heapify(array); for (var i = array.length - 1; i > 0; i--) {swap(array, i, 0);heapDown(array, 0, i);}return array;
}

构造大顶堆类

class PriorityQueue {constructor(init = []) {this.heap = []for (var item of init) {this.heap.push(item)}this.heapify()}heapify() {for (var i = (this.heap.length - 2) >> 1; i >= 0; i--) {this.heapDown(i)}return this}swap(array, i, j) {if (i !== j) {var t = array[i]array[i] = array[j]array[j] = t}}// 从堆heap中删除零顶元素并返回// 同时调整它让它继续满足堆的性质remove() {if (this.heap.length <= 1) {return this.heap.pop()}var result = this.heap[0] // 取出堆顶元素this.heap[0] = this.heap.pop() // 将末尾元素放入堆顶this.heapDown(0)return result}add(val) {this.heap.push(val)this.heapUp(this.heap.length - 1)return this}heapUp(idx) {while (idx > 0) {var pIdx = (idx - 1) >> 1 // 计算出焦点的父元素位置if (this.heap[pIdx] < this.heap[idx]) {this.swap(this.heap, pIdx, idx)idx = pIdx} else {break}}}// 从idx位置开始向下调整heapDown(idx) {while (true) {var leftIdx = idx * 2 + 1var rightIdx = idx * 2 + 2var maxIdx = idx // 先假设此时的根元素是最大的// 左子结点存在并且大于当前当前最大元素if (leftIdx < this.heap.length && this.heap[leftIdx] > this.heap[maxIdx]) {maxIdx = leftIdx}// 右子结点存在并且大于当前当前最大元素if (rightIdx < this.heap.length && this.heap[rightIdx] > this.heap[maxIdx]) {maxIdx = rightIdx}if (maxIdx !== idx) {this.swap(this.heap, maxIdx, idx)idx = maxIdx // 从末尾上来的元素换到了哪里,哪里就是新的焦点} else {break}}}}

————————————————————————
♥♥♥码字不易,大家的支持就是我坚持下去的动力♥♥♥
版权声明:本文为CSDN博主「亚太地区百大最帅面孔第101名」的原创文章


http://www.ppmy.cn/news/94285.html

相关文章

接口测试-Mock测试方法

一、关于Mock测试 1、什么是Mock测试&#xff1f; Mock 测试就是在测试过程中&#xff0c;对于某些不容易构造&#xff08;如 HttpServletRequest 必须在Servlet 容器中才能构造出来&#xff09;或者不容易获取的比较复杂的对象&#xff08;如 JDBC 中的ResultSet 对象&#…

低资源大语言模型LLM研究者的希望 LIMA + 4Bit 量化训练

人类的大模型炼丹可能也遵从2/8规则&#xff0c;RLHF训练能增强20%的大模型响应能力但是需要花费额外80%的训练成本。 LIMA模型的研究 &#xff08;https://arxiv.org/abs/2305.11206&#xff09;给大家指明了可能的低资源条件下大模型研究方向&#xff0c;概括起来就是以下几…

21天学会C++:Day5----引用

CSDN的uu们&#xff0c;大家好。这里是C入门的第五讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 知识引入 2. 引用的特性 2.1 引用在定义时必须初始化 2.2 一个变量可以有多…

NoSQL之Redis高可用与优化

目录 一、Redis高可用二、Redis 持久化2.1 Redis 提供两种方式进行持久化2.2 RDB持久化2.2-1 触发条件2.2-2 执行流程2.2-3 启动时加载 2.3 AOF 持久化2.3.1 开启AOF2.3.2 执行流程2.3.3 执行流程启动时加载 三、RDB和AOF的优缺点四、Redis 性能管理4.1 查看Redis内存使用4.2 内…

ONNX模型修改为自定义节点

参考一 首先&#xff0c;需要将ONNX模型中的节点修改为自定义节点。要实现这一点&#xff0c;您需要了解自定义节点的定义和如何在ONNX中使用它们。ONNX定义了一个自定义运算符的接口&#xff0c;您可以使用该接口定义自己的运算符&#xff0c;并将其编译为ONNX模型可以识别的…

java基础入门-13-【集合(List集合)】

Java基础入门-13-【集合(List集合)】 22、集合(List集合)1.Collection集合1.1 数组和集合的区别【理解】1.2 集合类体系结构【理解】1.3 Collection 集合概述和使用【应用】Collection集合概述Collection集合常用方法代码书写1.4 Collection集合的遍历【应用】迭代器介绍Co…

设置linux的时间

目录 一、什么是时间 &#xff08;1&#xff09;例子1 &#xff08;2&#xff09;例子2 二、什么是本地时间 三、linux设置本地时间的方法 &#xff08;1&#xff09;方式一&#xff1a;通过互联网自动同步 1.修改时间同步服务器 2.查看时间同步情况 &#xff08;2&…

Spring的作用域和生命周期

目录 1.Bean的作用域 2.Bean的作用域的分类 3.设置作用域 4.Spring的执行流程&#xff08;生命周期&#xff09; 5.Bean的生命周期 1.Bean的作用域 lombok &#xff08;dependency依赖&#xff09; 是为了解决代码的冗余&#xff08;比如说get和set方法&#xff09;那些构造…