精华内容
下载资源
问答
  • 大根堆
    2021-05-23 03:06:15

    数据结构-大根堆小根堆模板2021-04-11 14:32:20

    明明用优先队列就可以了的说

    #include

    using namespace std;

    #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

    typedef long long ll;

    typedef unsigned long long ull;

    const ll MAXN=1e18;

    const int MOD=1e6;

    struct Maxheap{

    int cnt,date[

    295. 数据流的中位数2021-02-06 12:30:12

    使用大根堆和小根, PriorityQueue默认是小根堆,所以存入负数让其变成大根堆.

    from queue import PriorityQueue

    class MedianFinder:

    def __init__(self):

    """

    initialize your data structure here.

    """

    self.hi = PriorityQueue()

    1. 问题描述:

    有一堆石头,每块石头的重量都是正整数。每一回合,从中选出两块最重的石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

    如果 x == y,那么两块石头都会被完全粉碎;如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y

    堆排序分析(大根堆为例,由小到大排序)2020-11-30 11:01:07

    时间复杂度为O(nlogn),思路就是从最后一个非叶结点开始,依次往回遍历每个结点,将以该结点为根的子树建立成大根堆,直到遍历到整棵完全二叉树的根结点时为止,此时整棵树为大根堆。

    以当前结点为根的子树建立大根堆:

    //向下调整,将该结点的子树变成大根堆

    void AdjustDown(int A[],int

    堆排序2020-09-20 08:35:02

    堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序。

    大根堆:每个结点的值都大于其左孩子和右孩子结点的值。

    小根堆:每个结点的值都小于其左孩子和右孩子结点的值。

    堆可以采用数组存储,结点的标号从 $0$ 开始,则对任一个结点 $i$,其左孩

    堆排序2020-07-16 13:31:13

    堆排序

    选择排序:

    简单选择排序

    堆排序

    选择排序:每一趟在待选择元素中选取关键字最小(或最大)的元素加入有序子序列

    难理解!!

    什么是“堆(Heap)”?

    若n个关键字序列L[1...n] 满足下面某一条性质,则称为堆(Heap):

    若满足:L(i)≥L(2i) 且L(i)≥L(2i+1) (1≤i≤n/2) ——大根堆(大顶堆)

    若满足:L(

    最小的k个数2020-04-30 23:54:34

    题目:最小的k个数

    输入n个整数,找出其中最小的k个数。

    注意:

    数据保证k一定小于等于输入数组的长度;

    输出数组内元素请按从小到大顺序排序;

    样例:

    输入:[1,2,3,4,5,6,7,8] , k=4

    输出:[1,2,3,4]

    思路:

    用大根堆来解决此题。大根堆的特征,大根堆的堆顶元素一定是最大的元素。

    面试题40:最小的k个数(C++)2020-03-20 10:56:00

    题目地址:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/

    题目描述

    输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

    题目示例

    示例 1:

    输入:arr = [3,2,1], k = 2

    输出:[1,2] 或者 [2,1]

    示例 2:

    链接:HDU - 4261 Estimation

    题意:

    给出长度为NNN(1≤N≤20001\le N\le 20001≤N≤2000)的序列A1,A2,⋯ ,ANA_1,A_2,\cdots,A_NA1​,A2​,⋯,AN​,要求将其分为KKK(1≤K≤min⁡{25,N}1\le K\le \min\{25,N\}1≤K≤min{25,N})段,并对每段确定一个值BjB_jBj​(1≤j≤K1\le j\le K1≤j

    堆2020-01-22 19:50:50

    因为堆是一棵完全二叉树,所以对于一个节点数为\(n\)的堆,它的高度不会超过\(log\) \(n\),所以对于插入,删除操作复杂度为\(O(log\) \(n)\),查询堆顶操作的复杂度为\(O(1)\)。

    可以用来维护若干贪心题,如数据备份(用堆来实现反悔),超市(也是一种反悔)。

    用对顶堆(一个大根堆一个小根堆)维护一些

    Day22020-01-16 22:01:40

    树状数组

    二叉树比较好看,所以,先从它下手

    =>\(C[i] = A[i - 2^k+1] + A[i - 2^k+2] + ... + A[i]\)

    那我们可以得到\(SUMi = C[i] + C[i-2^{k_1}] + C[(i - 2^{k_1}) - 2^{k_2}] + .....\)

    然后\(2^k\)这么好看的东西怎么能放过呢?于是就有\(2^k\) = i&(-i)

    具体怎么得到的。。。

    9.272019-09-27 23:04:23

    今天我再写了一次大根堆,一些问题我就记在heap4了,heap2是自己写的并且能ac的。

    记得明天再写一遍,确实还有不少问题。

    1,关于大根堆的问题。

    一,algorithm头文件用在哪里

    二,define RI LE DAD 这几个东西的深入理解。

    、 三,struct 中 modify 和repair 的完整理解

    【POJ 1442 --- Black Box】大根堆和小根堆,优先队列

    Description

    Our Black Box represents a primitive database. It can save an integer array and has a special i variable. At the initial moment Black Box is empty and i equals 0. This Black Box processes a

    转: 堆排序算法 讲解的比较清晰2019-09-01 23:54:37

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    本文链接:https://blog.csdn.net/u010452388/article/details/81283998堆排序的时间复杂度O(N*logN),额外空间复杂度O(1),是一个不稳定性的排序

    目录

    一 准备知识

    1.1  大根堆和小根堆

    Python八大排序(八)——堆排序2019-08-31 17:38:56

    堆排序涉及到的概念

    堆排序是利用 堆进行排序的

    堆是一种完全二叉树

    堆有两种类型: 大根堆 小根堆

    两种类型的概念如下:

    大根堆:每个结点的值都大于或等于左右孩子结点

    小根堆:每个结点的值都小于或等于左右孩子结点

    因为比较抽象,所以专门花了两个图表示

    那么,什么是完全二叉

    基本数据结构——二叉堆2019-07-21 20:03:23

    迅速补档,为A*做一下铺垫…

    概念定义

    二叉堆就是一个支持插入、删除、查询最值的数据结构。他其实是一棵完全二叉树。那么堆一般分为大根堆和小根堆

    大根堆

    树中的任意一个节点的权值都小于或者等于其父节点的权值,则称该二叉树满足大根堆性质。

    小根堆

    树中的任意一个节点的权值都大

    6月10日数据结构——堆2019-06-10 17:03:30

    堆的建立和输出

    #include#include#define maxSize 128typedef int HElemType;typedef struct node { //大根堆的定义 HElemType data[maxSize]; //存放大根堆中元素的数组 int n;

    堆排序2019-06-09 16:01:36

    堆排序的原理是利用了完全二叉树的性质

    我以这个数组来举例子int arr[]={2,6,4,8,5,3};

    这是一颗完全二叉树:

    结点的父节点为:(index-1)/2,index是指数组的下标,比如我举个例子值为8的结点在数组中的下标为3,那么它的父节点下标为1,父节点值为6,

    结点的左孩子的下标为:index*2+1,index

    luogu P1843奶牛晒衣服2019-05-08 13:40:34

    第一篇正儿八经的题解

    先看题目描述

    发现本题主要解决以下问题

    给出一个数列,在单位一的时间内可同时做以下操作

    ·对所有的数减A

    ·对指定数减B

    求出最少的操作次数使这个数列的所有数均<=0

    不难发现这是一道简单的贪心题

    每次操作只需将上一次操作后产生的最大的数减B,其余数

    大根堆2019-04-13 19:52:35

    大根堆的概念:

    大根堆的建立:

    大根堆的基本操作:

    未完待续。。。

    https://wenku.baidu.com/view/be727e8ccc22bcd126ff0c9e.html?sxts=1555155590171

    AcWing 53 最小的k个数2019-03-10 10:47:32

    题目描述:

    输入n个整数,找出其中最小的k个数。

    注意:

    数据保证k一定小于等于输入数组的长度;

    输出数组内元素请按从小到大顺序排序;

    样例

    输入:[1,2,3,4,5,6,7,8] , k=4

    输出:[1,2,3,4]

    分析:

    大根堆的经典应用。维护一个大根堆,遍历向量时将元素加入大根堆。一旦大根堆元素个数超

    堆排序——c语言实现2019-03-08 21:39:46

    从键盘任意输入一组数, 比如:3216549870。要求对它进行排序,使它顺序排列。

    我理解的堆排序思路如下:

    NO.1 首先想着让这组数按下面这种方式形成完全二叉树树型结构。

    A

    我先给出这棵完全二叉树所具备的一些基本性质:

    a: 不管这组数是奇数个还是偶数个,假设

    更多相关内容
  • 主要介绍了Java实现堆排序(大根堆)的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • c++ 大根堆和小根堆

    2021-01-14 17:00:02
    基于c++实现以数组为基础大根堆和小根堆
  • 大根堆(C++)示例代码

    2020-11-24 21:49:53
    根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆,又称最大堆(大顶堆)。 大根堆要求 ①根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值。 ②为完全二叉树。
  • 基于C++ 模板实现的大根堆,里面有大根堆的实现,初始化,插入元素和pop顶端元素,注释详细,并写好了测试代码,简明易懂,想学习的可以下载。
  • 初始化堆并将其调整为大根堆 初始化堆 调整堆为大根堆 大根堆的插入和删除 大根堆的插入 大根堆的删除 完整代码 堆的概念以及问题思考 堆的概念:如果有关键字集合k = {k0,k1,k2,......,k(n-1)},把...

    目录

    堆的概念以及问题思考

    初始化堆并将其调整为大根堆

    初始化堆

    调整堆为大根堆

    大根堆的插入和删除 

    大根堆的插入

    大根堆的删除 

    完整代码 


    堆的概念以及问题思考

     堆的概念:如果有关键字集合k = {k0,k1,k2,......,k(n-1)},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,且满足Ki <= K2i+1 且Ki <= K2i+2(或Ki >= K2i+1 且Ki >= K2i+2)i = 0,1,2.....,则称为小堆(或大堆)。将根节点最大的堆称为大根堆,将根节点最小的堆称为小根堆。

    上图为大根堆举例.

    若要创建一个大根堆并实现其插入删除操作,需要进行以下步骤:

    ①首先需要传入一个堆,以传递数组的方式,先初始化一个堆;

    例如要传入的数据为:5 8 12 22 15 32 11,则首先初始化,初始化的结果如下图所示.

    ②然后对该堆进行调整,将其调整为大根堆,采取从根节点向下调整的方式来实现大根堆的创建.

    ③在建成大根堆后再对其进行插入删除操作,插入删除后依旧满足大根堆性质,具体实现思想在下午代码中描述.

    初始化堆并将其调整为大根堆

    初始化堆

    在初始化时,需要定义一个数组,初始化数组大小为10,作为底层来实现堆,再定义usedSize用来记录堆中的元素个数,传入一个数组,将其抽象为堆结构,即完成初始化操作.

    除此之外,还需写出一个判满和扩容的方法,若插入数据时,该堆底层的数组已满,则对其进行扩容,扩容的空间为当前空间的二倍.

    public class TestHeap {
        public int[] elem;
        public int usedSize;
    
        public TestHeap() {
            this.elem = new int[10];
        }
        //扩容
        public void dilatation() {
            this.elem = Arrays.copyOf(this.elem, this.elem.length*2);
        }
        //判断数组是否满
        public boolean isFull() {
            return this.usedSize == this.elem.length;
        }
        //初始化堆
        public void createHeap(int[] array) {
            for(int i = 0; i < array.length; i++) {
                if(isFull()) {
                    dilatation();
                }
                this.elem[i] = array[i];
                this.usedSize++;
            }
        }
    }

    调整堆为大根堆

    在将堆调整为大根堆的过程中采用向下调整的方式,首先利用usedSize找到要调整的第一个节点,具体如下图所示:

    再判断elem[parent]和elem[child]哪个大,如果父亲结点大,则将两个结点的值互换,反之,则不需要做出改变.

    在交换后,需要进行如下代码,意在对于交换后的结点判断其是否也满足大根堆,如果不满足,则进行调整,如果满足,则无需进行操作.

    parent = child;
    child = 2*parent+1;

    具体代码实现: 

        /**
         * 向下调整
         * @param parent:每次调整的根节点
         * @param len:每次结束的位置
         */
        public void shiftDown(int parent, int len) {
            int child = (2*parent) + 1;
            while(child < len) {
                //判断该节点是否有右孩子
                if(child+1 < len && this.elem[child+1] > this.elem[child]) {
                    child ++;
                }
                //保证child下标一定为左右孩子最大值的下标
                if(this.elem[child] > this.elem[parent]) {
                    int tmp = this.elem[parent];
                    this.elem[parent] = this.elem[child];
                    this.elem[child] = tmp;
                    parent = child;
                    child = 2*parent + 1;
                }else {
                    break;
                }
            }
        }

    大根堆的插入和删除 

    大根堆的插入

    之后利用uedSize找到第一个要比较的结点,具体语句为如下代码

    int parent = (child-1) / 2;

     之后一直向上调整,直至整个堆被调整为大根堆为止,具体代码实现如下:

        /**
         * 向上调整
         * @param child 每次要调整的孩子结点
         */
        public void shiftUp(int child) {
            int parent = (child-1) / 2;
            while(parent >= 0) {
                if(this.elem[parent] < this.elem[child]) {
                    int tmp = this.elem[parent];
                    this.elem[parent] = this.elem[child];
                    this.elem[child] = tmp;
                    child = parent;
                    parent = (child-1) / 2;
                } else {
                    break;
                }
            }
        }
        /**
         * 大根堆的插入
         * @param val 要插入大根堆的值
         */
        public void push(int val) {
            if(isFull()) {
                dilatation();
            }
            this.elem[this.usedSize++] = val;
            shiftUp(this.usedSize-1);
        }

    大根堆的删除 

    进行大根堆删除的主要思想为将下标为0位置的元素与数组最后一个元素互换,之后数组长度-1,再将目前的堆重新向下调整为大根堆即完成删除操作.

    具体代码如下:

        /**
         * 判断大根堆是否为空
         * @return 是否为空(true/false)
         */
        public boolean isEmpty() {
            return this.usedSize == 0;
        }
        /**
         * 删除操作
         * @return 删除的值
         */
        public int pop() {
            if(isEmpty()) {
                throw new RuntimeException("堆为空,无法进行删除操作");
            }
            int tmp = this.elem[0];
            this.elem[0] = this.elem[this.usedSize-1];
            this.elem[this.usedSize-1] = tmp;
            this.usedSize--;
            shiftDown(0, this.usedSize);
            return tmp;
        }

    完整代码 

    import java.util.Arrays;
    
    public class TestHeap {
        public int[] elem;
        public int usedSize;
    
        public TestHeap() {
            this.elem = new int[10];
        }
    
        /**
         * 扩容
         */
        public void dilatation() {
            this.elem = Arrays.copyOf(this.elem, this.elem.length*2);
        }
    
        /**
         * @return 数组是否为满
         */
        public boolean isFull() {
            return this.usedSize == this.elem.length;
        }
    
        /**
         * 向下调整
         * @param parent:每次调整的根节点
         * @param len:每次结束的位置
         */
        public void shiftDown(int parent, int len) {
            int child = (2*parent) + 1;
            while(child < len) {
                //判断该节点是否有右孩子
                if(child+1 < len && this.elem[child+1] > this.elem[child]) {
                    child ++;
                }
                //保证child下标一定为左右孩子最大值的下标
                if(this.elem[child] > this.elem[parent]) {
                    int tmp = this.elem[parent];
                    this.elem[parent] = this.elem[child];
                    this.elem[child] = tmp;
                    parent = child;
                    child = 2*parent + 1;
                }else {
                    break;
                }
            }
        }
        /**
         * 创建大根堆
         * @param array 传入的数据
         */
        public void createHeap(int[] array) {
            for(int i = 0; i < array.length; i++) {
                this.elem[i] = array[i];
                this.usedSize++;
            }
            for(int i = (this.usedSize-1-1) / 2; i >= 0; i--) {
                shiftDown(i, this.usedSize);
            }
        }
    
        /**
         * 向上调整
         * @param child 每次要调整的孩子结点
         */
        public void shiftUp(int child) {
            int parent = (child-1) / 2;
            while(parent >= 0) {
                if(this.elem[parent] < this.elem[child]) {
                    int tmp = this.elem[parent];
                    this.elem[parent] = this.elem[child];
                    this.elem[child] = tmp;
                    child = parent;
                    parent = (child-1) / 2;
                } else {
                    break;
                }
            }
        }
        /**
         * 大根堆的插入
         * @param val 要插入大根堆的值
         */
        public void push(int val) {
            if(isFull()) {
                dilatation();
            }
            this.elem[this.usedSize++] = val;
            shiftUp(this.usedSize-1);
        }
    
        /**
         * 判断大根堆是否为空
         * @return 是否为空(true/false)
         */
        public boolean isEmpty() {
            return this.usedSize == 0;
        }
    
        /**
         * 删除操作
         * @return 删除的值
         */
        public int pop() {
            if(isEmpty()) {
                throw new RuntimeException("堆为空,无法进行删除操作");
            }
            int tmp = this.elem[0];
            this.elem[0] = this.elem[this.usedSize-1];
            this.elem[this.usedSize-1] = tmp;
            this.usedSize--;
            shiftDown(0, this.usedSize);
            return tmp;
        }
    }
    

     

     

    展开全文
  • JavaScript大根堆小根堆

    2021-12-22 22:24:20
    最近在刷leetcode遇到一个名为【大根堆】的东西,首先我不太清楚这是什么,所以我不能改厨准确的定义;它是方法?或者一个阶梯思路?或者一个数据结构?或者是其他什么。因为这个名字广泛出现在各种题解中。比如: ...

    序言

    最近在刷leetcode遇到一个名为【大根堆】的东西,首先我不太清楚这是什么,所以我不能改厨准确的定义;它是方法?或者一个阶梯思路?或者一个数据结构?或者是其他什么。因为这个名字广泛出现在各种题解中。比如:

    既然这么多题出现【大根堆】,它应该很重要,而我又不会;所以我决定搞清楚它

    百度百科上说:堆通常是一个可以被看做一棵完全二叉树的数组对象

    比如:数组array = [7,3,8,5,1,2]

    数组array可以看做如下完全二叉树

              7
            /   \
           3     8
          / \   /
         5   1 2
    

    是要将数组转换成二叉树?
    不不不,只是把数组类比成二叉树,要不然我说8和7要调换位置,你会问为什么要调换?

    什么是大根堆?

    什么是大根堆:每个结点的值都大于等于其左右孩子结点的值
    比如:数组array = [7,3,8,5,1,2]
    数组array大根堆可以是

              8
            /   \
           5     7
          / \   /
         3   1 2
    

    上述二叉树是不是节点值都大于等于左右子节点?

    这就是大根堆;

    疑问:你这还是将数组转换为二叉树了呀。
    没有啊,数组由[7,3,8,5,1,2] 变成了 [8,5,7,3,1,2]

    数组还是数组,只是数组中的值位置发生了改变;

    改变的规则是按照二叉树的大根堆规则来的;这样在数组添加,或者删除元素后,可以快速找到数组中最大值,最小值

    总结:找最值用大根堆,小根堆

    如何构建大根堆呢?

    添加

    比如:数组array = [7,3,8,5,1,2],二叉树根节点位0;
    构建后的大根堆位list = [0],其中0没有实际意义,表示根节点

    1、取数组第一位7放入二叉树

              7
    

    list = [0,7]
    2、取第2为值3放在二叉树中;

    • list = [0,7,3]
    • list符合大根堆吗?
              7
            /   
           3
    

    符合,不处理
    3、取数组array第3为值8放在二叉树中;

    • list = [0,7,3,8]
    • list符合大根堆吗?
              7
            /   \
           3     8
        
    

    不符合,8>7所以8要与7交换位置;

    在二叉树视图上比较好观察,但是怎么在程序中交换他们的位置呢?

    这里需要补充几个概念;

    在完全二叉树中,对于非根节点x都有

    父级值在array数组的下标为: Math.floor(x/2)
    左子级值在array数组的下标为:2x
    右子级值在array数组的下标为: 2
    x + 1

              1
            /   \
           2     3
          / \   /  \
         4   5 6    7
    

    所以:7与8交换位子就是8所在的下标3,与7所在的下标1交换位置,所以数组变成了[0,8,3,7]
    直观的看二叉树变成了

              8
            /   \
           3     7
        
    

    4、取数组array第4位值5放入list中

    • list = [0,8,3,7,5]
              8
            /   \
           3     7
          /
         5
    
    • 不符合大根堆条件,因为5 > 3
      如何调整数组呢?将5的位置与3互换;
      5的下标是多少呢?是4;3的下标可以计算出来是2;所以5与3调换后得到list = [0,8,5,7,3]
              8
            /   \
           5     7
          /
         3
    

    总结

    通过以上4个步骤,可以知道,在向数组中添加数据的时候,现添加到数组末尾,数组末尾表示数组的叶子节点;将该数据放在叶子节点后,将该值与该值的父级节点值对比,如果该值大于父级节点值,交换两个位置;参考步骤3、4

    因为从叶子节点向上交换,所以该值也父级节点交换后,要判断交换后的父级节点与父级的父级节点比较,直至比较到根节点或者小于父级节点;

    删除

    现在list = [0,8,5,7,3]
    与list对应的二叉树如下:

              8
            /   \
           5     7
          /
         3
    

    获取数组最大值,返回array[1]即可;

    删除数组最大值呢?

    首先:将最后一个节点值与第一个节点子调换;调换后如下
    list = [0,3,5,7,8]

              3
            /   \
           5     7
          /
         8
    

    第2步:删除叶子节点;list.pop()
    list = [0,3,5,7]

              3
            /   \
           5     7
    

    第3步:重新构建大根堆

    在这个例子中,3应该与左子节点交换还是应该去右子节点交换?这个是关键;

    假如3与左子节点交换,交换后

              5
            /   \
           3     7
    

    不行吧,还是没构成大根堆,因为7>5
    假如3与右子节点交换,交换后

              7
            /   \
           5     3
    

    符合大根堆;

    通过上述两个假设,可以到的一个结论,如果根节点与子节点交换,可以重新构成大根堆,则与该子节点交换

    了解以上内容,可以编辑代码

    手写堆

    先搭个架子

    class Heap {
      constructor(compare) {
        this.list = [0] //数组,存放数据
        this.compare =
            typeof compare === 'function' ? compare : this.defaultCompare
      }
      //控制堆升序排列还是降序排列
       defaultCompare(a, b) {
       return a > b
      }
      isEmpty() {} //是否为空
      getSize() {}// 数组长度
      top() {}// 最大值
      pop() {}// 删除最大值
      push() {}//添加值
      left = (x) => 2 * x //根据当前节点下标获取节点左侧子节点下标
      right = (x) => 2 * x + 1
      parent = (x) => Math.floor(x / 2)
    }
    

    isEmpty

      isEmpty() {
          return this.num === 0
        }
    

    top

     top() {
          return this.list[1]
        }
    

    push

      push(val) {
          // 新增数据,向堆尾添加
          this.list.push(val)
    
          this.up(this.list.length - 1)
        }
        // 上浮
        up(k) {
          const { list, parent, compare } = this
          //迭代交换当前节点与父节点
          while (k > 1 && compare(list[k], list[parent(k)])) {
            this.swap(parent(k), k)
            k = parent(k)
          }
        }
    

    pop

    核心代码,重点难点,需要着重理解down函数;从第1为,将数据【下沉】到对应位置,

     pop() {
          const { list } = this
          if (list.length === 0) return null
          this.swap(1, list.length - 1)
          const top = list.pop()
          this.down(1)
          return top
        }
    
        down(k) {
          const { list, left, right, compare } = this
          const size = this.getSize()
          console.log('size', size)
          while (left(k) <= size) {
            let _left = left(k)
            if (right(k) <= size && compare(list[right(k)], list[_left])) {
              _left = right(k)
            }
            if (compare(list[k], list[_left])) return
            this.swap(k, _left)
            k = _left
          }
        }
    

    完整代码

      class Heap {
        constructor(compare) {
          this.list = [0]
          this.compare =
            typeof compare === 'function' ? compare : this.defaultCompare
        }
    
        defaultCompare(a, b) {
          return a > b
        }
    
        swap(x, y) {
          const t = this.list[x]
          this.list[x] = this.list[y]
          this.list[y] = t
        }
        isEmpty() {
          return this.list.length === 1
        }
        getSize() {
          return this.list.length - 1
        }
        top() {
          return this.list[1]
        }
    
        left(x) {
          return 2 * x
        }
        right(x) {
          return 2 * x + 1
        }
        parent(x) {
          return Math.floor(x / 2)
        }
    
        push(val) {
          // 新增数据,向堆尾添加
          this.list.push(val)
    
          this.up(this.list.length - 1)
        }
        // 上浮
        up(k) {
          const { list, parent, compare } = this
          while (k > 1 && compare(list[k], list[parent(k)])) {
            this.swap(parent(k), k)
            k = parent(k)
          }
        }
        pop() {
          const { list } = this
          if (list.length === 0) return null
          this.swap(1, list.length - 1)
          const top = list.pop()
          this.down(1)
          return top
        }
    
        down(k) {
          const { list, left, right, compare } = this
          const size = this.getSize()
          while (left(k) <= size) {
            let _left = left(k)
            if (right(k) <= size && compare(list[right(k)], list[_left])) {
              _left = right(k)
            }
            if (compare(list[k], list[_left])) return
            this.swap(k, _left)
            k = _left
          }
        }
      }
    

    参考文档

    堆-百度百科

    展开全文
  • 何为优先级队列 在简绍优先级队列前,我们先来回顾一下普通队列的特点,即“先进先出(FIFO)...为了满足优先级队列这一特性,可以使用大根堆或者小根堆。 1.大根堆的堆顶元素是整个堆中的最大元素 2.小根堆的堆顶..

    目录

    何为二叉堆

    二叉堆的调整 

    最大堆

    最大堆的插入操作

    最大堆的删除操作 

    最大堆的构建

    最大堆code

    最小堆 

    小根堆的插入操作

    最小堆的删除操作 

    最小堆的构建

    最小堆code 

    二叉堆的存储方式


    何为二叉堆

    二叉堆本质上是一种完全二叉树,它分为两个类型:

    • 最大堆
    • 最小堆 

    二叉堆的调整 

    对于二叉堆,如下有几种操作:

    • 插入节点:无论是大根堆还是小根堆,插入节点都是从完全二叉树的最后一个位置进行的,插入后再自下向上的调整,这一过程被称为“上浮”。
    • 删除节点:无论是大根堆还是小根堆,删除的节点都是当前完全二叉树的堆顶元素,接着再将当前完全二叉树的最后一个节点补到原本堆顶的位置,然后再进行自上向下的调整,这一过程被称为“下沉”。
    • 构建二叉堆:构建二叉堆,也就是把一个无序的完全二叉树调整为二叉堆,本质上就是让所有非叶子节点依次下沉

    这几种操作都是基于堆的自我调整。

    最大堆

     所谓的最大堆是指任何一个父节点的值,都大于等于它左右孩子节点的值。例如下图所表示的完全二叉树就是一个最大堆。

    二叉堆的根节点叫做堆顶。最大堆的堆顶是整个堆中的最大元素。

    最大堆的插入操作

    现在有如下一个大根堆

    现在我们进行插入操作,插入节点21,即先将它插入到完全二叉树的最后一个位置。

    接着进行“上浮”调整

    最大堆的删除操作 

    现在有如下一个大根堆 

    删除节点20

    再将当前完全二叉树的最后一个节点补到原本堆顶的位置

    进行“下沉”调整

    最大堆的构建

    所谓最大堆的构建是指,将n个元素先顺序放入一个二叉树中形成一个完全二叉树,然后来调整各个结点的位置来满足最大堆的特性。 

    现有如下一个无序完全二叉树

    现在要将它变为一个最大堆,首先我们从该完全二叉树中的最后一个非叶子节点为根节点的子树进行调整,然后依次去找倒数第二个倒数第三个非叶子节点...

    该完全二叉树的第一个非叶子结点为87

     该完全二叉树的第二个非叶子结点为30

      该完全二叉树的第三个非叶子结点为83

      该完全二叉树的第四个非叶子结点为43

      该完全二叉树的第五个非叶子结点为66

    最后到根结点79

    最大堆code

    	void FilterUp(int begin)//上浮操作   插入  大根堆
    	{
    		int j = begin, i = (j - 1) / 2;
    		Type tmp = data[j];
    		while (j > 0)
    		{
    			if (data[i] >= tmp) break;
    			data[j] = data[i];
    			j = i;
    			i = (j - 1) / 2;
    		}
    		data[j] = tmp;
    	}
    
        
        void FilterDown(int begin, int end)//下沉操作  删除  大根堆
    	{ 
    		int i = begin, j = i * 2 + 1;//j是左孩子
    		Type tmp = data[i];
    		while (j <= end)
    		{
    			if (j < end && data[j] < data[j + 1]) ++j;
    			if (tmp >= data[j]) break;
    			data[i] = data[j];
    			i = j;
    			j = i * 2 + 1;
    		}
    		data[i] = tmp;
    	}

    最小堆 

    所谓的最小堆是指任何一个父节点的值,都小于等于它左右孩子节点的值。例如下图所表示的完全二叉树就是一个最小堆。 

    最小堆的堆顶是整个堆中的最小元素。 

    小根堆的插入操作

    二叉堆的节点插入,插入位置是完全二叉树的最后一个位置。比如我们插入一个新节点,值是 0。

    这时候,我们让节点0的它的父节点5做比较,如果0小于5,则让新节点“上浮”,和父节点交换位置。

    继续用节点0和父节点3做比较,如果0小于3,则让新节点继续“上浮”。

    继续比较,最终让新节点0上浮到了堆顶位置。

    最小堆的删除操作 

    我们删除最小堆的堆顶节点1。

    这时候,为了维持完全二叉树的结构,我们把堆的最后一个节点10补到原本堆顶的位置。

    接下来我们让移动到堆顶的节点10和它的左右孩子进行比较,如果左右孩子中最小的一个(显然是节点2)比节点10小,那么让节点10“下沉”。

    继续让节点10和它的左右孩子做比较,左右孩子中最小的是节点7,由于10大于7,让节点10继续“下沉”。

    这样一来,二叉堆重新得到了调整。

    最小堆的构建

    构建二叉堆,就是把一个无序的完全二叉树调整为二叉堆,本质上就是让所有非叶子节点依次下沉

    我们举一个无序完全二叉树的例子:

    首先,我们从最后一个非叶子节点开始,也就是从节点10开始。如果节点10大于它左右孩子中最小的一个,则节点10下沉。

    接下来轮到节点3,如果节点3大于它左右孩子中最小的一个,则节点3下沉。

    接下来轮到节点1,节点1小于它的左右孩子,所以不用改变。

    接下来轮到节点7,如果节点7大于它左右孩子中最小的一个,则节点7下沉。

    节点7继续比较,继续下沉。

    最小堆code 

    	void FilterDown(int begin, int end)//下沉操作  删除  小根堆
    	{
    		int i = begin, j = i * 2 + 1;//i指向根结点
    		Type tmp = data[i];//用来保存当前根结点的值
    		while (j <= end)
    		{
    			if (j < end && data[j] > data[j + 1]) ++j;//j指向左右孩子中值较小的那个节点
    			if (tmp <= data[j]) break;//如果当前根结点的值小于它两个孩子,则不需要调整
    			data[i] = data[j];//否则替换根结点和比他小的孩子结点的值
    			i = j;//i指向替换后的根节点的位置
    			j = i * 2 + 1;
    		}
    		data[i] = tmp;
    	}
    
    
    	void FilterUp(int begin)//上浮操作   插入   小根堆
    	{
    		int j = begin, i = (j - 1) / 2;
    		Type tmp = data[j];
    		while (j > 0)
    		{
    			if (data[i] <= tmp) break;
    			data[j] = data[i];
    			j = i;
    			i = (j - 1) / 2;
    		}
    		data[j] = tmp;
    	}

    二叉堆的存储方式

    二叉堆虽然是一颗完全二叉树,但它的存储方式并不是链式存储,而是顺序存储。也就是说,二叉堆的所有节点都存储在数组当中。

    数组中,在没有左右指针的情况下,可以像图中那样,依靠数组下标来计算。

    假设父节点的下标是parent,那么它的左孩子下标就是 2*parent+1;它的右孩子下标就是  2*parent+2 

    比如上面例子中,节点6包含9和10两个孩子,节点6在数组中的下标是3,节点9在数组中的下标是7,节点10在数组中的下标是8。

    7 = 3*2+1

    8 = 3*2+2

    原文参考连接:

    最大堆(创建、删除、插入和堆排序) - 简书 (jianshu.com)

    https://mp.weixin.qq.com/s/cq2EhVtOTzTVpNpLDXfeJg

    展开全文
  • 优先级队列,C++的容器适配器,底层是默认实现的大根堆结构。 二叉堆,这个堆本身还是用数组存储着元素,物理上还是用数组存储的元素,只不过在逻辑上把它看成有1个入口的根节点,每1个节点都有2个孩子,没有孩子的...
  • 大根堆Java实现

    2022-03-26 11:41:12
    // 大根堆建立 // 核心方法:heapInsert和heapify /** * 插入元素时候:堆上升 * 删除元素时候:堆下沉 * 堆排序和删除相关 */ public class BigHeap{ // 大根堆 private int[] heap; // 堆结构 private int ...
  • 大根堆(堆排序)

    2022-05-27 21:42:01
    大根堆:同理,任何子树的最大值是它的头节点。 我们可以使用一个数组表示堆 当头结点为i时,左节点为 2i+1,右节点 为2i+2,父节点 为(i-1)/2 我们可以使用系统的堆PriorityQueue(优先队列),没设置比较器的时候为小根...
  • 图解大根堆的堆排序

    万次阅读 多人点赞 2020-03-30 22:09:55
    文章目录1 大根堆2 创建堆,heapInsert 1 大根堆 进行堆排序之前,需要先明确大根堆的概念,大根堆就是根节点是整棵树的最大值(根节点大于等于左右子树的最大值),对于他的任意子树,根节点也是最大值。大根堆有两个...
  • 大根堆排序

    2021-07-25 13:00:02
    堆排序 序言 排序算法分为: 1、插入排序 2、交换排序 3、选择排序 4、归并排序 5、基数排序 一、介绍大根堆排序 ...本篇博客主要讲解大根堆排序,什么是大根堆??? 大根堆实际上是一颗完全二叉树,在完
  • 因为插入一个元素时,列表已经是一个大根堆,所以当出现父元素大于自己时,就没有必要继续,因为父元素的父元素值更大。 shift down 删除一个元素时,把该元素和列表的最后一个元素交换。然后列表的长度减一(如果...
  • 堆排序——大根堆

    2021-10-23 22:12:02
    堆:在完全二叉树上有其他要求,大根堆和小根对 */ type MyMaxHeap struct { Heap []int Limit int HeapSize int // 已经收集了多少个数,及其新来的数放在哪里 } func NewMyMaxHeap(limit int) *MyMaxHeap { ...
  • 堆(大根堆、小根堆)

    万次阅读 多人点赞 2020-05-26 20:51:02
    本文介绍完全二叉堆,包括大根堆、小根堆。相关的算法堆(大根堆、小根堆)的插入、删除、批量建立。
  • 大根堆的结构为完全二叉树 任意一颗子树的最大值在树根上,其根节点和子节点的坐标索引关系为,i位置的节点的:具体大根堆的介绍和实现参考另外一篇文章 左子节点索引为:2*i+1 右子节点索引坐标为:2*i+2 父节点...
  • 如何构造大根堆

    2021-08-15 21:33:45
    如何构造一个大顶堆(C实现) 基础知识 堆是一种二叉树结构,但是他的物理保存是一个数组,如下图 实际的保存形式为 ...**大根堆的概念:**从根结点开始,每一个结点的值都大于其两个孩子结点的值 接下来
  • 2.大根堆如果根是儿童的存在留下的根值多名离开自己的孩子值。子女则根节点的值大于右子女的值。3.结论(1)堆是一棵全然二叉树(假设公有h层,那么1~h-1层均满,在h层连续缺失若干个右叶子)。(2)小根堆的根节点的值是...
  • 2.大根堆若根节点存在左子女则根节点的值大于左子女的值;若根节点存在右子女则根节点的值大于右子女的值。3.结论(1)堆是一棵完全二叉树(如果公有h层,那么1~h-1层均满,在h层连续缺失若干个右叶子)。(2)小根堆的根...
  • (二叉)数据结构是一种数组对象,如图所示(下标从0开始),它完全可以被视为一棵完全二叉树。 接下来要出现的几个词语,这里介绍一下:length[A]: 数组A中元素的个数heap-size[A]: 存放在数组A中的元素的个数,是要...
  • 这里以大根堆举例,适时的会说一下小根堆 讲解代码 目录说在前面两个重要函数siftDown() 和 siftUp()堆的建立插入结点删除结点堆排序全部代码 说在前面 首先,了解一下大根堆or小根堆 (下面简称’堆’)的性质。 ...
  • 堆(大根堆与小根堆)
  • 小根堆和大根堆

    2022-04-06 22:05:21
    大根堆即指在逻辑上的二叉树结构中,根结点>子结点,总是最大的,并且在堆的每一个局部都是如此。 根结点<子结点。例如{1,2,3}为小根堆,{1,3,2}同样也是小根堆。小根堆的根结点在整个堆中是最小的元素。 小根...
  • 文章目录C语言实现堆排序大根堆排序算法1.交换操作2.对结点进行调整为大根堆3.建立大根堆4.大根堆排序算法实现小根堆排序算法1.交换操作2.对结点进行调整为小根堆3.建立小根堆4.大根堆排序算法实现项目完整代码运行...
  • 文章目录四、堆、改进堆、对排序及其应用1、堆和完全二叉树2、用数组实现大根堆3、堆排序4、加强堆(小根堆) 四、堆、改进堆、对排序及其应用 1、堆和完全二叉树 堆(heap)是计算机科学中一类特殊的数据结构的统称...
  • //构建大根堆:将array看成完全二叉树的顺序存储结构 private int[] buildMaxHeap(int[] array){ //从最后一个节点array.length-1的父节点(array.length-1-1)/2开始,直到根节点0,反复调整堆 for(int i=(array....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 24,431
精华内容 9,772
关键字:

大根堆

友情链接: tousumail.rar