【记录总结贴】数据结构

本文详细介绍了数据结构的时间复杂度和空间复杂度,包括大O表示法,常见时间复杂度和空间复杂度的比较。讨论了栈、队列、链表、集合、字典、树和图等数据结构的创建、应用场景及操作时间复杂度。同时,通过leetcode题目展示了具体应用,探讨了栈、队列、链表、树和图的操作,以及堆的实现和应用。

时间复杂度


1. 什么是时间复杂度

就是算法的执行效率。 即算法的执行时间与算法的输入值之间的关系

例  

    function test(num){
        total = 0                       ------>假设该行运行时间为t1
        for (i = 0 ; i < num ; i++){
            total += i                  ------>假设该行运行时间为t2
        }
        return total                    ------>假设该行运行时间为t3
    }--------->那么总运行时间为  (t1 + num*t2 + t3)
    
t1 t3为固定的时间,t2*num是根据num动态变化的,所以整体的时间取决于num
比如num=10000时,就可以忽略t1 t3,故用大O表示法为O(N)

2. 大O表示法

一种粗略的评价计算机算法效率的方法.后面的内容会用到表示效率的方法.
名称来源:使用大写字母O 含义: order of (大约是)

大O表示法实质并不是对运行时间给出实际值,而是表达运行时间是如何受数据项个数所影响

形式为:O()—>括号里是一个数学函数表达式f(N),比如1、logN、N、N^2等,
指明了该算法的耗时/耗空间程度与数据增长量之间的管理,N代表输入数据的量

3. 常见的时间复杂度

O(1)    O(logn)    O(n)    O(nlogn)    O(n^2)

大小关系:
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)

常见时间复杂度之间的关系(图表):https://www.cnblogs.com/byron0918/p/10544937.html
在这里插入图片描述

例子:(以下代码为伪代码,没有var变量,示意而已)

O(1)    function O1 (num){
            i = num                 --->t1
            j = num * 2             --->t2
            return i + j            --->t3
        }                   ---> (t1 + t2 + t3)
        t 为常数,与num无关,为O(1)
        

O(logn)     function Ologn (num){
                i = 1                   --->t1
                while(i < num){
                    i = i * 2           --->t2
                }             
                return i                --->t3
            }                   ---> (t1 + ?*t2 + t3)
            因为while循环里面不是每次加一,所以循环总时间tx不再是num*t2
            假设要循环x次能跳出循环,则2^x = num,所以x = log2(num)
            每一次循环时间为t2,循环总时间  tx=t2 * log2(num)
            常量去除后简写为 O(logn)


O(n)    function On (num){
            total = 0                       --->t1
            for (i = 0 ; i < num ; i++){
                total += i                  --->num*t2
            }
        return total                        --->t3
        }                      ---->(t1 + num*t2 + t3)
        for循环,循环时间为 num*t2,不考虑常量t2,即num所以为O(n)


O(n+m)  function On (num1,num2){
            total = 0                       --->t1
            for (i = 0 ; i < num1 ; i++){
                total += i                  --->num*t2
            }
            for (j = 0 ; j < num2 ; j++){
                total += j                  --->num*t3
            }
        return total                        --->t4
        }                      ---->(t1 + num*t2 + num*t3 + t4)
        for循环两次,同时因为是并列的循环,所以时间应该是两者相加,故同上,所以为O(n+m)


O(nlogn)    function Onlogn (num1,num2){
                total = 0
                j = 0                           --->t1
                for (i = 0 ; i < num1 ; i++){
                    while(i < num2){
                        total += i + j
                        j = j * 2               --->t2
                    }
                }             
                return total                    --->t3
            }                   ---> (t1 + ?*t2 + t3)
            双重嵌套循环,里面一层是O(logn),外面一层是O(n),相乘即为O(nlogn)


