优先级队列(堆)的实现

1.什么是优先级队列

队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队
列时,可能需要优先级高的元素先出队列
,该中场景下,使用队列显然不合适,比如:在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话。
在这种情况下,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)。
 

2. 优先级队列模拟实现

堆实际就是在完全二叉树的基础上进行了一些调整。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

小根堆:                                                                            大根堆:

                  
堆的性质:

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

 

 1)堆的向下调整

 以集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据为例

1. 让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子)

2. 如果parent的左孩子存在,即:child < end, 进行以下操作,直到parent的左孩子不存在

      parent右孩子是否存在,存在找到左右孩子中最小的孩子,让child进行标

      将parent与较小的孩子child比较,如果:

              parent小于较小的孩子child,调整结束;

              否则:交换parent与较小的孩子child,交换完成之后,parent中大的元素向下移动,可能导致子树不满足堆的性质,因此需要继续向下调整,即parent = child;child = parent*2+1; 然后继续2

 

   /**
     *
     * @param parent 是每棵子树的根节点的下标
     * @param end  是每棵子树调整结束的结束条件
     * 向下调整的时间复杂度:O(logn)
     */
    private void shiftDown(int parent,int end) {
        int child=2*parent+1;
        while(child<end){
            if(child+1<usedSize && elem[child]<elem[child+1]){
                child++;
            }

            if(elem[child]>elem[parent]){
                swap(child,parent);
                parent=child;
                child=2*parent+1;
            }else {
                break;
            }
        }

    }

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

 

2)建堆 

  public void createBigHeap(int[] array) {
        for(int parent=(usedSize-1-1)/2;parent>=0;parent--){
            shiftDown(parent,usedSize);
        }
  }

 

3)堆的插入

  1. 先将元素放入到底层空间中(注意:空间不够时需要扩容)
  2.  将最后新插入的节点向上调整,直到满足堆的性质

 

 /**
     * 堆的删除:每次删除的都是优先级高的元素
     * 仍然要保持是大根堆
     */
    public int poll() {
        if(isEmpty()){
            return -1;
        }
        int tmp=elem[0];
        swap(0,usedSize-1);
        usedSize--;
        shiftDown(0,usedSize);
        return tmp;
    }

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

 

4)堆的删除

  1.  将堆顶元素对堆中最后一个元素交换
  2.  将堆中有效数据个数减少一个
  3.  对堆顶元素进行向下调整

 

    /**
     * 堆的插入:仍然要保持是大根堆
     * @param val
     */
    public void offer(int val) {
        if(isFull()){
            this.elem= Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize]=val;
        usedSize++;

        shiftUp(usedSize-1);
    }

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

 

 全部代码: 

import java.util.Arrays;

public class PriorityQueue {
    public int[] elem;
    public int usedSize;//数组已使用的空间

    public PriorityQueue() {
        this.elem=new int[10];
    }
    
    //初始化elem数组
    public void initElem(int[] array){
        for(int i=0;i<elem.length;i++){
            elem[i]=array[i];
            usedSize++;
        }
    }

    /**
     * 建堆的时间复杂度:O(N)
     *
     * @param array
     */
    public void createBigHeap(int[] array) {
        for(int parent=(usedSize-1-1)/2;parent>=0;parent--){
            shiftDown(parent,usedSize);
        }
    }

