js数据结构基础,封装最小堆和最大堆

是什么

要封装这两个数据结构,首先要搞明白他们是什么,有什么特点

不管是最小堆还是最大堆,他们都是二叉树的衍生,在二叉树之上

他们在结构上要求每组节点都必须完整,即父节点必须存在左右两个子节点,除了最后一组,即最下层的最右侧的一组节点,可以只存在左节点,并且必须是左节点

数据上,最大堆要求父节点的key一定要大于等于子节点,最小堆则相反

最大堆和最小堆广泛运用于堆排序算法中,在求最大最小值时,效率比较高

具体封装---最小堆

之前我封装二叉搜索树时,使用的是链表形式的主体,通过left和right指针来查询子节点, 现在我们换一种方式,用数组来存储最小最大堆

我们给每个节点按从左到右,从上到下的顺序排序,就可以得到一个一维的数组,且每个节点的角标,都有规律可循 ,既然如此,能否将整个树结构转化为一维的数组,通过函数查询每个节点的子节点,最重要的是在插入和删除时,js的数组可以直接用index查找到对应元素,这完美满足的我们的需求!

获取节点角标

首先,我们封装最重要的基础方法,用来查询节点的父 / 左 / 右节点

左节点 = 当前节点角标 * 2 + 1 右节点 = 当前节点角标 * 2 + 2 父节点 = (当前节点角标 + 1) / 2

javascript 复制代码
    class MinHeep {
        constructor() {
            this.heep = []
        }

        getLeftIndex(index) {
            return (index * 2) + 1
        }

        getRightIndex(index) {
            return (index * 2) + 2
        }

        getParentIndex(index) {
            return Matn.floor((index - 1) / 2)
        }
    }

封装简单的基本方法

封一下size和isEmpty,方便使用,顺便假装一下私有属性

javascript 复制代码
        isEmpty() {
            return this.heep.length === 0
        }

        size() {
            return this.heep.length
        }

封装插入方法

在插入最小堆时,我们需要明确,怎么样插入才能保证最小堆的结构和数据性质保持不变呢?我的方法是,通过将节点插入到数组的末尾,即最后一个子节点的位置,在对比它的父节点,如果父节点大于插入节点的值,则将两者交换位置

kotlin 复制代码
        insert(item) {
            if(!item && item !== 0) return
                // 将插入值放到最后
                this.heep.push(item)
                let index = this.heep.length - 1
                this.shiftUP(index)
        }

        shiftUP(index) {
            let parentIndex = this.getParentIndex(index)
            // 当插入元素所在角标大于0且其值小于它父节点的值时,交换他两的位置
            while(index > 0 && this.heep[index] < this.heep[parentIndex]) {
                this.swap(this.heep, index, parentIndex)
                index = parentIndex
                parentIndex = this.getParentIndex(index)
            }
        }

        swap(arr, a, b) {
            let temp = arr[a]
            arr[a] = arr[b]
            arr[b] = temp
        }

封装弹出方法

封装弹出方法,即将数组的第一个元素,堆的根节点删除,并返回,最后对堆进行重新排序

我选择的排序方法是,将最后一个节点放在根节点上,然后向下查询,拿到该节点 / 左节点 / 右节点中最小的那个,如果根节点最小,则满足最小堆性质要求,结束排序,如果是左或右节点最小,则让最小的与该节点交换位置,直到该节点最小或者该节点的子节点为空

kotlin 复制代码
        extract() {
            if(this.isEmpty()) return
            if(this.size() === 1) return this.heep.pop()
            else {
                const m = this.heep[0]
                this.heep[0] = this.heep.pop()
                this.shiftDown(0)
                return m
            }
        }

        shiftDown(index) {
            let left = this.getLeftIndex(index)
            let right = this.getRightIndex(index)
            let min = index
            while(min < this.size()) {
                if(left < this.size() && this.heep[min] > this.heep[left]) {
                    min = left
                }
                if(right < this.size() && this.heep[min] > this.heep[right]) {
                    min = right
                }
                if(index !== min) {
                    this.swap(this.heep, min, index)
                    index = min
                    left = this.getLeftIndex(index)
                    right = this.getRightIndex(index)
                } else return
            }
        }

具体封装---最大堆

其实只需要把之前封装最小堆的一些条件判断改变就是最大堆了,我实在懒得再写一遍,大家如果看完想试试手,可以自己封装一下

其实,如果对比是自己封装在类中的方法的话,只需要继承,然后改一下这个方法就行了

kotlin 复制代码
    // 把 if(a > b) 改为 if(compare(a, b) === compareValue.bigger)
    const compareValue = {
        less: -1,
        equal: 0,
        bigger: 1
    }
    const compare = (a, b) => {
        if(a === b) return compareValue.equal
        else if(a > b) return compareValue.bigger
        else return compareValue.less
    }
    // 这样,只需要将 compare 函数改为以下即可,但这样改我觉得必须要加注释,说明大小值是相反的
    const compare = (a, b) => {
        if(a === b) return compareValue.equal
        else if(a < b) return compareValue.bigger
        else return compareValue.less
    }
相关推荐
小灰灰爱代码2 小时前
C++——求3*3矩阵对角元素之和。
数据结构·c++·算法
liangbm33 小时前
MATLAB系列02:MATLAB基础
开发语言·数据结构·笔记·matlab·教程·工程基础·高级绘图
DT——4 小时前
Vite项目中eslint的简单配置
前端·javascript·代码规范
我要学编程(ಥ_ಥ)5 小时前
双指针算法专题(2)
数据结构·算法·leetcode
我要学编程(ಥ_ಥ)7 小时前
滑动窗口算法专题(1)
java·数据结构·算法·leetcode
大油头儿7 小时前
排序算法-冒泡排序
数据结构·算法·排序算法
真的很上进7 小时前
【Git必看系列】—— Git巨好用的神器之git stash篇
java·前端·javascript·数据结构·git·react.js
qq_278063717 小时前
css scrollbar-width: none 隐藏默认滚动条
开发语言·前端·javascript
.ccl7 小时前
web开发 之 HTML、CSS、JavaScript、以及JavaScript的高级框架Vue(学习版2)
前端·javascript·vue.js
小徐不会写代码7 小时前
vue 实现tab菜单切换
前端·javascript·vue.js