O(n2)   function On2 (num){
            total = 0                       --->t1
            for (i = 0 ; i < num ; i++){
                for (j = 0 ; j < num ; j++){
                    total += i + j          --->num*t2
            }
        return total                        --->t3
        }                      ---->(t1 + num*t2 + t3)
        双重嵌套循环,里面一层是O(n),外面一层是O(n),相乘即为O(n2)


先看是否有循环,没有循环基本是就是O(1),再看循环是否嵌套,分情况考虑

4. 常用数据结构增删查时间复杂度

数据结构根据关键字查找根据索引查找插入删除
数组O(n)O(1)O(n)O(n)
有序数组O(logn)O(1)O(n)O(n)
链表O(n)O(n)O(1)O(1)
有序链表O(n)O(1)O(n)O(n)
双向链表O(n)O(1)O(n)O(n)
二叉树(一般情况)O(logn)-O(logn)O(logn)
二叉树(一般情况)最坏情况O(n)-O(n)O(n)
平衡树O(logn)O(logn)O(logn)O(logn)
排序二叉树O(logn)~O(n)O(logn)~O(n)O(logn)~O(n)O(logn)~O(n)
哈希表O(1)-O(1)O(1)

空间复杂度


1. 什么是空间复杂度

算法的存储空间与算法的输入值之间的关系
空间复杂度也用大O表示法

代码中,占空间的是变量(比如var x = 0),语句不占空间(如if、for、while等)
例 

    function test1(num){
        total = 0                     --->假设total变量占据一个位置b
        for (i = 0 ; i < num ; i++){
            total += i                --->不管total如何增加变化,变化的也只是它代表的数值,不变的是占据的位置依旧是b
        }
        return total                  
    }--------->那么占据的总存储空间为 b ,b为假设的常量,所以为O(1)


    function test2(num){
        array = []                    --->array数组占据的空间跟里面的元素成正比
        for (i = 0 ; i < num ; i++){
            array.push(i)             --->由于for循环,array的空间与num的大小成正比
        }
        return array                  
    }--------->那么占据的总存储空间为O(n)

2. 常见的空间复杂度

O(1)  <  O(n)  <  O(n^2)
  • O(1) 一般是单个常量类型
  • O(n) 一般是list,array,map等多个变量集合在一起
    注意递归算法,就算没用常量等变量,因为递归的算法是栈,会每层每层的保存下去,所以递归一般也是O(n)
  • O(n^2) 一般都不常见,其余的更少

3. Note

  • 时间和空间在优化上一般只能二选一,要么时间换空间,要么空间换时间;
  • 面试的时候,把时间最优和空间最优都告诉面试官
  • 工作时一般时间>空间,执行效率优先


1. 栈的应用场景

需要后进先出的场景,如:十进制转二进制;判断字符串的括号是否有效;函数调用堆栈;浏览器的history等。

2. 如何创建一个栈

用数组Array[]可以模拟栈结构
栈的常用操作:push、pop、stack[stack.length-1]

push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度
pop() 方法用于删除数组的最后一个元素并返回删除的元素

3. 时间复杂度:

访问栈顶元素  O(1)      --只能栈顶
搜索元素      O(n)
插入元素      O(1)      --只能栈顶
删除元素      O(1)      --只能栈顶

见 leetcode题目 20. 496.

--------------------------------------------------------------------------------------------- (2021.3.15)


队列


1. 队列的应用场景

需要先进先出的场景,如:食堂排队;js任务队列;计算最近请求次数。

2. 如何创建一个队列

用数组Array[]可以模拟队列结构
队列的常用操作:push、shift、queue[0]

push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度

shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。

3. 见 leetcode题目 933. 239.


链表


1. 链表的应用场景

需要后进先出的场景,如:十进制转二进制;判断字符串的括号是否有效;函数调用堆栈;浏览器的history等。

链表相对于数组来说,链表可以不连续,增删只需要改变指针指向即可

2. 如何创建一个链表

js没有链表结构

用Object可以模链表结构

如:

    const a = {val:'a'}
    const b = {val:'b'}
    const c = {val:'c'}
    a.next = b
    b.next = c

链表的常用操作:
遍历链表:用循环        O(n)
    let p = a
    while (p){
        console.log(p.val)
        p = p.next
    }

插入:改变next指向		O(1)
    在b、c之间插入d
    const d = {val:'d'}
    b.next = d
    d.next = c

删除:改变next指向			O(1)
    删除b
    a.next = c


push、pop、stack[stack.length-1]

push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度
pop() 方法用于删除数组的最后一个元素并返回删除的元素

3. 见 leetcode题目 237. 203. 206. 2. 83. 141. 92.

小结做题思路:

  • 如果是遇到需要删除结点的,包括了第一个结点,就需要三个指针;

  • 因为做题的链表一般为单指向链表,结构里面只有next,所以需要另一个指针来表示前一个node,还有一个指针用来表示链表的起始位置,(当然如果选择不用head来滑动,就用head当起始位置,新建一个滑动的指针)

  • 一个head,不动,用来return整个链表;
    一个current,用来移动,判断条件等;
    一个prev,用来表示前一位;

如:需要删除当前node时:
prev指针不动,prev.val不动,prev.next = current.next
current指针往下移,current = current.next
如果不需要删除,只是移动指针就直接
prev = current,
current = current.next

--------------------------------------------------------------------------------------------- (2021.3.17)


集合


1. 集合的应用场景

一种无序且唯一的数据结构

2. 如何创建一个集合

ES6中有集合,名为Set,直接实例化就可以 const set = new Set()
集合的常用操作:去重、判断某元素是否在集合中、求交集

去重:
    const arr = [1, 1, 2, 2]
    const arr2 = new Set(arr)
    console.log(arr2);//set结构
    arr3= [...arr2]
    console.log(arr3);//array结构
    
检查是否有重复:
    原数据,加入集合后,会自动去重,比较返回的新数据长度,可以知道是否重复
    var containsDuplicate = function(nums) {//LeetCode 217
        return new Set(nums).size === nums.length? false :true
    };

是否在集合中:

    const isHas = arr2.has(3)
    返回true

	数组的判断是includes或者indexOf

求交集:
    const arr = [1, 1, 2, 2]
    const arr4 = new Set([2,3])
    //转化到数组上,数组的筛选方法
    const set = new Set([...arr].filter(item => arr4.has(item)))

求差集:
    const set = new Set([...arr].filter(item=> !arr4.has(item)))

增删改查:(key value都一样,不需要改,所以只有增删查)
    实例化后使用 const set = new Set()
        set.add(xxx)
        set.delete(xxx)
        set.has(xxx)
        for of 迭代
        keys和values和本身迭代都是一样的
        for(let item of set) console.log(item)
        for(let item of set.keys) console.log(item)
        for(let item of set.values) console.log(item)
        entries方法可以返回keys和values
        for(let [keys, values] of set.entries) console.log(keys, values)

  Set有一个size属性,可以看里面元素的个数,类似array的length

3. 见 leetcode题目 349.

Set转Array:
    const myArr = [...mySet] 或 const myArr = Array.from(mySet)
    

Array转Set:
    const mySet = new Set(myArr)

--------------------------------------------------------------------------------------------- (2021.3.19)


字典


1. 字典的应用场景

与集合类似,也是一种存储唯一值的数据结果,但是是以键值对的形式存储的

2. 如何创建一个字典

ES6中有字典,名为Map,直接实例化就可以 const m = new Map()
字典的常用操作:键值对的增删改查
    const m = new Map()
增:
    m.set('a','aa')//第一个值是键,第二个是值
删:
    m.delete('a')//删除指定键值对
    m.clear()//删除所有的
改:
    m.set('a','ab')//再次set就行,会覆盖
查:
    m.get('a')--->返回'a'的值
    m.has('a')--->返回true,判断是否存在
   
遍历:for of  forEach
for (let [key, value] of m)
m.forEach((value,key)   forEach键值对反着来的

https://www.runoob.com/w3cnote/es6-map-set.html 菜鸟教程里讲es6map的

3. 见 leetcode题目 349. 20. 1. 76. 3.

集合Set和字典Map的区别(个人做题总结)

Set每个数据只能保存一个信息量,Map则可以保存键值对,键和值分别不同就是两个
相同点都是对于相同的数据,只保留一个,可以理解为保留新的,覆盖旧的,当然Map是根据键的是否相同来判断的
比如题中给出数组,如果只考虑数组的去重之类的,两个都可以使用,但是Set更方便
如果需要考虑数组的索引因素,就不是一个信息量能解决的,这个时候Map更合适

--------------------------------------------------------------------------------------------- (2021.3.20)



1. 树的应用场景

一种分层数据的抽象模型。
前端工作中常见的树包括:DOM树、级联选择、树形控件

二叉树的常用种类:

  1. 满二叉树:都有左右子节点(除了底层)
    形态上看是完整的三角形,各层节点数量形成公比为2的等比数列,节点总数为2^k-1,k为深度

  2. 完全二叉树:比满二叉树少几个叶节点,从左向右放子节点。

  3. 平衡二叉树:空树或者它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树也都是平衡树。

  4. 二叉搜索树:空树或者二叉树的所有节点比他的左子节点大,比他的右子节点小。

  5. 红黑树:不仅是具有二叉搜索树的属性,还具有平衡树的属性,有序且子树差不超过1,颜色规则:根节点和特殊节点(即叶节点下面两个虚无的节点和未填写的节点)是黑的,红节点的左右子节点是黑的,最重要的是对于每个节点,从该节点到子孙叶节点的所有路径包含相同数目的黑节点。

2. 如何创建一个树结构

JS中没有树,需要用Object和Array来模拟构建一个树结构
如下

{
    value:'China',
    children:[
        {
            value:'jiangsu',
            children:[
                {
                    value:'xuzhou',
                    children:[]
                },
                {
                    value:'nanjing',
                    children:[]
                }
            ]
        },
        {
            value:'chongqing'
            children:[]
        }
    ]
}

对于完全二叉树,也可以用数组Array来构建
左侧子节点的位置是 2 * index + 1
右侧子节点的位置是 2 * index + 2
父侧子节点的位置是 (index - 1) / 2

如:[0,1,2,3,4,5,6]就是
    {
        value:0,
        left:{
            value:1,
            left:{
                value:3,
                left:null,
                right:null
            },
            right:{
                value:4,
                left:nill,
                right:null
            }
        },
        right:{
            value:2,
            left:{
                value:5,
                left:null,
                right:null
            },
            right:{
                value:6,
                left:null,
                right:null
            }
        }
    }

比如节点1的index是1,它的左子树的index应该是2*1+1=3,此时index为3的元素也是3

3. 树的常用操作:深度/广度优先遍历,先中后序遍历(二叉树)

深度优先遍历:尽可能深的搜索树的分支。Depth First Search(DFS)
    1. 访问根节点;
    2. 对根节点的children挨个进行深度优先遍历

    代码:
    const tree = {
        val:'a',
        children:[
            {
                val:'b',
                children:[
                    {
                        val:'d',
                        children:[]
                    },
                    {
                        val:'e',
                        children:[]
                    },
                ]
            },
            {
                val:'c',
                children:[
                    {
                        val:'f',
                        children:[]
                    },
                    {
                        val:'g',
                        children:[]
                    },
                ]
            },
        ]
    }

    const dfs = (root)=>{
        console.log(root.val)
        root.children.forEach(dfs)
    }
    dfs(tree)
    
    
    对于此处为什么可以不写 if (!root) return
    是因为forEach对于空数组,不会有任何操作,如下例
    const a = []
    a.forEach(item=>{console.log(item.val)})
    a.forEach(item=>{console.log('xxx')})
    均不会输出任何值,而且forEach中用return没用
    
    深度优先遍历类似于二叉树的先序遍历,但是先序遍历会进行判断if (!root) return,因为使用的不是forEach

广度优先遍历:先访问离根节点最近的节点。Breadth First Search(BFS)
    1. 新建一个队列,把根节点入队;
    2. 把队头出队并访问;
    3. 把队头的children挨个入队;
    4. 重复二三步,直到队列为空

    代码:
    const bfs = (root)=>{
        const q = [root]
        while(q.length>0){
            const n = q.shift()
            console.log(n.val)
            n.children.forEach(child=>q.push(child))
        }
    }
    bfs(tree)

记录当时的一个疑惑:为什么dfs中的forEach可以直接写dfs,但是bfs中却要写child=>q.push(child)
暂时还未解决,用console.log验证了半天也没结果,先保留,继续往下看,后面再解决,不然浪费时间
解决了。。。太蠢了,dfs是整个函数进行递归,bfs只是利用队列进行递归

    const dfs = (root) => {
        console.log(root.val)
        /* 
        为什么这里可以直接写dfs,但是bfs中不能直接写q.push
        因为forEach的三个参数是function(currentValue, index, arr)
        currentValue   必需。当前元素
        index	       可选。当前元素的索引值。
        arr	           可选。当前元素所属的数组对象。
        在bfs中用q.push,就会像console.log一样默认传入三个参数,所以会报错bfs.html:49 Uncaught TypeError: Cannot convert undefined or null to object
        但问题是为什么dfs没有传入3个参数,有可能是传了,但是没接收后面两个,
        bfs中写全传入三个参数进push,报错不会是简写方式,所以是为什么
        */
        // root.children.forEach(dfs)
        root.children.forEach((currentValue, index, arr)=>{dfs(currentValue, index, arr)})
        // root.children.forEach(console.log)
    }
    dfs(tree)

--------分割线-------------问题未解决---------------

二叉树:
树的每个节点最多只有两个子节点
js中通常用Object来模拟二叉树

    const binaryTree = {
        val:1,
        left:{
            val:2,
            left:null,
            right:null
        },
        right{
            val:3,
            left:null,
            right:null
        }
    }

    三种遍历方式:(递归版)//递归虽然没有用到什么结构,但是隐藏了栈的应用,非递归版就是用栈来实现递归
    一) 先序遍历
        1. 访问根节点;
        2. 对根节点的左子树进行先序遍历;
        3. 对根节点的右子树进行先序遍历

        const bt = {
            val:1,
            left:{
                val:2,
                left:{
                    val:4,
                    left:null,
                    right:null
                },
                right:{
                    val:5,
                    left:null,
                    right:null
                },
            },
            right:{
                val:3,
                left:{
                    val:6,
                    left:null,
                    right:null
                },
                right:{
                    val:7,
                    left:null,
                    right:null
                },
            }
        }

        const preorder = (root)=>{
            if(!root) return
            console.log(root.val)
            preorder(root.left)
            preorder(root.right)
        }

        preorder(bt)
        //结果为1245367

        非递归版(调用栈,都是对栈顶元素进行操作,所以是push和pop)
        const preorder = (root)=>{
            if(!root) return
            const stack = [root]
            while(stack.length>0){
                const n = stack.pop()
                console.log(n.val)
                if(n.right) stack.push(n.right)
                if(n.left) stack.push(n.left)
            }
        }
        preorder(bt)

        



    二) 中序遍历
        1. 对根节点的左子树进行中序遍历;
        2. 访问根节点;
        3. 对根节点的右子树进行中序遍历

        const inorder = (root)=>{
            if(!root) return
            inorder(root.left)
            console.log(root.val)
            inorder(root.right)
        }

        inorder(bt)
        //结果为4251637


        非递归版(调用栈,都是对栈顶元素进行操作,所以是push和pop)
        const inorder = (root)=>{
            if(!root) return
            const stack = []
            let p = root 
            while(stack.length || p){
                while(p){
                    stack.push(p)
                    p = p.left
                }
                const n = stack.pop()
                console.log(n.val)
                p = n.right
            }
        }
        inorder(bt)



    三) 后序遍历
        1. 对根节点的左子树进行后序遍历;
        2. 对根节点的右子树进行后序遍历
        3. 访问根节点;

        const postorder = (root)=>{
            if(!root) return
            inorder(root.left)
            inorder(root.right)
            console.log(root.val)
        }

        postorder(bt)
        //结果为4526731

        非递归版(调用栈,都是对栈顶元素进行操作,所以是push和pop)
        //因为先序遍历和后续遍历是相似的(不是说输出结果),是遍历顺序,先序遍历的非递归版的入栈顺序稍微修改一下,
        //所以用先序遍历的非递归版,每次入栈,再该顺序最后出栈就是后续遍历了
        const postorder = (root)=>{
            if(!root) return
            const stack = [root]
            const outputStack = []
            while(stack.length>0){
                const n = stack.pop()
                outputStack.push(n)
                if(n.left) stack.push(n.left)
                if(n.right) stack.push(n.right)
            }
            while(outputStack.length){
                const n = outputStack.pop()
                console.log(n.val)
            }
        }
        postorder(bt)


    遍历JSON的所有节点值(深度优先遍历)
    const json = {
        a: { b: { c: 1 } },
        d: [ 1, 2],
    }

    const dfs = (n)=>{
        console.log(n)
        Object.keys(n).forEach(k =>{
            dfs(n[k])
        })
    }

    dfs(json)

    加上path后

    const json = {
        a: { b: { c: 1 } },
        d: [ 1, 2],
    }

    const dfs = (n, path)=>{
        console.log(n, path)
        Object.keys(n).forEach(k =>{
            dfs(n[k], path.concat(k))
        })
    }

    dfs(json, [])

