【Java】还在死磕算法?懂“堆”与“优先级队列”,代码效率飙升

dc49951ad219454bbef81e408b809a6b.gif

个人主页:喜欢做梦

欢迎 💛点赞 🌟收藏 💫关注


🏆堆

一、🎯什么是堆

堆的概念

堆是一种特殊的完全二叉树 ,如果有一个关键码的集合K={k0,k1,k2,...,kn-1} ,把它所有的元素按照完全二叉树的顺序存储方式一维数组 中,并满足:Ki <=K2i+1且Ki<=K2i+2(Ki>=K2i+2)i=0,1,2,3....,则称为小堆 。堆有两种类型 分别为大根堆小根堆

  • 小根堆:根节点的值最小,父节点的值小于或等于其孩子节点的值;
  • 大根堆:根节点的值最大,父节点的值大于或等于其孩子节点的值;

c97ff782617443feb96aeb1f70a5c13e.png

堆的性质

  • 是一个完全二叉树;
  • 堆的某个节点总是不大于或不小于父节点的值;

二、🀄️堆的创建

大堆

实现过程:
255b7fc12bd94eed89801a9e8ceccba9.png

ec55d38b93bd4e43a40ff20226edf8c7.png

代码:

```java
public class Heap {
    public int[] elem;//数组
    public int usedSize;//使用大小
    public Heap() {
        this.elem=new int[10];
    }
    //初始化
    public void initHeap(int[] elem){
        for (int i = 0; i =0; parent--) {
            //parent:调整的起始位置;
            //usedSize:调整的结束位置
            siftDown(parent,usedSize);
        }
    }
    public void siftDown(int parent,int usedSize){
        int child=2*parent+1;
        while(childelem[parent]){
                swap(elem,child,parent);
                //交换完,将父节点等于下一个子节点,看下一个堆是否形成大堆,
                //如果没有,继续交换
                parent=child;
                child=2*parent+1;
            }else{
                //如果大于子节点,不调整
                break;
            }                          }
    }
    private void swap(int[] elem,int i,int j){
        int tmp=elem[i];
        elem[i]=elem[j];
        elem[j]=tmp;

}
}
```

小堆

小堆的思路与大堆相同,只不过一个父节点比子孩子小

代码:

```java
    private void swap(int[] elem,int i,int j){
        int tmp=elem[i];
        elem[i]=elem[j];
        elem[j]=tmp;

}
    public void creatHeap2(){
        for (int parent = (usedSize-1-1)/2; parent >=0; parent--) {
            siftDown2(parent,usedSize);
        }
    }
    public void siftDown2(int parent,int usedSize){
        int child=2*parent+1;
        while(childelem[child+1]){
                child++;
            }
            if(elem[child]
  • 建堆的时间复杂度为O(n);

测试:

```java
    public static void main(String[] args) {
        int[] array={15,28,17,36,45,23,35,56};
        Heap heap=new Heap();
        heap.initHeap(array);
        heap.creatHeap1();
        for (int i = 0; i < heap.elem.length; i++) {
            System.out.print(heap.elem[i]+" ");
        }
        System.out.println();
        heap.creatHeap2();
        for (int i = 0; i < heap.elem.length; i++) {
            System.out.print(heap.elem[i]+" ");
        }
    }
