优先级队列(堆)——小记

news2025/7/18 7:10:44

文章目录

      • 概念
      • 堆的创建
        • 堆向下调整
      • 堆的插入
      • 堆的删除
      • 堆排序
      • 整体代码(创建堆(向下调整),堆的插入,堆的删除,堆排序)
      • TOPK
      • PriorityQueue特性

概念

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

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。
    在这里插入图片描述

从堆的概念可知,堆是一提完全二叉树,因此可以层序的规则采用顺序的方式来高效存储。
在这里插入图片描述
实质:
1.逻辑上是一棵完全二叉树
  可以按照层序的方式平铺在数组中。
  已知parent 的下标:1) left = 2 * parent + 1;
                     2)right = 2 * parent +2 ;
  已知child (不分左右)的下标:parent = ( child -1 ) / 2

2.物理上是一个数组
3.满足任意位置的值大于等于它左右孩子的值 - -大堆
 满足任意位置的值小于等于它左右孩子的值 - - 小堆

堆的创建

堆向下调整

从根节点开始的向下调整算法可以把它调整
成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

int[] array = { 27,15,19,18,28,34,65,49,25,37 };
在这里插入图片描述
生成大根堆:
在这里插入图片描述

堆的插入

先插入一个80到数组的尾上,再进行向上调整算法,直到满足堆。
在这里插入图片描述

堆的删除

1.0下标和最后一个元素交换
2.向下调整0下标这棵树即可
在这里插入图片描述

堆排序

1.从小到大排序——升序

  • 需要创建一个大根堆
  • 堆顶元素不断与堆尾元素(end下标)进行交换,直到end<=0,即堆尾元素遍历到堆顶。
  • 交换后,从堆顶再向下调整
    在这里插入图片描述
    在这里插入图片描述
    2.从大到小排序——降序

整体代码(创建堆(向下调整),堆的插入,堆的删除,堆排序)

public class TestHeap {

    public int[] elem;
    public int usedSize;

    public TestHeap() {
        this.elem = new int[10];
    }

    /**
     * 向下调整
     * parent:每次调整的根节点
     * len:每次的结束位置
     */
    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++;
            }
            //child下标 一定是左右孩子最大值的下标
            if(elem[child] > elem[parent]) {
                int tmp = elem[parent]; 
                elem[parent] = elem[child];
                elem[child] = tmp;
                parent = child;
                child = 2*parent+1;
            }else {
                break;
            }
        }
    }

    public void createHeap(int[] array) {
        //this.elem = Arrays.copyOf(array,array.length); 不算
        for (int i = 0; i < array.length; i++) {
            elem[i] = array[i];
            this.usedSize++;
        }

        for (int i = (usedSize-1-1)/2; i >= 0 ; i--) {
            shiftDown(i,usedSize);
        }

    }

    /**
     * 向上调整
     * @param child
     */
    public void shiftUp(int child) {
        int parent = (child-1) / 2;
        while (parent >= 0) {
            if(elem[child] > elem[parent]) {
                int tmp = elem[parent];
                elem[parent] = elem[child];
                elem[child] = tmp;
                child = parent;
                parent = (child-1)/2;
            }else {
                break;
            }
        }
    }

    /**
     * 插入一个元素到堆中
     * @param val
     */
    public void push(int val) {
        if(isFull()) {
            this.elem = Arrays.copyOf(this.elem,2*this.elem.length);//扩容
        }
        this.elem[this.usedSize] = val;
        this.usedSize++;
        shiftUp(this.usedSize-1);
    }

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

    /**
     * 出队,删除堆顶元素.
     */
    public int pop() {
        if(isEmpty()) {
            throw new HeapEmptyException("堆为空!");
        }
        int tmp = elem[0];
        elem[0] = elem[this.usedSize-1];
        elem[this.usedSize-1] = tmp;
        this.usedSize--;
        shiftDown(0,this.usedSize);
        return tmp;
    }

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

    /**
     * 堆排序
     */
    public void heapSort() {
        int end = usedSize-1;
        while (end > 0) {
            int tmp = elem[end];
            elem[end] = elem[0];
            elem[0] = tmp;
            shiftDown(0,end);
            end--;
        }
    }

    public void heapSort1() {
        //createHeap();创建一个大根堆
        int end = usedSize-1;
        while (end > 0) {
            int tmp = elem[end];
            elem[end] = elem[0];
            elem[0] = tmp;
            shiftDown(0,end);
            end--;
        }
    }

}

