数据结构之优先级队列(堆)

2023-11-10

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、二叉树的顺序存储

1.存储方式

使用数组保存二叉树结构,方式即将二叉树用层序遍历方式放入数组中。
一般只适合表示完全二叉树,因为非完全二叉树会有空间的浪费。
这种方式的主要用法就是堆的表示。
在这里插入图片描述
在这里插入图片描述

2.下标关系

已知双亲(parent)的下标,则:
左孩子(left)下标 = 2 * parent + 1;
右孩子(right)下标 = 2 * parent + 2;
已知孩子(不区分左右)(child)下标,则:
双亲(parent)下标 = (child - 1) / 2

二、堆

概念

  1. 堆逻辑上是一棵完全二叉树
  2. 堆物理上是保存在数组中
  3. 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆,或者最大堆
  4. 反之,则是小堆,或者小根堆,或者最小堆
  5. 堆的基本作用是,快速找集合中的最值

创建大根堆

public class MyPriorityQueue {
    public int[] elem;
    public int uizSize;
    MyPriorityQueue(){
        this.elem = new int[10];
    }
    public void adjustDown(int parent , int len){
        int child = 2*parent+1;
        //用来保证child是孩子节点的最大值
        while(child < len){
            if(child+1 < len && this.elem[child] < this.elem[child+1]){
                child++;
            }
            if (this.elem[child] > this.elem[parent]){
                //交换
                int tmp = this.elem[child];
                this.elem[child] = this.elem[parent];
                this.elem[parent] = tmp;
                //交换后继续走
                parent = child;
                child = 2*child+1;
            }else{
                break;
            }
        }
    }
    //创建大根堆
    public void createHeap(int[] array){
        for (int i = 0; i < array.length; i++) {
            this.elem[i] = array[i];
            this.uizSize++;
        }
        for (int p = (this.uizSize-1-1)/2; p >= 0 ; p--) {
            //每棵树的调整方案
            adjustDown(p,this.uizSize);
        }
    }
}

建堆的时间复杂度
从代码和思想来看为O(n*log(n));
而实际上是O(n);
建堆的过程中时间复杂度On的由来

三、堆的应用及相关操作

入队列

1.使用尾插的方式放入数组
2. 比较其和其双亲的值的大小,如果双亲的值大,则满足堆的性质,插入结束
3. 否则,交换其和双亲位置的值,重新进行 2、3 步骤
4. 直至根节点

    public void adjustUp(int child){
        int parent = (child-1)/2;
        while(child > 0){
            if(this.elem[child] > this.elem[parent]){
                int tmp = this.elem[child];
                this.elem[child] = this.elem[parent];
                this.elem[parent] = tmp;
                child = parent;
                parent = (child-1)/2;
            }else{
                break;
            }
        }
    }
    //入队列
    public void push(int key){
        if(this.elem.length == this.uizSize){
            this.elem = Arrays.copyOf(this.elem,this.elem.length*2);
        }
        this.elem[this.uizSize] = key;
        this.uizSize++;
        adjustUp(this.uizSize-1);
    }

出队列

为了防止破坏堆的结构,删除时并不是直接将堆顶元素删除,而是用数组的最后一个元素替换堆顶元素,然后通过向下调整方式重新调整成堆

public void adjustDown(int parent , int len){
        int child = 2*parent+1;
        //用来保证child是孩子节点的最大值
        while(child < len){
            if(child+1 < len && this.elem[child] < this.elem[child+1]){
                child++;
            }
            if (this.elem[child] > this.elem[parent]){
                //交换
                int tmp = this.elem[child];
                this.elem[child] = this.elem[parent];
                this.elem[parent] = tmp;
                //交换后继续走
                parent = child;
                child = 2*child+1;
            }else{
                break;
            }
        }
    }
//出队列
    public int pop()throws UnsupportedClassVersionError{
        if(isEmpty()){
            throw new UnsupportedOperationException("队列为空");
        }
        int tmp = this.elem[this.uizSize-1];
        this.elem[uizSize-1] = this.elem[0];
        this.elem[0] = tmp;
        this.uizSize--;
        adjustDown(0,this.uizSize);
        return tmp;
    }
    public boolean isEmpty(){
        return this.uizSize == 0;
    }

得到队头元素

public int getTop()throws UnsupportedClassVersionError{
        if(isEmpty()){
            throw new UnsupportedOperationException("队列为空");
        }
        return this.elem[0];
    }
    public boolean isEmpty(){
        return this.uizSize == 0;
    }

四、Java中的优先级队列

PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();

这时就创建了一个优先级队列

细节问题

由这几行代码可知,默认创建的为一个小堆队列。

        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(15);
        priorityQueue.offer(60);
        priorityQueue.offer(30);
        priorityQueue.offer(25);
        System.out.println(priorityQueue.peek());

创建一个大堆队列

PriorityQueue<Integer> priorityQueue =
                new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });

使用比较器来进行创建大堆
重写了Comparator的方法

指定堆的大小来进行创建

PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(10, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });

其中在创建对象时给定第一个参数为int类型,则会创建出对应大小的堆

五、Topk问题

典型问题:给定一个数值为1000的数组,来找出最大的10个数

public static void topK(int k,int array[]){
        //1.建立大小为k的小堆
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
        //2.遍历数组元素,将前k个元素放到小堆
        for (int i = 0; i < array.length; i++) {
            if(k > 0){
                priorityQueue.offer(array[i]);
            }else {
                //3.从第k+1个值开始 和 堆顶元素比较。
                //4.当前元素比堆顶大 那么,先出pop,后入offer
                if(array[i]>priorityQueue.peek()){
                    priorityQueue.poll();
                    priorityQueue.offer(array[i]);
                }
            }
        }
        //5.输入堆里面的元素就好了
        System.out.println(priorityQueue);
    }

六、堆排序

