【JavaScript版数据结构与算法面向大厂面试】第十章 数据结构之“堆”

第十章 数据结构之“堆”

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;

};

10.6 堆总结

在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qiqizgl777/article/details/129161319