TOPK

代码可参考之前的博客: TOPK
在这里插入图片描述

PriorityQueue实现非基本类型的建堆、TOPK操作:
1.实现Comparable 接口 重写compareTo()方法,设计规则实现比较
注意:

@Override
    public int compareTo(Student o) {
        return this.age-o.age;//小堆
        //return o.age-this.age;//大堆
    }

2.自己写比较器

//比较器 
class AgeComparator implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        return o2.age-o1.age;
    }
}

整体参考代码:

import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;

/**
 * @Author 12629
 * @Date 2022/3/24 16:18
 * @Description:
 */
 //实现Comparable 接口 重写compareTo()方法,设计规则通过年龄比较
/*class Student implements Comparable<Student>{
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        return this.age-o.age;//小堆
        //return o.age-this.age;//大堆
    }
}*/
class Student {
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

}
//比较器 
class AgeComparator implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        return o2.age-o1.age;
    }
}

public class TestDemo {

    /**
     * 前K个最小的元素
     * @param array
     */
    public static int[] topK(int[] array,int k) {
		//相当于是一个类,实现了Comparator接口,并且重写了compare接口。匿名内部类
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;//大堆,否则小堆
            }
        });
        //PriorityQueue<Integer> maxHeap2 = new PriorityQueue<>(k,((o1, o2) -> {return o2-o1;}));//lamda表达式上述写法

        for (int i = 0; i < array.length; i++) {
            if(maxHeap.size() < k) {
                maxHeap.offer(array[i]);
            }else {
                //1、先获取堆顶元素
                int top = maxHeap.peek();
                if(top > array[i]) {
                    maxHeap.poll();
                    maxHeap.offer(array[i]);//maxHeap插入元素,并调整堆为大堆
                }
            }
        }

        int[] ret = new int[k];
        for (int i = 0; i < k; i++) {
            ret[i] = maxHeap.poll();//前K个最小的元素
        }
        return ret;
    }

    public static void main(String[] args) {
        int[] array = {1,2,31,4,51,16,7};
        int[] ret = topK(array,3);
        System.out.println(Arrays.toString(ret));
    }


    public static void main4(String[] args) {

        AgeComparator ageComparator = new AgeComparator();
        
        PriorityQueue<Student> students = new PriorityQueue<>(ageComparator);//传入比较器ageComparator参数。默认的话,比较器为null
        students.offer(new Student("bit",19));
        students.offer(new Student("gaobo",9));
        //建堆
        System.out.println(students);
    }


    public static void main3(String[] args) {
        //默认容量是11  到底是大根堆  还是 小根堆-> 默认小根堆
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(10);
        priorityQueue.offer(8);
        priorityQueue.offer(30);
        priorityQueue.offer(5);

        System.out.println(priorityQueue.poll());//5
        System.out.println(priorityQueue.peek());//8

    }
}

PriorityQueue特性

  1. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出ClassCastException异常
  2. 不能插入null对象,否则会抛出NullPointerException
  3. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容
  4. 插入和删除元素的时间复杂度为O(log2N)
  5. PriorityQueue底层使用了堆数据结构,(注意:此处大家可以不用管什么是堆,后文中有介绍)7.PriorityQueue默认情况下是小堆—即每次获取到的元素都是最小的元素

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

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

相关文章

48 基于 jdk9 编译的 jdk8 的字节码报错