public void heapSort(){
        int end = this.uizSize-1;
        while(end > 0){
            int tmp = this.elem[0];
            this.elem[0] = this.elem[end];
            this.elem[end] = tmp;
            adjustDown(0,end);
            end--;
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构之优先级队列(堆) 的相关文章

  • 【STM32】定时器中断原理及操作

    目录 时钟的选择及分频 定时器中断有关的寄存器 定时器中断有关的库函数 1 时钟使能函数 RCC APB1PeriphClockCmd 2 定时器初始化函数 TIM TimeBaseInit 3 定时器中断使能 选择函数 TIM ITCon
  • 车辆路径问题

    车辆路径问题 提示 这里可以添加系列文章的所有文章的目录 目录需要自己手动添加 利用Python和Gurobi求解VRPSPDTW 考虑需求动态变化的共享单车调度问题研究 提示 写完文章后 目录可以自动生成 如何生成可参考右边的帮助文档 文
  • 用python实现二分查找(折半查找)

    文章目录 一 算法简介 二 算法思路 三 具体编码 一 算法简介 折半查找又叫二分查找 要求线性表必须采用顺序存储结构 而且表中元素按关键字有序排列 升序或者降序 时间复杂度 O log2n 每次循环都会舍弃一半的查找空间 空间复杂度 O

随机推荐

  • 利用读时建模等数据分析能力,实现网络安全态势感知的落地

    摘要 本文提出一种基于鸿鹄数据平台的网络安全态势感知系统 系统借助鸿鹄数据平台读时建模 时序处理 数据搜索等高效灵活的超大数据存储和分析处理能力 支持海量大数据存储 分类 统计到数据分析 关联 预测 判断的网络安全态势感知能力需求 以安全大
  • HttpRequest中常见的四种ContentType

    HTTP 1 1 协议规定的 HTTP 请求方法有 OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT 这几种 其中 POST 一般用来向服务端提交数据 本文主要讨论 POST 提交数据的几种方式
  • python中的GIL详解

    python中的GIL详解 参考Python GIL 锁简述 GIL是什么 首先需要明确的一点是GIL并不是Python的特性 它是在实现Python解析器 CPython 时所引入的一个概念 就好比C 是一套语言 语法 标准 但是可以用不
  • mysql启动失败:mysql服务无法启动 服务没有报告任何错误 解决方法

    1 一开始无法启动时因为mysql安装目录下我没有Data文件夹 而我的my ini文件通过查找默认在C ProgramData MySQL MYSQL Server 8 0于是参考mysql无法启动 服务没有报任何错误 进行了如下部分更改
  • 游戏开发物理引擎PhysX研究系列:学习链接

    参考 基础介绍 原 译 physX phsyX3 3 4官方文档物理引擎基本概念和例子介绍 如何使用官方自带的demo Nvidia PhysX 学习文档2 Snippets PhysX 物理引擎研究 一 源码编译 在 Net平台使用Phy
  • 码云使用pull request出现无法合并

    在使用码云的时候 常常会因为各种各样的原因而出现冲突这里就来讲一下如何解决 再做第一步之前先把你要上传的文件copy出来然后解决冲突后再把他们扔进去上传 那第一步先来查看我们的源 git remote v 那么很明显我这里有一个origin
  • 非root用户-elastic-stack日志收集系统的规划及部署

    架构图 192 168 140 17 ELK 1 4核 8G 250G centos7 8 ES1 kibana 192 168 140 18 ELK 2 4核 8G 250G centos7 8 ES2 192 168 140 19 EL
  • 【数据结构】图的实现

    文章目录 图 1 图的基本概念 2 图的存储结构 3 邻接矩阵 3 1邻接矩阵的优缺点 3 2邻接矩阵的实现 4 邻接表 4 1邻接表的实现 5 图的遍历 5 1广度优先遍历 5 2深度优先遍历 5 3如何遍历不连通的图 图 1 图的基本概
  • Verilog学习记录3——三目运算符

    三目运算符 三目运算符 assign a b c d 等同于 if b true a c else a d 进阶示例 以牛客网 VL1 四选一多路器 为例 timescale 1ns 1ns module mux4 1 input 1 0
  • ML-Agents案例之双人足球

    本案例源自ML Agents官方的示例 Github地址 https github com Unity Technologies ml agents 本文是详细的配套讲解 本文基于我前面发的两篇文章 需要对ML Agents有一定的了解 详
  • Java的测试方法有哪些?自动化测试让Java测试变得更简单!

    Java现在是后端和前端开发项目中使用最广泛的服务器端语言之一 凭借如此庞大的活跃社区 Java 多年来一直保持着世界三大最受欢迎编程语言的地位 Java 之所以如此成功 是因为它的技术标准在不断发展 而且 Java 将在没有强大竞争对手的
  • iOS App 连接外设的几种方式

    原创作者 Max Marry 文章地址 http www jianshu com p 852bf92c5c92 随着近年来车联网和物联网的兴起 智能家居和智能硬件的逐步火热 越来越多的 App 被用来跟硬件设备进行来连接 获取硬件相关信息用
  • Android开发必须掌握!Kotlin可能带来的一个深坑,使用指南

    1 项目介绍 Flutter是目前比较流行的跨平台开发技术 凭借其出色的性能获得很多前端技术爱好者的关注 比如阿里闲鱼 美团 腾讯等大公司都有投入相关案例生产使用 基于Flutter Dart chewie photo view image
  • 聊一聊 Java 中的 ThreadLocal

    前言 本文首发于我的个人博客 http yifanstar top 提到 ThreadLocal Java 开发者并不陌生 在面试中 也经常被面试官提及 对 Java 开发者而言也是一个必须掌握的知识点 所以将它理解透彻是很有必要的 文章稍
  • linux下lpython查版本信息,ln进行python软连接、find、which进行环境变量文件查找、ps进行进程查看、/usr/local/为软件安装主目录-new

    1 查看某个安装包的版本信息指令 python m django version 如果是查看其它安装包的信息则改为其它包名即可 2 ln进行python版本软连接 安装python3 5推荐使用Anaconda 推荐安装到 usr loca
  • 推荐9个最顶级的IT公众号

    固步自封只会让自己落后于他人 如今 网络已将人与人之间的距离拉近 我们应开拓自己的眼界 结识更多的大能来丰富自己的知识 以下是8个技术公众号 每日共享最新的技术资讯 快收下这波安利吧 stormzhang stormzhang 大家都喊他张
  • Python pip install 安装包报错ERROR: Could not find a version that satisfies the requirement XXX解决方法

    Python pip install 安装包报错ERROR Could not find a version that satisfies the requirement XXX解决方法 文章目录 Python pip install 安装
  • 利用arp欺骗获取局域网目标浏览的图片

    之前的实验中实现了arp断网攻击 这是arp欺骗错误配置下产生的现象 所谓arp欺骗 就是在断网攻击的前提下 让流量转发出去 原理 使目标主机认为攻击者的网卡是网关 从而将数据包都发给攻击者的网卡 攻击者的网卡再开启转发 将数据包传到真正网
  • 毕业设计 单片机选题100例(五)

    单片机毕业设计项目分享系列 这里是DD学长 单片机毕业设计及享100例系列的第一篇 目的是分享高质量的毕设作品给大家 包含全面内容 源码 原理图 PCB 实物演示 论文 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的单片机项目缺少
  • 数据结构之优先级队列(堆)

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 一 二叉树的顺序存储 1 存储方式 2 下标关系 二 堆 概念 创建大根堆 三 堆的应用及相关操作 入队列 出队列 得到队头元素 四 Java中的优先级队列 细节问