❤️ 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 + 1
var rightIdx = idx * 2 + 2
var 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名」的原创文章