--------------------------------------------------------------------------------------------- (2021.3.23)



1. 图的应用场景

图是网络结构的抽象模型。是一组由边连接的节点,图可以表示任何二元关系,如航班网络,道路网路等

2. 如何创建一个图

js中没有图,但是可以用Object和Array来构建一个图
常用的表示方法为:邻接矩阵、邻接表、关联矩阵...

在这里插入图片描述
在这里插入图片描述
图的常用操作,利用队列完成深度优先遍历和广度优先遍历
类似于树的dfs和bfs

深度优先遍历:
    1. 访问根节点
    2. 对根节点的没访问过的相邻节点挨个进行深度优先遍历

在这里插入图片描述

const graph = { 
        0:[1, 2],
        1:[2],
        2:[0,3],
        3:[3]
    }

    const visited = new Set()
    const dfs = (n)=>{
        console.log(n)
        visited.add(n)
        graph[n].forEach(c =>{
            if (!visited.has(c)){
                dfs(c)
            }
        })
    }
    dfs(2) --->2013


广度优先遍历:
    1. 新建一个队列,把根节点入队
    2. 把队头出队并访问
    3. 把队头的没访问过的相邻节点入队
    4. 重复二、三步,知道队列为空

在这里插入图片描述

    const graph = { 
        0:[1, 2],
        1:[2],
        2:[0,3],
        3:[3]
    }

    const visited = new Set()
    visited.add(2)
    const q = [2]
    while(q.length) {
        const n = q.shift()
        console.log(n)
        graph[n].forEach(c =>{
            if (!visited.has(c)){
                q.push(c)
                visited.add(c)
            }
        })
    }
    --->2031

