堆是一种特殊的完全二叉树。除了最后一层必须填满,最后一层可以不填满
- 所有节点都大于等于(最大堆)或者小于等于它的子节点 (最小堆)
- js中使用数组表示堆

- 左侧子节点的位置是2 * index + 1
- 右侧子节点的位置是2 * index + 2
- 父节点的位置是 Math.floor((index - 1) /2 )
应用
- 堆能高效快速的查找出最大值最小值。时间复杂度为O(n)
- 找出第K个最大(小)值
算法
第k个最大元素(leetcode 215)
时间复杂度O(n * logk)
空间复杂度O(k)
- 构建一个最小堆,并将元素一次插入堆中
- 当堆的容量超过k,就删除堆顶
插入结束后,堆顶就是第k个最大元素 ```javascript class MinHeap{ constructor(){
this.heap = []
}
getParentIndex(index) {
return Math.floor((index - 1) / 2)
}
insert(value){
this.heap.push(value)this.shiftUp(this.heap.length - 1)
}
swap(i1, i2) {
const temp = this.heap[i1]this.heap[i1] = this.heap[i2]this.heap[i2] = temp
}
shiftUp(index) {
if(index === 0 ) returnconst parentIndex = this.getParentIndex(index)if(this.heap[parentIndex] > this.heap[index]) {this.swap(parentIndex, index)this.shiftUp(parentIndex)}
}
getLeftIndex(index) {
return index * 2 + 1
}
getRightIndex(index) {
return index * 2 + 2
}
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)}
}
pop(){
this.heap[0] = this.heap.pop()this.shiftDown(0)
}
peek(){
return this.heap[0]
}
size(){
return this.heap.length
} }
/**
- @param {number[]} nums
- @param {number} k
- @return {number}
*/
var findKthLargest = function(nums, k) {
const minHeap = new MinHeap()
nums.forEach(item=>{
}) console.log(‘minP’, minHeap) return minHeap.peek() }; ```minHeap.insert(item)if(minHeap.size() > k) {minHeap.pop()}
前k个高频元素(leetcode 347)
```javascript /** - @param {number[]} nums
- @param {number} k
- @return {number[]}
时间复杂度O(n logn) / var topKFrequent = function(nums, k) { const map = new Map() nums.forEach(item=>{
map.set(item, map.has(item) ? map.get(item) + 1: 1)
}) const array = Array.from(map) // 原生排序算法最快时间复杂度O(n*logn) // 这里进行了全排序,所以时间复杂度较高,实际上不需要 array.sort((a, b ) => {
return b [1] - a[1]
}) return array.slice(0, k).map(item=>{
return item[0]
}) };
javascript class MinHeap{ constructor(){this.heap = []
}
getParentIndex(index){
return Math.floor((index - 1) / 2)
}
getLeftIndex(index){
return index * 2 + 1
}
getRightIndex(index){
return index * 2 + 2
}
insert(value){
this.heap.push(value)this.shiftUp(this.heap.length - 1)
}
swap(i1, i2) {
const temp = this.heap[i1]this.heap[i1] = this.heap[i2]this.heap[i2] = temp
}
shiftUp(index) {
if(index === 0 ) returnconst 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)}
}
pop(){
this.heap[0] = this.heap.pop()this.shiftDown(0)
} size(){
return this.heap.length
} }
/**
- @param {number[]} nums
- @param {number} k
- @return {number[]}
时间复杂度O(n logk) / var topKFrequent = function(nums, k) { const map = new Map() const minHeap = new MinHeap() nums.forEach(item=>{
map.set(item, map.has(item) ? map.get(item) + 1: 1)
})
// O(n) map.forEach((value, key) => {
//时间复杂度O(logk)minHeap.insert({value,key})//时间复杂度O(logk)if(minHeap.size() > k) {minHeap.pop()}
})
return minHeap.heap.map(item=>{
return item.key
合并k个排序链表(leetcode 23)
```javascript class MinHeap{ constructor(){
this.heap = []
}
getParentIndex(index){
return Math.floor((index - 1) / 2)
}
getLeftIndex(index){
return index * 2 + 1
}
getRightIndex(index){
return index * 2 + 2
}
insert(value){
this.heap.push(value)this.shiftUp(this.heap.length - 1)
}
swap(i1, i2) {
const temp = this.heap[i1]this.heap[i1] = this.heap[i2]this.heap[i2] = temp
}
shiftUp(index) {
if(index === 0 ) returnconst 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)}
}
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
}
size(){
return this.heap.length
} }
/**
- Definition for singly-linked list.
- function ListNode(val, next) {
- this.val = (val===undefined ? 0 : val)
- this.next = (next===undefined ? null : next)
- } / /*
- @param {ListNode[]} lists
- @return {ListNode}
- 时间复杂度O(n * logk)
- 时间复杂度O(k) h
*/
var mergeKLists = function(lists) {
const h = new MinHeap()
const res = new ListNode(0)
// 定义指针p
let p = res
lists.forEach(item => {
}) while(h.size()){if(item) h.insert(item);
} return res.next }; ```console.log(h)const n = h.pop()p.next = np = p.nextif(n.next) {h.insert(n.next)}