前言 呵呵 大概是由于最近的这个 “Apache Log4j被曝存在严重高危险级别远程代码执行漏洞” 昨天晚上 编译了一下 logging-log4j2-log4j-2.15.0-rc2, 项目需要一个 toolchain.xml 的一个配置, 里面需要配置为 jdk9 因此 我的项目配置的 jdk 为 jdk9 然后 idea 里面默认…

【计算机毕业设计】校园二手市场平台+vue源码

一、系统截图&#xff08;需要演示视频可以私聊&#xff09; 摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐…

校园跑腿系统小程序怎么用_校园跑腿系统小程序的基本功能是什么

大学可能是人生中最可能的阶段&#xff0c;而大学也是创业的最佳选择。近年来&#xff0c;在微信小程序的红利生态圈下&#xff0c;校园跑腿系统系统已经成为大学校园创业的第一热点。 随着大学生人数的增加&#xff0c;消费水平也在不断地提高&#xff0c;大学校园内代取快递、…

交换机之trunk access hybrid 以及vlan深入理解

服务器开发系列 文章目录服务器开发系列一、802.1Q封装VLAN数据帧格式是&#xff1f;二、Access Trunk Hybrid是什么&#xff1f;三、Access Trunk Hybrid数据处理流程是什么&#xff1f;四、示例五、最简单交换机应用总结一、802.1Q封装VLAN数据帧格式是&#xff1f; IEEE 80…

kubernetes中ingress控制器traefik获取真实客户源IP

一.现象 公司kubenetes生产环境使用的ingress控制器是traefik&#xff0c;默认是通过deployment部署的&#xff0c;现在研发上反馈不能获取客户的真实源IP地址&#xff0c;通过x_forward_for获取的IP地址都是kubernetes集群内部的IP地址。 二.解决思路 通过查找traefik的官方…

【雨夜】业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?

今天和同事 聊了下异常 相关的事&#xff0c;整理在此 目前公司中使用的 自定义异常是 extend RuntimeException 目录 思维导图 继承异常 我们在业务开发中 继承异常是extend RuntimeException 还是 Exception呢 一想 这肯定是 RuntimeException 啊&#xff0c;但是这是为什…

kingdee漏洞金蝶云星空存在弱口令漏洞

kingdee漏洞简介 金蝶云星是基于云计算、大数据、社交、人工智能、物联网等前沿技术研发的新一代战略性企业管理软件。金蝶云星空存在弱口令漏洞&#xff0c;攻击者利用该漏洞登录系统后台&#xff0c;获取敏感信息。 CNNVD编号&#xff1a;CNVD-2022-15854危害等级&#xff…

【C++笔试强训】第二十七天

&#x1f387;C笔试强训 博客主页&#xff1a;一起去看日落吗分享博主的C刷题日常&#xff0c;大家一起学习博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a;夜色难免微凉&#xff0c;前方必有曙光 &#x1f31e;。 &#x1f4a6;&a…

使用PostMan测试WebService接口

在浏览器中输入 http://ws.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl 查看是否启动服务&#xff0c;确保WS地址可用。通过地址获取获取WSDL地址相关参数&#xff0c;并找空间命名&#xff0c;这个位置是固定的&#xff0c;下面会用到&#xff0c;这里是 http://WebXml.c…

62岁腾格尔要开线上演唱会,直播间能否唱《遥远的地方》成焦点

人生六十岁一花甲&#xff0c;著名草原歌手腾格尔&#xff0c;在经历了人生的风风雨雨后&#xff0c;如今已经步入了六十二岁的年龄。虽然已经年过花甲&#xff0c;但是腾格尔老师依旧意气风发&#xff0c;他的个人线上演唱会&#xff0c;也准备在11月19日与大家见面。 在网友的…

【C++布隆过滤器和哈希切分】