```

三、🎨堆的基本操作

堆的插入

思路:

  • 看位置是否已满,如果满了扩容;
  • 插入元素:

  • 将元素插入在最后一个节点后面,也就是插入在elem[uesdSize];

  • 随后将其进行向上调整;
  • 向上调整:将子节点进行向上调整

向上调整的实现过程:
f9f637c09bdf49df9653efdc74b7d5eb.png

d9c4fadd30d64c8398a3e482eb352ecd.png

实现代码:

```java
    public void offer(int val){
        if(isFull()){
            this.elem= Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize]=val;
        siftUp(usedSize);
        usedSize++;
    }
    private boolean isFull(){
        return this.usedSize== elem.length;
    }
    //向上调整:
    //将子节点与父节点进行比较;
         //如果大于父节点,交换;随后减子节点跳到父节点的位置,父节点跳到父节点的位置
         //小于退出本次循环
    public void siftUp(int child){
         int parent=(child-1)/2;
         //循环条件:parent>=0
         while(parent>=0){
             if(elem[parent]

堆的删除

堆的删除:删除堆顶元素

思路

  • 将堆顶元素与最后一个节点元素进行交换,也就是位置0的元素与位置usedSize的元素进行交换
  • 交换后,只有0位置开始不是大堆,所以我们从0开始进行向下调整;
  • 调整完将使用大小减小

调整过程:

0a74d1887a4c42619750f0ef10db266c.png

7729a17b0199400a9d02b1db452f3284.png 代码:

```java
  public int poll(){
          if(isEmpty()){
              return -1;
          }
          int val=elem[0];
          swap(elem,0,usedSize-1);
          siftDown1(0,usedSize-1);
          usedSize--;
          return val;
    }
    private boolean isEmpty(){
        return this.usedSize==0;
    }
```

获取堆顶元素

```java
//获取堆顶元素
    public int peek(){
        if (isEmpty()){
            return -1;
        }
        return elem[0];
    }
```

堆的排序(从小到大)

思路:

  • 将最后一个元素与第一个元素进行交换,也就是将最大值放在最后一个;
  • 随后将交换在第一个位置的元素进行向下调整到交换到最后的那些数之前;
  • 调整完,也就是倒数第二大的元素在堆顶,将其与倒二个元素进行交换,交换完调整,其他同样如此;

调整过程:

33ec44c2c1ca40b29375a7531966658d.png

e2bb37a7d11b485480655f8df0c1bd66.png

26c51c9a2d284e8f9b7ae6a56d5d5313.png

62eb16a0edd14dd28b0f15fcb2108668.png

```java
 public void heapSort(){
        int end=usedSize-1;
        while(end>0) {
            swap(elem, 0, end);
            siftDown1(0,end);
            end--;
        }
```

向下调整和向上调整的区别:

区别 向下调整 向上调整
方向 父节点向下调整 子节点向上调整
比较对象 主要父节点与子节点最值进行比较 主要新插入的子节点与父节点进行比较
触发场景 删除或更新操作 插入操作

🏆优先级队列(Priority Queue)

一、📖优先级队列的概念

优先级队列:

是队列的一种,遵循先进先出 的原则。但是其元素有优先级之分 ,在出队时,优先出队,优先级最高的元素 。比如在医院急诊时,优先治疗病情严重的病人。

  • 优先级队列底层使用了堆这种数据结构。

注意事项:

  • 使用时必须导入PriorityQueue所在的包;
  • PriorityQueue中放置的元素必须能够比较大小,否则抛出异常;
  • 不能插入null对象,否则抛出异常;
  • 没有容量限制,可以任意插入多个元素,自动扩容;

2fe8ad82df034731a0b317c0c252aa8c.png

  • 如果容量小于64进行2倍扩容;
  • 如果容量大于等于64进行1.5倍扩容;
  • 如果容量超过Max_ARRAY_Size,按照Max_ARRAY_Size来进行扩容;
  • 插入和删除的时间复杂度为O(eq?%5Clog_%7B2%7DN);
  • PriorityQueue底层使用了堆数据结构;
  • PriorityQueue默认情况下是小堆;

如果要PriorityQueue变为大堆,可以重写compare方法:

```java
class cmp implements Comparator{
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);
    }
}
```

二、⛳️优先级队列的使用

PriorityQueue的构造方法:

187713b95cdd47e1996147db87086729.png

PriorityQueue的方法

516d8fd4a85343b18d7c99393ab65def.png

```java
  public static void main(String[] args) {
        PriorityQueue priorityQueue=new PriorityQueue<>();
        //插入元素
        priorityQueue.offer(24);
        priorityQueue.offer(12);
        priorityQueue.offer(35);
        priorityQueue.offer(20);
        //获取优先级最高的元素
        priorityQueue.peek();
        //删除指定元素
        priorityQueue.remove(35);
        //删除优先级最高的元素
        priorityQueue.poll();
        //.....
    }
```

07237e5031ba47fb98dc5e8b90759947.jpeg

感谢支持!!! 🌹 🌹 🌹

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/5301.html

(0)
LomuLomu
上一篇 2025 年 1 月 6 日 上午3:30
下一篇 2025 年 1 月 6 日 上午4:32

相关推荐

  • A5433 Java+Jsp+Servlet+MySQL+微信小程序+LW+在线点餐小程序的设计与实现 源码 配置 文档

    在线点餐小程序的设计与实现 1.摘要 2.开发目的和意义 2.1 系统开发目的 2.2 系统开发意义 3.系统功能设计 4.系统界面截图 5.源码获取 1.摘要 摘 要近几年,人们生活水平日益提升,但工作强度和压力不断增强,尤其是对于上班族而言,到餐厅吃饭费时费力,而传统的APP点餐难以适应针对性,基于此,借助Web开发技术以及后台数据库,设计了在线点餐小程…

    2025 年 1 月 11 日
    13900
  • 华为OD机试E卷 –连续字母长度–24年OD统一考试(Java & JS & Python & C & C++)

    文章目录 题目描述 输入描述 输出描述 用例 题目解析 JS算法源码 Java算法源码 python算法源码 c算法源码 c++算法源码 题目描述 给定一个字符串,只包含大写字母,求在包含同一字母的子串中,长度第 k 长的子串的长度,相同字母只取最长的那个子串。 输入描述 第一行有一个子串(1

    未分类 2025 年 1 月 19 日
    14900
  • 从零开始的Python世界生活——语法基础先导篇(Python小白零基础光速入门上手)

    从零开始的Python世界生活——语法基础先导篇(Python小白零基础光速入门上手) 1. 准备阶段 1.1 下载并安装Python 1.1.1 下载步骤: 访问Python官方网站:点击这里下载Python 在页面上,选择适合你操作系统的Python版本(Windows、macOS或Linux)。 点击下载按钮,开始下载安装程序。 1.1.2 安装步骤:…

    未分类 2025 年 1 月 6 日
    13200
  • 通过延时从库+binlog复制,恢复误操作数据

    通过延迟复制与binlog恢复意外删除的数据 一、环境概述 以下是我们操作的数据库环境的详细信息: 数据库版本 实例角色 IP地址 端口 GreatSQL 8.0.32-26 主库 192.168.134.199 5725 GreatSQL 8.0.32-26 从库 192.168.134.199 5726 二、主库设置 在主库上,我们首先需要创建一个复制用…

    2024 年 12 月 24 日
    15500
  • JAVA 图形界面编程 AWT篇(1)

    前言 为了应对JAVA课设,小编走上了java的图形界面编程的道路,通过博客分享自己的学习历程,并进行笔记的记录。 AWT(Abstract Window Toolkit)介绍 AWT(抽象窗口工具包)是 Java 最早的图形用户界面(GUI)框架之一,主要用于构建桌面应用程序的图形界面。最初在 JDK 1.0 版本中作为 Java GUI 的核心库引入,旨…

    未分类 2025 年 1 月 11 日
    13600

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信