目录
第十章 数据结构之“堆”
10.1 堆简介
第K个最小元素
构建一个最大堆,步骤同上
10.2 JavaScript 实现:最小堆类
新建一个空堆类
class MinHeap{//新建一个类来存放堆数组
constructor() {
this.heap = [];//新建一个名为heap的数组,把它绑定到this上
}}
插入元素代码:
class MinHeap {
//1、新建一个类来存放堆数组
constructor() {
//2
this.heap = [];//3、新建一个名为heap的数组,把它绑定到this上
}
swap(i1, i2) {
//12、实现交换方法
var temp = this.heap[i1];//声明一个临时变量来存i1的值
this.heap[i1] = this.heap[i2];
this.heap[i2] = temp;
}
getParentIndex(i) {
//8、拿到这个值的父节点
return (i - 1) >> 1;//9、法一:二进制方法
// return Math.floor((i - 1) / 2); 法二
}
shiftUp(index) {
//7、实现shiftUp()方法
//不停的和父节点交换,直到父节点小于它的子节点
if (index == 0) {
return; }//14、如果上移的值等于堆顶,那就不用上移了
var parentIndex = this.getParentIndex(index);
if (this.heap[parentIndex] > this.heap[index]) {
//10、如果当前节点大于父节点,那么就需要交换
this.swap(parentIndex, index);//11、交换下标
this.shiftUp(parentIndex);//13、继续上移操作
}
}
insert(value) {
//4、插入方法:插入一个值
this.heap.push(value);//5、把这个值推入heap数组的最后一位
this.shiftUp(this.heap.length - 1);//6、封装一个shifUp(要上移的值的数组下标)方法,让值上移,
}
}
var h = new MinHeap();//15、声明一个变量h它等于实例化的最小堆
h.insert(3);//16、插入值3
h.insert(2);
h.insert(1);
删除堆顶代码:
class MinHeap {
//1、新建一个类来存放堆数组
constructor() {
//2
this.heap = [];//3、新建一个名为heap的数组,把它绑定到this上
}
swap(i1, i2) {
//12、实现交换方法
var temp = this.heap[i1];//声明一个临时变量来存i1的值
this.heap[i1] = this.heap[i2];
this.heap[i2] = temp;
}
getParentIndex(i) {
//8、拿到这个值的父节点
return (i - 1) >> 1;//9、法一:二进制方法
// return Math.floor((i - 1) / 2); 法二
}
getLeftIndex(i) {
//拿到当前节点的左节点
return i * 2 + 1;
}
getRightIndex(i) {
//拿到当前节点的右节点
return i * 2 + 2;
}
shiftUp(index) {
//7、实现shiftUp()方法
//不停的和父节点交换,直到父节点小于它的子节点
if (index == 0) {
return; }//14、如果上移的值等于堆顶,那就不用上移了
var parentIndex = this.getParentIndex(index);
if (this.heap[parentIndex] > this.heap[index]) {
//10、如果当前节点大于父节点,那么就需要交换
this.swap(parentIndex, index);//11、交换下标
this.shiftUp(parentIndex);//13、继续上移操作
}
}
shiftDown(index) {
//实现下移算法
var leftIndex = this.getLeftIndex(index);
var 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) {
//4、插入方法:插入一个值
this.heap.push(value);//5、把这个值推入heap数组的最后一位
this.shiftUp(this.heap.length - 1);//6、封装一个shifUp(要上移的值的数组下标)方法,让值上移,
}
pop() {
//下移方法操作
this.heap[0] = this.heap.pop();//把数组的最后一位转移到数组的头部
this.shiftDown(0);//this.shiftDown(“要下元素的数组下标“)把头部元素进行下移操作
}
}
var h = new MinHeap();//15、声明一个变量h它等于实例化的最小堆
h.insert(3);//16、插入值3
h.insert(2);
h.insert(1);
h.pop();//调用移除方法
class MinHeap {
//1、新建一个类来存放堆数组
constructor() {
//2
this.heap = [];//3、新建一个名为heap的数组,把它绑定到this上
}
swap(i1, i2) {
//12、实现交换方法
var temp = this.heap[i1];//声明一个临时变量来存i1的值
this.heap[i1] = this.heap[i2];
this.heap[i2] = temp;
}
getParentIndex(i) {
//8、拿到这个值的父节点
return (i - 1) >> 1;//9、法一:二进制方法
// return Math.floor((i - 1) / 2); 法二
}
getLeftIndex(i) {
//拿到当前节点的左节点
return i * 2 + 1;
}
getRightIndex(i) {
//拿到当前节点的右节点
return i * 2 + 2;
}
shiftUp(index) {
//7、实现shiftUp()方法
//不停的和父节点交换,直到父节点小于它的子节点
if (index == 0) {
return; }//14、如果上移的值等于堆顶,那就不用上移了
var parentIndex = this.getParentIndex(index);
if (this.heap[parentIndex] > this.heap[index]) {
//10、如果当前节点大于父节点,那么就需要交换
this.swap(parentIndex, index);//11、交换下标
this.shiftUp(parentIndex);//13、继续上移操作
}
}
shiftDown(index) {
//实现下移算法
var leftIndex = this.getLeftIndex(index);
var 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) {
//4、插入方法:插入一个值
this.heap.push(value);//5、把这个值推入heap数组的最后一位
this.shiftUp(this.heap.length - 1);//6、封装一个shifUp(要上移的值的数组下标)方法,让值上移,
}
pop() {
//下移方法操作
this.heap[0] = this.heap.pop();//把数组的最后一位转移到数组的头部
this.shiftDown(0);//this.shiftDown(“要下元素的数组下标“)把头部元素进行下移操作
}
peek(){
//获取堆顶
return this.heap[0];
}
size(){
//获取堆的大小
return this.heap.length;
}
}
10.3 LeetCode:3215. 数组中的第K个最大元素
代码实现:
class MinHeap {
//1、新建一个类来存放堆数组
constructor() {
//2
this.heap = [];//3、新建一个名为heap的数组,把它绑定到this上
}
swap(i1, i2) {
//12、实现交换方法
var temp = this.heap[i1];//声明一个临时变量来存i1的值
this.heap[i1] = this.heap[i2];
this.heap[i2] = temp;
}
getParentIndex(i) {
//8、拿到这个值的父节点
return (i - 1) >> 1;//9、法一:二进制方法
// return Math.floor((i - 1) / 2); 法二
}
getLeftIndex(i) {
//拿到当前节点的左节点
return i * 2 + 1;
}
getRightIndex(i) {
//拿到当前节点的右节点
return i * 2 + 2;
}
shiftUp(index) {
//7、实现shiftUp()方法
//不停的和父节点交换,直到父节点小于它的子节点
if (index == 0) {
return; }//14、如果上移的值等于堆顶,那就不用上移了
var parentIndex = this.getParentIndex(index);
if (this.heap[parentIndex] > this.heap[index]) {
//10、如果当前节点大于父节点,那么就需要交换
this.swap(parentIndex, index);//11、交换下标
this.shiftUp(parentIndex);//13、继续上移操作
}
}
shiftDown(index) {
//实现下移算法
var leftIndex = this.getLeftIndex(index);
var 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) {
//4、插入方法:插入一个值
this.heap.push(value);//5、把这个值推入heap数组的最后一位
this.shiftUp(this.heap.length - 1);//6、封装一个shifUp(要上移的值的数组下标)方法,让值上移,
}
pop() {
//下移方法操作
this.heap[0] = this.heap.pop();//把数组的最后一位转移到数组的头部
this.shiftDown(0);//this.shiftDown(“要下元素的数组下标“)把头部元素进行下移操作
}
peek(){
return this.heap[0];
}
size(){
return this.heap.length;
}
}
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var findKthLargest = function(nums, k) {
var h =new MinHeap();
nums.forEach(n=>{
//
h.insert(n);
if(h.size()> k){
h.pop();
}
});
return h.peek();
};
10.4 LeetCode:347. 前K个高频元素
代码实现:
class MinHeap {
//1、新建一个类来存放堆数组
constructor() {
//2
this.heap = [];//3、新建一个名为heap的数组,把它绑定到this上
}
swap(i1, i2) {
//12、实现交换方法
var temp = this.heap[i1];//声明一个临时变量来存i1的值
this.heap[i1] = this.heap[i2];
this.heap[i2] = temp;
}
getParentIndex(i) {
//8、拿到这个值的父节点
return (i - 1) >> 1;//9、法一:二进制方法
// return Math.floor((i - 1) / 2); 法二
}
getLeftIndex(i) {
//拿到当前节点的左节点
return i * 2 + 1;
}
getRightIndex(i) {
//拿到当前节点的右节点
return i * 2 + 2;
}
shiftUp(index) {
//7、实现shiftUp()方法
//不停的和父节点交换,直到父节点小于它的子节点
if (index == 0) {
return; }//14、如果上移的值等于堆顶,那就不用上移了
var parentIndex = this.getParentIndex(index);
if (this.heap[parentIndex]&& this.heap[parentIndex].value > this.heap[index].value) {
this.swap(parentIndex, index);//11、交换下标
this.shiftUp(parentIndex);//13、继续上移操作
}
}
shiftDown(index) {
//实现下移算法
var leftIndex = this.getLeftIndex(index);
var 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) {
//4、插入方法:插入一个值
this.heap.push(value);//5、把这个值推入heap数组的最后一位
this.shiftUp(this.heap.length - 1);//6、封装一个shifUp(要上移的值的数组下标)方法,让值上移,
}
pop() {
//下移方法操作
this.heap[0] = this.heap.pop();//把数组的最后一位转移到数组的头部
this.shiftDown(0);//this.shiftDown(“要下元素的数组下标“)把头部元素进行下移操作
}
peek(){
return this.heap[0];
}
size(){
return this.heap.length;
}
}
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function(nums, k) {
var map = new Map();
nums.forEach(n=>{
map.set(n,map.has(n)?map.get(n)+1:1);
});
var h= new MinHeap();
map.forEach((value,key)=>{
h.insert({
value,key});
if(h.size()>k){
h.pop();
}
});
return h.heap.map(a=>a.key);
};
10.5 LeetCode:23. 合并K个排序链表
代码实现:
class MinHeap {
//1、新建一个类来存放堆数组
constructor() {
//2
this.heap = [];//3、新建一个名为heap的数组,把它绑定到this上
}
swap(i1, i2) {
//12、实现交换方法
var temp = this.heap[i1];//声明一个临时变量来存i1的值
this.heap[i1] = this.heap[i2];
this.heap[i2] = temp;
}
getParentIndex(i) {
//8、拿到这个值的父节点
return (i - 1) >> 1;//9、法一:二进制方法
// return Math.floor((i - 1) / 2); 法二
}
getLeftIndex(i) {
//拿到当前节点的左节点
return i * 2 + 1;
}
getRightIndex(i) {
//拿到当前节点的右节点
return i * 2 + 2;
}
shiftUp(index) {
//7、实现shiftUp()方法
//不停的和父节点交换,直到父节点小于它的子节点
if (index == 0) {
return; }//14、如果上移的值等于堆顶,那就不用上移了
var parentIndex = this.getParentIndex(index);
if (this.heap[parentIndex] && this.heap[parentIndex].val > this.heap[index].val) {
this.swap(parentIndex, index);//11、交换下标
this.shiftUp(parentIndex);//13、继续上移操作
}
}
shiftDown(index) {
//实现下移算法
var leftIndex = this.getLeftIndex(index);
var 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) {
//4、插入方法:插入一个值
this.heap.push(value);//5、把这个值推入heap数组的最后一位
this.shiftUp(this.heap.length - 1);//6、封装一个shifUp(要上移的值的数组下标)方法,让值上移,
}
pop() {
//下移方法操作
this.heap[0] = this.heap.pop();//把数组的最后一位转移到数组的头部
this.shiftDown(0);//this.shiftDown(“要下元素的数组下标“)把头部元素进行下移操作
}
peek(){
if(this.size() === 1) return this.heap.shift();
return 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}
*/
var mergeKLists = function(lists) {
var res = new ListNode(0);
let p = res;
var h = new MinHeap();
lists.forEach(l => {
if(l) h.insert(l);
});
while (h.size()){
var n = h.pop();
p.next = n;
p = p.next;
if(n.next) h.insert(n.next);
}
return res.next;
};