目录 1.布隆过滤器概念 2.布隆过滤器优点 3.哈希切分 位图储存的类型只能是整形&#xff0c;有没有储存自定义类型或者是字符串类型的“位图”呢&#xff1f; 1.布隆过滤器概念 步隆过滤器是由布隆&#xff08;Burton Howard Bloom&#xff09;在1970年提出的 一种紧凑型的…

从3D ToF到智能座舱系统方案,英飞凌如何赋能未来出行?

当前&#xff0c;全球汽车产业正处于大变革和市场重构的关键时期&#xff0c;智能汽车新时代的大幕已然拉开。 “智能座舱、人机交互已经成为车载信息娱乐系统‘智能化’的新亮点。”英飞凌相关负责人表示。在汽车智能化、网联化、电动化等大趋势下&#xff0c;越来越多的创新…

【C++进阶】map和set——下篇(红黑树的学习以及封装map和set)

&#x1f387;C学习历程&#xff1a;入门 博客主页&#xff1a;一起去看日落吗持续分享博主的C学习历程博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 也许你现在做的事情&#xff0c;暂时看不到成果&#xff0c;但不要忘记&…

ggplot2图形简单绘制

文章目录一、所用函数1. sort、rank、order用法2. arrange 用法3. reorder用法4. cumsum 用法5. interaction用法二、散点图三、折线图、直方图、箱线图四、柱状图1. 单一变量 &#xff08;统计单一变量的属性值分布&#xff09;2. 单一变量fill &#xff08;列联表&#xff09…

mybatis详解

学习到现在,作为我们的java萌新来说,是时候来学习一点偷懒的武林秘籍了,今天我给大家介绍的就是在无上秘宝--mybatis持久型框架. 学习一个东西之前,我们得首先了解他的前世今生... 前世:原是Apache的一个开源项目iBatis, 2010年6月这个项目由ApacheSoftware Foundation 迁移到…

SQL注入靶机练习:BUU SQL COURSE 1

SQL注入靶机练习&#xff1a;BUU SQL COURSE 1一、SQL注入知识点二、前置知识三、SQL注入测试的一般步骤四、解题过程一、SQL注入知识点 可参考SQL注入详解 二、前置知识 参考来源&#xff1a;渗透攻防Web篇-深入浅出SQL注入 mysql5.0以上版本中存在一个重要的系统数据…

无敌,全面对标字节跳动2-2:算法与数据结构突击手册(leetcode)

学习是一种基础性的能力。然而&#xff0c;“吾生也有涯&#xff0c;而知也无涯。”&#xff0c;如果学习不注意方法&#xff0c;则会“以有涯随无涯&#xff0c;殆矣”。 学习就像吃饭睡觉一样&#xff0c;是人的一种本能&#xff0c;人人都有学习的能力。我们在刚出生的时候…

某城市道路桥梁设计计算书+cad图纸

第一章 工程概述 41 1.1设计题目 41 1.2 设计资料 42 1&#xff0e;3 桥梁设计的基本要求 42 1.3.1 使用上的要求&#xff1a; 42 1.3.2 经济上的要求&#xff1a; 42 1.3.3 结构和尺寸上的要求&#xff1a; 42 1.3.4 施工上的要求&#xff1a; 42 1.3.5美观上的要求&#xff1…

Aspose.PDF for Java Crack by Xacker

Aspose.PDF for Java 是一个本地库&#xff0c;使开发人员能够将 PDF 处理功能添加到他们的应用程序中。API 可用于构建任何类型的 32 位和 64 位应用程序&#xff0c;以在不使用 Adob​​e Acrobat 的情况下生成或读取、转换和操作 PDF 文件。 Aspose.PDF for Java API 允许执…

嵌入式(驱动开发)(内核内存管理)

一、内核内存管理框架 内核将物理内存等分成N块4KB&#xff0c;称之为一页&#xff0c;每页都用一个struct page来表示&#xff0c;采用伙伴关系算法维护 内核地址空间划分图&#xff1a; 3G~3G896M&#xff1a;低端内存&#xff0c;直接映射 虚拟地址 3G 物理地址 ​ 细…