    /**
     *
     * @param parent 是每棵子树的根节点的下标
     * @param end  是每棵子树调整结束的结束条件
     * 向下调整的时间复杂度:O(logn)
     */
    private void shiftDown(int parent,int end) {
        int child=2*parent+1;
        while(child<end){
            if(child+1<usedSize && elem[child]<elem[child+1]){
                child++;
            }

            if(elem[child]>elem[parent]){
                swap(child,parent);
                parent=child;
                child=2*parent+1;
            }else {
                break;
            }
        }

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


    /**
     * 堆的插入:插入完后仍然要保持是大根堆
     * @param val
     */
    public void offer(int val) {
        if(isFull()){
            this.elem= Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize]=val;
        usedSize++;

        shiftUp(usedSize-1);
    }

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

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

    /**
     * 堆的删除:每次删除的都是优先级高的元素
     * 仍然要保持是大根堆
     */
    public int poll() {
        if(isEmpty()){
            return -1;
        }
        int tmp=elem[0];
        swap(0,usedSize-1);
        usedSize--;
        shiftDown(0,usedSize);
        return tmp;
    }

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

    /**
     * 获取堆顶元素
     * @return
     */
    public int peek (){
        return elem[0];
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Drone+Gitee自动执行构建、测试和发布工作流

拉取Drone:(至于版本&#xff0c;你可以下载最新的) sudo docker pull drone/drone:2 拉取runner&#xff1a; sudo docker pull drone/drone-runner-docker 在Gitee中添加第三方应用&#xff1a; 进入个人主页&#xff0c;点击设置&#xff1a; 往下翻&#xff0c;找到数…

2022蓝桥杯大赛软件类国赛Java大学B组 左移右移 空间换时间+双指针

import java.util.Scanner;public class Main {static Scanner scnew Scanner(System.in);public static void main(String[] args) {int nsc.nextInt();//数组长度int tsc.nextInt();//操作次数int arr[]new int[n];char arr1[] new char[t];int arr2[] new int[t];int vis…

输入一串字符,输入想要字符串前*的个数n,判断字符串前*的个数是大于n还是小于n,如果大于n则删除多余的*其它保持不变,如果小于n,则字符串也保持不变

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> void fun(char* a, int n) {int i 0, j 0, m 0,b0,c0;char* p;p a;//第一步&#xff0c;判断字母前面有多少个*while (p[i] *){j;}printf("字母前*的个数%d\n",j);//求总的字符串长度while (a[m] !…

基于.net开发的博客系统

基于.net开发可以批量上传md文件生成文章的博客系统 .NET 个人博客 基于.net开发的博客系统 个人博客系统&#xff0c;采用.net core微服务技术搭建&#xff0c;采用传统的MVC模式&#xff0c;使用EF core来对mysql数据库(sqlite数据库)进行CRUD操作项目 为什么要自己开发博客…

csdn的insCode怎么用IDE和linux终端

1.进入insCode&#xff0c;选择工作台 找到我的项目&#xff0c;没有项目的话可以新建一个。 选择在IDE中编辑&#xff0c;界面如下&#xff1a; 右边有个终端&#xff0c;点击即可出现linux的xterm终端。

依赖的各种java库(工具类) :fastjson,lombok,jedis,druid,mybatis等

lombok 功能&#xff1a; Lombok 是一个实用的Java类库&#xff0c;可以通过简单的注解来简化和消除一些必须有但显得很臃肿的Java代码。 导入包&#xff1a;使用Lombok首先要将其作为依赖添加到项目中&#xff0c;在pom.xml文件中手动添加 <dependency><groupId&g…

别对我动心短视频:成都鼎茂宏升文化传媒公司

别对我动心短视频&#xff1a;时代的爱情哲学与心理探索 在短视频的海洋里&#xff0c;"别对我动心"这样的标题&#xff0c;如同一颗石子投入平静的湖面&#xff0c;激起了层层涟漪。它不仅仅是对一段情感的拒绝&#xff0c;更是一种现代人情感态度的表达&#xff0…

AIGC-常见图像质量评估MSE、PSNR、SSIM、LPIPS、FID、CSFD,余弦相似度----理论+代码

持续更新和补充中…多多交流&#xff01; 参考: 图像评价指标PNSR和SSIM 函数 structural_similarity 图片相似度计算方法总结 MSE和PSNR MSE: M S E 1 m n ∑ i 0 m − 1 ∑ j 0 n − 1 [ I ( i , j ) − K ( i , j ) ] 2 MSE\frac{1}{mn}\sum_{i0}^{m-1}\sum_{j0}^{n-1}[…

TECHNIUM INTERNATIONAL: 利用 AI 和 TECHNIUM 矩阵协议引领区块链创新

在充满活力的加密货币和区块链技术领域&#xff0c;Technium International 以领军者的姿态迅速崛起&#xff0c;跻身科技巨头的顶尖行列。Technium International 成立于 2018 年&#xff0c;总部设于塞席尔&#xff0c;透过人工智慧&#xff08;AI&#xff09;和区块链技术的…

代码随想录算法训练营第三十七天|435. 无重叠区间、763.划分字母区间、56. 合并区间、738.单调递增的数字、968.监控二叉树

435. 无重叠区间 文档讲解&#xff1a;代码随想录 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 本道题与上个题目相似&#xff0c;都是求重叠区间 统计重叠区间的个数&#xff0c;减去重叠区间的个数就是无重叠区间了 主要就是为了让区间尽可能的重叠。&a…

Python_文件操作_学习

目录 一、关于文件的打开和关闭 1. 文件的打开 2.文件的关闭 二、文件的读取 1. 文件的读_r 2. 使用readline 3.使用readlines 三、文件的写入 1. 文本的新建写入 2.文本的追加写入 四、文件的删除和重命名 1.文件的重命名 2.文件的删除 五、文件的定位读写 1.t…

【pyspark速成专家】5_Spark之RDD编程3

目录 ​编辑 六&#xff0c;共享变量 七&#xff0c;分区操作 六&#xff0c;共享变量 当spark集群在许多节点上运行一个函数时&#xff0c;默认情况下会把这个函数涉及到的对象在每个节点生成一个副本。 但是&#xff0c;有时候需要在不同节点或者节点和Driver之间共享变…

电商公司需不需要建数字档案室呢

建立数字档案室对于电商公司来说是非常有必要的。以下是一些原因&#xff1a; 1. 空间节约&#xff1a;数字档案室可以将纸质文件转化为电子文件&#xff0c;节省了大量存储空间。这对于电商公司来说尤为重要&#xff0c;因为他们通常会有大量的订单、客户信息和供应商合同等文…

OpenHarmony系统使用gdb调试init

前言 OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;适配新的开发板时&#xff0c;启动流程init大概率会出现问题&#xff0c;其为内核直接拉起的第一个用户态进程&#xff0c;问题定位手段只能依赖代码走读和增加调试打印&#xff0c;初始化过程中系统崩溃…

封装了一个iOS中间放大的collectionView layout

效果图如下所示 原理&#xff1a;就是首先确定一个放大和缩小系数和原大小对应的基准位置&#xff0c;然后根据距离每个布局属性到视图中心的距离和基准点到中心的距离的差距/基准点到中心的距离&#xff0c; 计算出每个布局属性的缩放系数 下面是代码 // // LBHorizontalCe…

数据库--数据库基础(一)

目录 第一章 绪论 一.数据库的基本概念 1. 数据库的4个基本概念 2、数据库系统的特点 二.数据库和文件 三.数据模型 1.概念模型 2.逻辑模型(物理模型) 2.1关系模型 四.数据库系统的三级模式结构&#xff1a; 五数据库的二级映像功能与数据独立性 第二章 关系数据库…

web学习笔记(五十六)

目录 1.绑定类名和style 1.1 绑定类名 1.1.1 绑定单个类名 1.1.2 绑定多个类名 1.2 style相关知识 2. vue的响应式原理 3. v-once 4.本地搭建Vue单页应用 4.1 安装Vue脚手架 4.2 安装对应的包文件 4.3 运行项目 1.绑定类名和style 1.1 绑定类名 1.1.1 绑定单个类名…

【Unitydemo制作】音游制作—模式玩法的实现

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

Redis(十三) 事务

文章目录 前言事务的特性Redis事务的执行原理Redis中使用事务WATCH UNWATCH实现乐观锁 前言 前面我们学习 MySQL 的时候&#xff0c;肯定也学习了事务。事务是什么&#xff1f;给大家举个例子&#xff1a;假如我给朋友微信转账&#xff0c;我给他转了 100 块钱&#xff0c;当我…

5.18 TCP机械臂模拟

#include <netinet/tcp.h>//包含TCP选项的头文件 #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <linux/input.h>//读取输入事件 #include <sys/types.h> #include <sys/stat.h&…