3. 见 leetcode题目 65. 417.

有效的数字
太平洋大西洋水流问题

--------------------------------------------------------------------------------------------- (2021.3.26)



1. 堆的应用场景

堆是一种特殊的完全二叉树。
所有节点都大于等于(最大堆)或小于等于(最小堆)它的子节点
求前k个最大(小)的元素,设定堆的高度来解决

2. 如何创建一个堆

用数组Array[]可以模拟堆结构,相对于数组也可以表示二叉树
js中用Object来表示二叉树,但是可以用数组来表示堆(完全二叉树)
  • 左侧子节点的位置是 2 * index + 1
  • 右侧子节点的位置是 2 * index + 2
  • 父侧子节点的位置是 (index - 1) / 2
  • 队列的常用操作:创建最小堆类

3. 见 leetcode题目 215. 347. 实现最小堆类

最小堆类

class MinHeap {
	constructor() {
    	this.heap = []
	}
	swap(i1, i2) {
    	const temp = this.heap[i1]
    	this.heap[i1] = this.heap[i2]
    	this.heap[i2] = temp
	}
	getParentIndex(i) {
    	return (i - 1) >> 1//用二进制右移一位,来达到除以2求商
	}
	getLeftIndex(i) {
    	return i * 2 + 1
	}
	getRightIndex(i) {
    	return i * 2 + 2
	}
	shiftUp(index) {
    	if (index == 0) return
    	const parentIndex = this.getParentIndex(index)
    	if (this.heap[parentIndex] > this.heap[index]) {
        	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[index]) {
        	this.swap(leftIndex, index)
        	this.shiftDown(leftIndex)
    	}
    	if (this.heap[rightIndex] < this.heap[index]) {
        	this.swap(rightIndex, index)
        	this.shiftDown(rightIndex)
    	}
	}
	insert(value) {
		//把新的放到最后,这样不会丢失之前的值,再进行排序
    	this.heap.push(value)
    	this.shiftUp(this.heap.length - 1)
	}
	pop() {
		// 把最大的数放到弹出的顶部,替换掉最小值,然后再排序,就可以了
    	this.heap[0] = this.heap.pop()
    	this.shiftDown(0)
	}
	peek() {
    	return this.heap[0]
	}
	size() {
    	return this.heap.length
	}
}
const h = new MinHeap()
h.insert(3)
h.insert(2)
h.insert(1)

--------------------------------------------------------------------------------------------- (2021.3.28)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值