(Java)数据结构——排序(第一节)堆排序+PTA L2-012 关于堆的判断

前言

本博客是博主用于复习数据结构以及算法的博客,如果疏忽出现错误,还望各位指正。

堆排序(Heap Sort)概念

堆排序是一种基于堆数据结构的排序算法,其核心思想是将待排序的序列构建成一个最大堆(或最小堆),然后将堆顶元素与最后一个元素交换,再将剩余元素重新调整为最大堆(或最小堆),重复以上步骤直到所有元素都有序。

堆是一棵完全二叉树,因此一般可以当作数组处理。

对于最大堆,任何一个父节点的值都大于(或等于)其左右子节点的值;

对于最小堆,则是任何一个父节点的值都小于(或等于)其左右子节点的值。

建堆

上滤(插入新元素到堆中)

时间复杂度为O(N logN)

也就是一个一个插入,比如拿[46 23 26 24 10]来说,建堆过程就如下:


        List<Integer> list = new ArrayList<>();
        String[] num = in.nextLine().split(" ");
        
        for(int i = 0;i<N;i++){
            //小顶堆的形成,自上而下建堆,一个一个插入
            if(list.size()==0){
                list.add(Integer.parseInt(num[i]));
            }else{
                //如果长度不是0,就插入后进行比较
                list.add(Integer.parseInt(num[i]));
                int count = i;
                while(count!=0){
                    int parent = 0;
                    if((count-1)%2==0){
                        parent = (count-1)/2;
                    }else if((count-2)%2==0){
                        parent =(count-2)/2;
                    }
                    if(list.get(count)<list.get(parent)){
                        int temp = list.get(count);
                        list.set(count,list.get(parent));
                        list.set(parent,temp);
                        count = parent;
                    }else{
                        break;
                    }
                }
            }
        }

下滤

一般用的是下滤,因为时间复杂度为O(N)

就是先整体插入,然后从倒数第一个非叶子结点进行堆调整:

1、找到倒数第一个非叶子结点23,判断其与子节点关系,发现比10大,于是互换

2、之后继续寻找非叶子结点,找到46,46与10交换后,继续与23交换

注意事项

建堆结束,两种方法建立的堆可能不一样,所以注意题目要求透露出的是哪一种。

比如要求上滤的:L2-012 关于堆的判断 - 团体程序设计天梯赛-练习集 (pintia.cn)

实现代码:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] mn = in.nextLine().split(" ");
        int N = Integer.parseInt(mn[0]);
        int M = Integer.parseInt(mn[1]);
        List<Integer> list = new ArrayList<>();
        String[] num = in.nextLine().split(" ");

        for(int i = 0;i<N;i++){
            //小顶堆的形成
            if(list.size()==0){
                list.add(Integer.parseInt(num[i]));
            }else{
                //如果长度不是0,就进行比较
                list.add(Integer.parseInt(num[i]));
                int count = i;
                while(count!=0){
                    int parent = 0;
                    if((count-1)%2==0){
                        parent = (count-1)/2;
                    }else if((count-2)%2==0){
                        parent =(count-2)/2;
                    }
                    if(list.get(count)<list.get(parent)){
                        int temp = list.get(count);
                        list.set(count,list.get(parent));
                        list.set(parent,temp);
                        count = parent;
                    }else{
                        break;
                    }
                }
            }
        }

        //System.out.println(list.toString());
        //判断
        while(M-->0){
            String[] judge = in.nextLine().split(" ");
            //变成在数组中的下标
            int x = list.indexOf(Integer.parseInt(judge[0]));
            if(judge[3].equals("root")){
                if(x==0){
                    System.out.println("T");
                }else{
                    System.out.println("F");
                }
            }else if(judge[3].equals("are")){
                int y = list.indexOf(Integer.parseInt(judge[2]));
                if((y-1)%2==0){
                    if(y+1==x){
                        System.out.println("T");
                    }else{
                        System.out.println("F");
                    }
                }else if((y-2)%2==0){
                    if(y-1==x){
                        System.out.println("T");
                    }else{
                        System.out.println("F");
                    }
                }
            }else if(judge[3].equals("parent")){
                int y = list.indexOf(Integer.parseInt(judge[5]));
                if((y-1)%2==0){
                    if((y-1)/2==x){
                        System.out.println("T");
                    }else{
                        System.out.println("F");
                    }
                }else if((y-2)%2==0){
                    if((y-2)/2==x){
                        System.out.println("T");
                    }else{
                        System.out.println("F");
                    }
                }
            }else if(judge[3].equals("child")){
                int y = list.indexOf(Integer.parseInt(judge[5]));
                if((2*y+1) == x || (2*y+2)== x){
                    System.out.println("T");
                }else{
                    System.out.println("F");
                }
            }
        }
    }
}

当然,更简单的,可以直接使用Java提供的类,直接使用优先队列toArray解决:

【PTA-训练day1】L2-012 关于堆的判断 + L1-002打印沙漏_pta打印沙漏测试点-CSDN博客

Java优先队列

关于Java优先队列的一篇博主的博客详细介绍

【Java】PriorityQueue--优先级队列_java priorityqueue-CSDN博客

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

JDK1.8 中的 PriorityQueue底层使用了堆这种数据结构 ,而堆实际就是在完全二叉树的基础上进行了一些调整。

默认情况下是小根堆,如果需要大根堆,则需要构建比较器。

其他方法与队列无异。

PriorityQueue<Integer> q=new PriorityQueue<>(); //默认小顶堆
 
PriorityQueue<Integer> q=new PriorityQueue<>((a,b)->(b-a)); //大顶堆
 
q.contains(val);
 
Integer[] t=q.toArray(new Integer[n]); //将队列转化为数组

堆排序

上述三种建堆的方法,每次之后将最顶点进行一下处理(移除或者加入数组末尾等操作),然后重新建堆再操作即可实现堆排序。

应用场景

堆排序使用场景堆排序的使用场景与其他排序算法类似,适用于需要对大量数据进行排序的场景。比如取出第k大(小)的数,这时候可以用堆排序。

优/缺点

优点主要包括:

时间复杂度较低:堆排序的时间复杂度为 O(NlogN),相对于其他排序算法,其排序速度较快。

不占用额外空间:堆排序是一种原地排序算法,不需要额外的空间来存储排序结果。

适用于大数据量的排序:堆排序的时间复杂度不随数据量的增加而变化,因此适用于大数据量的排序。

缺点主要包括:

不稳定性:由于堆排序是通过交换元素来实现排序的,因此在排序过程中可能会破坏原有的相对顺序,导致排序结果不稳定。

实现复杂:相对于其他排序算法,堆排序的实现稍微复杂一些(不过借助Java提供的优先队列可以简单实现),需要理解堆数据结构的基本原理和实现过程。

代码(后续写了再上传,咕咕咕)

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

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

相关文章

大模型+交通治理,高德地图“评诊治”系统迎来全新升级

近日&#xff0c;由中国道路交通安全协会主办的第十四届中国国际道路交通安全产品博览会暨公安交警警用装备展(以下简称交博会)在厦门国际会展中心开幕&#xff0c;会上高德地图发布了全新升级的城市交通“评诊治”智能决策SaaS系统&#xff0c;以助力城市交通的可持续、精细化…

spring boot 集成rocketMq + 基本使用

1. RocketMq基本概念 1. NameServer 每个NameServer结点之间是相互独立&#xff0c;彼此没有任何信息交互 启动NameServer。NameServer启动后监听端口&#xff0c;等待Broker、Producer、Consumer连接&#xff0c; 相当于一个路由控制中心。主要是用来保存topic路由信息&#…

知识图谱与人工智能:携手共进

知识图谱与人工智能&#xff1a;携手共进 一、引言&#xff1a;知识图谱与人工智能的融合 在这个数据驱动的时代&#xff0c;知识图谱与人工智能&#xff08;AI&#xff09;之间的融合不仅是技术发展的必然趋势&#xff0c;也是推动各行各业创新的关键。知识图谱&#xff0c;作…

windows下pycharm中配置conda虚拟环境

目录 一&#xff1a;背景 二&#xff1a;安装conda环境 三&#xff1a;pycharm配置环境 四&#xff1a;注意问题 一&#xff1a;背景 在使用python的过程中&#xff0c;我们可能需要在一个windows环境中创建多个版本的python和安装不同的库去做一些开发任务。 使用conda&a…

TQ15EG开发板教程:在MPSOC上运行ADRV9371

首先需要在github上下载两个文件&#xff0c;本例程用到的文件以及最终文件我都会放在网盘里面&#xff0c; 地址放在本文最后。首先在github搜索hdl选择第一个&#xff0c;如下图所示 GitHub网址&#xff1a;https://github.com/analogdevicesinc/hdl/releases 点击releases…

Docker入门实战教程

文章目录 Docker引擎的安装Docker比vm虚拟机快 Docker常用命令帮助启动类命令镜像命令docker imagesdocker searchdocker pulldocker system dfdocker rmi 容器命令redis前台交互式启动redis后台守护式启动Nginx容器运行ubuntu交互式运行tomcat交互式运行对外暴露访问端口 Dock…

Java基础07--多线程-网络编程-Java高级

一、多线程 1.认识多线程 ①线程 ②多线程 2.创建线程方式 ①方式一&#xff1a;继承Thread类 1.让子类继承Thread线程类 2.重写run方法&#xff0c;就是这个线程执行会执行的操作。 3.创建继承Thread的子类对象就代表一个线程 4.启动线程:.start()-自动执行run方法 注意&am…

