优先级队列 (堆)

news2024/7/6 20:51:57

目录

一,堆的概念

二, 堆的存储结构

三, 堆的实现

3.1 shiftDown()

3.2 shiftUp()

3.3 shiftDown 与 shiftUp 的时间复杂度

四,堆排序


一,堆的概念

堆常用于实现优先队列(Priority Queue)等应用,其中可以快速查找和删除具有最大(或最小)优先级的元素。堆的操作包括插入新元素、移除堆中的顶部元素(即最值),以及对现有堆进行调整以满足堆序属性。常见的堆调整操作是"上浮"(上滤)和"下沉"(下滤)

堆具有以下两个主要特点:

  1.  堆是一个完全二叉树
  2.  堆中的每个节点的值都要大于等于(或小于等于)其子节点的值。

二, 堆的存储结构

从堆的概念可知,堆在逻辑结构上是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储,也就是说,堆是使用顺序表来存储的,画个图理解一下:

 将元素存储到数组中后,可以根据完全二叉树的性质对树进行还原。假设i为节点在数组中的下标,则有:

  • 如果i = 0,则 i 表示的节点为根节点,否则 i 节点的双亲节点为 (i - 1)/2
  • 如果2 * i + 1 小于节点个数,则节点 i 的左孩子下标为2 * i + 1,否则没有左孩子
  • 如果2 * i + 2 小于节点个数,则节点 i 的右孩子下标为2 * i + 2,否则没有右孩子

三, 堆的实现

在此实现的是大根堆:

public class Heap {
    private int[] elem;
    private int usedSize;

    public Heap(int[] arr){
        elem = new int[arr.length];
        createHeap(arr);
    }

    //建堆
    public void createHeap(int[] arr){
        for (int i = 0; i < arr.length; i++) {
            elem[i] = arr[i];
            usedSize++;
        }
        for (int parent = (usedSize-2)/2; parent >= 0; parent--) {
            shiftDown(parent,usedSize);
        }
    }

    //向下调整
    public void shiftDown(int parent, int len){}

    public void swap(int i, int j){
        int tmp = elem[i];
        elem[i] = elem[j];
        elem[j] = tmp;
    }

    //入堆
    public void push(int val){}

    public boolean isFull(){
        return usedSize == elem.length;
    }

    //向上调整
    public void shiftUp(int child){}

    //出堆顶元素
    public int poll(){
        if(isEmpty()){
            System.out.println("堆中没有元素");
            return -1;
        }
        swap(0,usedSize-1);//将头尾交换
        usedSize--;//去掉堆顶元素
        shiftDown(0,usedSize);//重新排序
        return elem[usedSize];//返回堆顶元素
    }

    public boolean isEmpty(){
        return usedSize == 0;
    }

    //得到堆顶元素
    public int peek(){
        if(!isEmpty()){
            return elem[0];
        }
        System.out.println("堆中没有元素");
        return -1;
    }
}

堆中最核心的代码就是 shiftDown() 和 shiftUp() 方法的实现,其他的方法看看就懂了,下面来详细讲一讲这两个方法的实现

3.1 shiftDown()

比如说我们要将{27,15,19,18,28,34,65,49,25,37}这个数组变成一个堆,我们要如何实现,思路:先找到最后一棵子树,将它变成堆后,依次遍历其他的子树,直到最后一棵子树的根节点是整棵树的根节点结束,看下图: 

代码如下:

    public void shiftDown(int parent, int len){
        int child = 2*parent + 1;
        while(child < len){
            if(child+1 < len && elem[child] < elem[child+1]){
                child++;
            }
            if(elem[parent] < elem[child]){
                swap(parent,child);
                parent = child;
                child = 2*parent + 1;
            }else{
                break;
            }
        }
    }

3.2 shiftUp()

该方法是在插入一个元素时,将其以堆的形式插入,本质上shiftDown 与 shiftUp 的思路差不多:

 

    public void shiftUp(int child){
        int parent = (child-1)/2;
        while(parent >= 0){
            if(elem[child] > elem[parent]){
                swap(child,parent);
                child = parent;
                parent = (child-1)/2;
            }else {
                break;
            }
        }
    }

3.3 shiftDown 与 shiftUp 的时间复杂度

 ​​​​​​​

四,堆排序

比如我们要进行升序排序,我们先要建立一个大根堆,再将根节点与最后一个节点交换,这个时候最后一个节点一定是的最大的,然后进行shiftDown,再将根节点与倒数第二个节点交换,依次类推。代码如下:

/**
     * 堆排序
     * 时间复杂度:O(N*logN)
     * 空间复杂度:O(1)
     * 不稳定
     */
    public void heapSort(int[] arr){
        createHeap(arr);
        int end = arr.length-1;
        while(end > 0){
            swap(arr,0,end);
            shiftDown(arr,0,end);
            end--;
        }
    }
    private void shiftDown(int[] arr, int parent,int len) {
        int child = 2*parent+1;
        while(child < len){
            if(child+1 < len && arr[child] < arr[child+1]){
                child++;
            }
            if(arr[child] > arr[parent]){
                swap(arr,child,parent);
                parent = child;
                child = 2*parent+1;
            }else{
                break;
            }
        }
    }
    public void swap(int[] arr, int i, int j){
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public void createHeap(int[] array) {
        for (int parent = (array.length-2)/2; parent >= 0; parent--) {
            shiftDown(array,parent,array.length);
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/822395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【算法训练营】求最小公倍数+另类加法+走方格的方案数

7月31日 求最小公倍数题目题解代码 另类加法题目题解代码 走方格的方案数题目题解| 1 | 2 | 3 || 4 | 5 | 6 || 7 | 8 | 9 |代码 求最小公倍数 题目 点击跳转: 求最小公倍数 题解 最小公倍数 两数之积除以最大公约数&#xff0c;这里使用碾转相除法进行最大公约数的求解&am…

学习盒模型

1.是什么 2.标准模型 3.怪异模型 一、是什么 一个盒子由四部分组成&#xff1a; content、padding、border、margin 在CSS中&#xff0c;盒子模型可以分成&#xff1a; W3C 标准盒子模型IE 怪异盒子模型 默认情况下&#xff0c;盒子模型为W3C标准盒模型 二、标准盒模型 盒子总…

NetApp FAS存储系统磁盘更换详细步骤

说起更换磁盘&#xff0c;都会说非常简单&#xff0c;但无数次的血淋淋的教训让我们再次来审视一下更换磁盘的专业步骤。本文就是介绍最专业的也是最简单的磁盘更换步骤。常在河边走哪有不湿鞋&#xff0c;希望做了几十年攻城狮的你不要在这里翻船。 本文介绍的内容适用于Onta…

ELK日志管理平台架构和使用说明

一、部署架构 二、服务注册 2.1 日志解析服务 服务名&#xff1a;日志解析服务&#xff08;Logstash&#xff09; 服务默认端口&#xff1a;9600 2.2 日志查询服务 服务名&#xff1a;日志查询服务&#xff08;Kibana&#xff09; 服务默认端口&#xff1a;5601 三、对接…

光纤激光切割机是否属于环保设备

光纤激光切割机不属于环保设备。 环保设备是指用于控制环境污染、改善环境质量而由生产单位或建筑安装单位制造和建造出来的机械产品、构筑物及系统。 单纯的激光切割机当前是豁免环评的&#xff0c;比起普通二氧化碳激光切割机更节省空间和气体消耗量&#xff0c;光电转化率高…

C语言手撕单链表

一、链表的概念 链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;也就是内存存储不是像顺序表那么连续存储&#xff0c;而是以结点的形式一块一块存储在堆上的&#xff08;用动态内存开辟&#xff09;。 既然在内存上不是连续存储&#xff0c;那我们如何将这一…

代码随想录算法训练营第二十八天 | Leetcode随机抽题检测

Leetcode随机抽题检测--使用题库&#xff1a;Leetcode热题100 1 两数之和未看解答自己编写的青春版重点题解的代码日后再次复习重新写 49 字母异位词分组未看解答自己编写的青春版重点题解的代码日后再次复习重新写 128 最长连续序列未看解答自己编写的青春版重点关于 left 和 …

谷歌浏览器提示客户端和服务器不支持一般 SSL 协议版本或加密套件(亲测有效)

目录 一、定位问题二、升级TLS1.21、原理之前架构调整架构 2、配置nginx3、配置tomcat 三、访问nginx即可 最近访问一部分网站时&#xff0c;出现如下图所示 “ 此网站无法提供案例连接&#xff0c;客户端和服务器不支持一般 SSL 协议版本或加密套件 ” 的问题。 一、定位问题…

AIGC之AI绘画行业发展研究报告(2023)

全部140页&#xff0c;完整版pdf下载见文末。 链接&#xff1a;AIGC之AI绘画行业发展研究报告&#xff08;2023&#xff09; 提取码&#xff1a;关注 未来人智慧 回复 AIGC之AI绘画行业发展研究报告&#xff08;2023&#xff09;

C语言每日一题:11.《数据结构》链表分割。

题目一&#xff1a; 题目链接&#xff1a; 思路一&#xff1a;使用带头链表 1.构建两个新的带头链表&#xff0c;头节点不存储数据。 2.循环遍历原来的链表。 3.小于x的尾插到第一个链表。 4.大于等于x尾插到第二个链表。 5.进行链表合并&#xff0c;注意第二个链表的尾的下一…

IO进程线程第四天(8.1)

作业1&#xff1a; 从终端获取一个文件的路径以及名字。 若该文件是目录文件&#xff0c;则将该文件下的所有文件的属性显示到终端&#xff0c;类似ls -l该文件夹 若该文件不是目录文件&#xff0c;则显示该文件的属性到终端上&#xff0c;类似ls -l这单个文件 #include<…

ad+硬件每日学习十个知识点(16)23.7.27 (总线保持、lin报文、逻辑器件手册解读)

文章目录 1.总线保持是怎么实现的&#xff1f;有什么需要注意的&#xff08;驱动电流和电阻&#xff09;&#xff1f;2.LIN报文3.芯片datasheet的features、applications、description看完&#xff0c;应该能大致判断逻辑器件能否满足我们的要求。4.什么是逻辑器件的传输延时&a…

系统架构设计师_备考第1天

文章目录 前言一、软考历史与体系二、考试价值与意义三、软考报名与交费四、考试介绍五、综合备考策略 前言 从今天开始&#xff0c;会认真备考系统架构设计师&#xff0c;希望95天后&#xff0c;拿下软考证书。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可…

P3372 【模板】线段树 1(内附封面)

【模板】线段树 1 题目描述 如题&#xff0c;已知一个数列&#xff0c;你需要进行下面两种操作&#xff1a; 将某区间每一个数加上 k k k。求出某区间每一个数的和。 输入格式 第一行包含两个整数 n , m n, m n,m&#xff0c;分别表示该数列数字的个数和操作的总个数。 …

深度学习(33)——CycleGAN(1)

深度学习&#xff08;33&#xff09;——CycleGAN&#xff08;1&#xff09; 完整项目在在这里&#xff1a;欢迎造访 文章目录 深度学习&#xff08;33&#xff09;——CycleGAN&#xff08;1&#xff09;1. Generator2. Discriminator3. fake pool4. loss定义5. 模型参数量6…

Nodejs 第七章(发布npm包)

发布npm的包的好处是什么 方便团队或者跨团队共享代码&#xff0c;使用npm包就可以方便的管理&#xff0c;并且还可以进行版本控制做开源造轮子必备技术&#xff0c;否则你做完的轮子如何让别人使用难道是U盘拷贝&#xff1f;面试题我面字节的时候就问到了这个增加个人IP 让更…

消息队列之 - 消息持久化设计

目录 前言设计思想消息文件的格式垃圾回收的思想其他情况序列化和反序列化 具体代码实现测试消息文件 前言 我们之前说过, 消息队列不管要往硬盘中存储, 还要往内存中存储, 并且是以内存为主 ,硬盘为辅, 接下来, 就将消息队列如何存储到硬盘 做一个设计 设计思想 我们往硬盘…

云服务器无法远程连接服务

问题 今天刚买了华为的云服务器&#xff0c;通过宝塔安装了对应的基础服务&#xff0c;也在华为云的官网上设置了安全组。此时万事俱备只欠东风&#xff0c;我测试使用sqlyog进行远程连接。原本已经在准备部署项目了&#xff0c;现实给了我重重的一拳。 sqlyog爆2003代码错误&…

交换机VLAN技术和实验(eNSP)

目录 一&#xff0c;交换机的演变 1.1&#xff0c;最小网络单元 1.2&#xff0c;中继器&#xff08;物理层&#xff09; 1.3&#xff0c;集线器&#xff08;物理层&#xff09; 1.4&#xff0c;网桥&#xff08;数据链路层&#xff09; 二&#xff0c;交换机的工作行为 2.…

IO进线程——库的制作(静态库、动态库)

库的制作 1、静态库 ①生成二进制文件 gcc -c linkstack.c -o linkstack.o②制作静态库文件&#xff0c;把.o文件转换为.a文件 ar crs liblinkstack.a linkstack.o③编译时链接 gcc linkstack_main.c -L. -llinkstack2、动态库 ①生成地址无关二进制文件 gcc -fPIC -c l…