绝地求生:PUBG×杜卡迪联名上线!参与投稿评论赢取精美好礼

PUBG杜卡迪联名活动游戏内现已正式上线&#xff01;我们诚邀与您一起在开拓未知战场和书写新历史的过程中&#xff0c;与杜卡迪一同实现您的极速梦想&#xff01; 在本次的杜卡迪工坊中&#xff0c;更是包含了具备标志性红色在内的6种颜色供您自由选择&#xff0c;一起自由驰骋…

创作一首音乐需要多长时间?网易云音乐内测AI音乐生成工具『网易天音』

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

视频基础学习五——视频编码基础二(编码参数帧、GOP、码率等)

系列文章目录 视频基础学习一——色立体、三原色以及像素 视频基础学习二——图像深度与格式&#xff08;RGB与YUV&#xff09; 视频基础学习三——视频帧率、码率与分辨率 视频基础学习四——视频编码基础一&#xff08;冗余信息&#xff09; 视频基础学习五——视频编码基础…

KKVIEW远程远程访问家里电脑

远程访问家里电脑&#xff1a;简易指南与价值所在 在数字化时代&#xff0c;电脑已成为我们日常生活和工作中不可或缺的工具。有时&#xff0c;我们可能在外出时急需访问家中电脑里的某个文件或应用&#xff0c;这时&#xff0c;远程访问家里电脑就显得尤为重要。本文将简要介…

SQLite---调试提示(十九)

返回&#xff1a;SQLite—系列文章目录 上一篇:SQLite Android 绑定&#xff08;十八&#xff09; 下一篇&#xff1a;从 SQLite 3.4.2 迁移到 3.5.0&#xff08;二十&#xff09; ​ 以下是 SQLite 开发人员跟踪、检查和了解 核心 SQLite 库。 这些技术旨在帮助理解 核…

从 SQLite 3.5.9 迁移到 3.6.0(二十一)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;从 SQLite 3.4.2 迁移到 3.5.0&#xff08;二十&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 ​SQLite 版本 3.6.0 &#xff08;2008-07-16&#xff09; 包含许多更改。按照惯例 SQLite项目&#xff…

中移物联网 OneOS 操作系统环境搭建和工程创建

一、官网 OneOS Lite是中国移动针对物联网领域推出的轻量级操作系统&#xff0c;具有可裁剪、跨平台、低功耗、高安全等特点&#xff0c;支持ARM Cortex-A和 Cortex-M、MIPS、RISC-V等主流芯片架构&#xff0c;兼容POSIX、CMSIS等标准接口&#xff0c;支持Javascript、MicroPyt…

Ubuntu下配置Android NDK环境

Android-NDK的下载 下载Android-NDK wget -c http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin 执行bin文件&#xff08;即解压&#xff09; ./android-ndk-r10c-linux-x86_64.bin Android-NDK的配置 要想使用Android-NDK&#xff0c;还需要进行环境变量…

C++ stl容器string的底层模拟实现

目录 前言&#xff1a; 1.成员变量 2.构造函数与拷贝构造函数 3.析构函数 4.赋值重载 5.[]重载 6.比较关系重载 7.reserve 8.resize 9.push_back,append和重载 10.insert 11.erase 12.find 14.迭代器 15.流插入&#xff0c;流提取重载 16.swap 17.c_str 18.完…

Testng测试框架(6)--@Factory动态地创建测试类的实例

工厂允许您动态地创建测试。例如&#xff0c;假设您想创建一个测试方法&#xff0c;该方法将多次访问网站上的某个页面&#xff0c;并且您希望使用不同的值来调用它。 public class TestWebServer {Test(parameters { "number-of-times" })public void accessPage(…

【C++题解】1605. 求一个两位数的个位和十位的和

问题&#xff1a;1605. 求一个两位数的个位和十位的和 类型&#xff1a;基本运算、拆位求解。 题目描述&#xff1a; 从键盘读入一个两位的整数 n &#xff0c;请求出这个两位整数个位和十位的和是多少&#xff1f; 输入&#xff1a; 一个两位的整数 n 。 输出&#xff1a…

hbase基础shell用法

HBase中用create命令创建表&#xff0c;具体如下&#xff1a; create student,Sname,Ssex,Sage,Sdept,course 此时&#xff0c;即创建了一个“student”表&#xff0c;属性有&#xff1a;Sname,Ssex,Sage,Sdept,course。因为HBase的表中会有一个系统默认的属性作为行键&#x…

【MySQL】事务篇

SueWakeup 个人主页&#xff1a;SueWakeup 系列专栏&#xff1a;学习技术栈 个性签名&#xff1a;保留赤子之心也许是种幸运吧 目录 本系列专栏 1. 什么是事务 2. 事务的特征 原子性&#xff08;Atomicity&#xff09; 一致性&#xff08;Consistency&#xff09; 隔离性&…