堆排序-java

这次主要讲了堆排序和堆的基本构造,下一期会详细讲述堆的各种基本操作。

文章目录

前言

一、堆排序

1.题目描述

2.堆

二、算法思路

1.堆的存储

2. 结点下移down

3.结点上移up

4.堆的基本操作

5.堆的初始化

三、代码如下

1.代码如下:

2.读入数据:

3.代码运行结果

总结


前言

这次主要讲了堆排序和堆的基本构造,下一期会详细讲述堆的各种基本操作。


提示:以下是本篇文章正文内容,下面案例可供参考

一、堆排序

1.题目描述

输入一个长度为 n 的整数数列,从小到大输出前 m小的数。

输入格式

第一行包含整数 n 和 m。

第二行包含 n 个整数,表示整数数列。

输出格式

共一行,包含 m 个整数,表示整数数列中前 m 小的数。

数据范围

1≤m≤n≤100000,
1≤数列中元素≤1000000000

2.堆

图2.1完全二叉树示意图 

完全二叉树:一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,每一层最多有2^{n-1}个结点,除了最后一层,其余层的结点数都是满的,且最后一层从左往右依次分布。

堆是一种基于完全二叉树的数据结构。可以分为大根堆,小根堆。

大根堆:每个结点的值都大于或者等于其左右孩子的值。

小根堆:每个结点的值都小于或者等于其左右孩子的值。 

二、算法思路

1.堆的存储

 图1.1堆的存储示例图

我们用一个一维数组来存储堆的值,下标来表示是哪个结点,下标为1就存储根节点的值,下标为2存储它的左孩子的值,下标为3存储它的右孩子的值,我们就可以类比推理出任一结点的左孩子和右孩子的下标。例如下标为x的结点,它的左孩子在数组中存储的下标就是2x,它的右孩子在数组中存储的下标是2x+1。(注:下标从1开始

2. 结点下移down

 图2.1示例一

 我们以一个小根堆为例,父结点的值要小于它的左右孩子结点。当我们将根节点修改为6后,此时小根堆的性质就被破坏了,那么我们就要对这个小根堆进行调整。

图2.2示例二 

此时,我们需要与根节点的左右孩子进行比较,得出6的左孩子3是3个点中最小的,进行交换。此时小根堆的性质还没维护好,此时我们还需要将6跟它的左右孩子进行比较,得出它的左孩子3是最小的,再将6和它的左孩子进行交换,此时检查后发现,符合小根堆的性质。即我们将某一个值变大,那么在小根堆中它就要下移。

    //传入结点下标public static void down(int x){int temp = x;//两个if语句来找出3个结点中最小的结点的下标if(2 * x <= size && heap[2* x] < heap[temp]){temp = 2 * x;}if (2 * x + 1 <= size && heap[2*x + 1] < heap[temp]){temp = 2 * x + 1;}//说明此时结点不是最小值,进行交换,再递归处理看是否还需要交换if(temp != x){int t = heap[temp];heap[temp] = heap[x];heap[x] = t;down(temp);}}

3.结点上移up

 

图3.1结点上移示例 

当我们把最右下角的结点值修改为2,此时小根堆的性质被破坏。我们把2和它的父结点进行比较得出2就是3个结点的最小值,2跟它的父结点进行交换;然后。此时的2再跟它的父结点进行比较得出2是3个结点中的最小值,将2跟它的父结点进行交换。此时检查后,发现符合小根堆的性质。可以看出如果值变大的话,我们需要进行结点上移操作,即结点上移来维护小根堆的性质。

up操作我们只需要跟父亲结点比就可以了。

    //传入结点下标public static void up(int x){int t = x;int temp =  x / 2;if(temp >= 1 && heap[temp] > heap[t]){t = temp;}if(t != x){int arr = heap[t];heap[t] = heap[x];heap[x] = arr;up(t);}}

 

4.堆的基本操作

我们引入一个一维整型数组heap来存储堆,一个整型变量size来表示堆中最后一个元素的下标或者堆中的元素个数。(数组下标0不用,我们从下标为1开始存储)

向堆中插入一个数:我们则直接在数组最后一个元素后面加入一个值,最后一个元素的下标为size即head[++size] = x;此时我们要预防堆的性质是否被破坏,那么我们直接执行结点上移操作即可。up(size);

求堆中的最小值:小根堆中的根节点就是堆中的最小值即head[1]。

删除最小值:即我们将根节点删除了,在一维数组中第一个元素我们很难删除,但是最后一个元素很容易删除,我们只需要用最后一个元素将根节点覆盖,然后将堆的大小减1即head[1] = head[size];dowx(1)来让结点下移来维护堆的性质。

删除任意一个元素:删除下标为k的结点值,我们还是用堆中的最后一个元素将这个元素值进行覆盖,然后将堆的大小减1即head[k] = head[size];size--;如果结点值变大的进行结点下移,结点值变小进行结点下移,那么我们直接down(k);up(k);因为它最后只会执行这两个操作中的一个,这样小根堆的性质也会被维护。

修改任意一个元素:修改下标为k的元素为x,那么我们需要head[k] = x;如果结点值变大的进行结点下移,结点值变小进行结点下移,那么我们直接down(k);up(k);因为它最后只会执行这两个操作中的一个,这样小根堆的性质也会被维护。

5.堆的初始化

图5.1示例图 

因为我们需要初始化建造一个小根堆,那么我们只需要从倒数第2层开始每一个结点进行结点下移操作就可以了。最后一层是叶子节点不需要进行结点下移操作。

        for(int i = 1; i <= n; i++){heap[i] = sc.nextInt();}size = n;//初始化建堆for(int i = n / 2;i > 0;i--){down(i);}

三、代码如下

1.代码如下:


import java.io.*;
import java.util.*;
public class 堆排序 {static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));static int N = 100010;//存储堆static int[] heap = new int[N];//堆中最后一个结点的下标,也是堆中元素的个数static int size = 0;public static void main(String[] args) throws Exception{Scanner sc = new Scanner(br);int n = sc.nextInt();int m = sc.nextInt();for(int i = 1; i <= n; i++){heap[i] = sc.nextInt();}size = n;//初始化建堆for(int i = n / 2;i > 0;i--){down(i);}while (m-- > 0){//打印最小值pw.print(heap[1] +" ");//删除堆中的根节点,然后维护小根堆性质heap[1] = heap[size];size--;down(1);}pw.flush();}//传入结点下标public static void down(int x){int temp = x;//两个if语句来找出3个结点中最小的结点的下标if(2 * x <= size && heap[2* x] < heap[temp]){temp = 2 * x;}if (2 * x + 1 <= size && heap[2*x + 1] < heap[temp]){temp = 2 * x + 1;}//说明此时结点不是最小值,进行交换,再递归处理看是否还需要交换if(temp != x){int t = heap[temp];heap[temp] = heap[x];heap[x] = t;down(temp);}}//传入结点下标public static void up(int x){int t = x;int temp =  x / 2;if(temp >= 1 && heap[temp] > heap[t]){t = temp;}if(t != x){int arr = heap[t];heap[t] = heap[x];heap[x] = arr;up(t);}}
}

2.读入数据:

5 3
4 5 1 3 2

3.代码运行结果

1 2 3 

总结

上述通过一些堆的基本操作来完成堆排序,后续会专门再写一次博客来详细介绍模拟堆的各种操作。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重庆人文科技学院建立“软件安全产学研基地”,推动西南地区软件安全发展

5月29日&#xff0c;重庆人文科技学院与开源网安签订了《产学研校企合作协议》&#xff0c;并举行了“重庆人文科技学院产学研基地”授牌仪式&#xff0c;此次合作不仅深化了双方在软件安全领域的产学研紧密联结&#xff0c;更是对川渝乃至西南地区软件供应链安全发展起到重要的…

C++17之std::void_t

目录 1.std::void_t 的原理 2.std::void_t 的应用 2.1.判断成员存在性 2.1.1.判断嵌套类型定义 2.1.2 判断成员是否存在 2.2 判断表达式是否合法 2.2.1 判断是否支持前置运算符 2.2.3 判断两个类型是否可做加法运算 3.std::void_t 与 std::enable_if 1.std::void_t 的…

相机等效焦距

1. 背景 物理焦距我们很熟悉,但是在接触实际的相机参数时,相机厂家会提到一个参数等效焦距,甚至有时候不提供物理焦距,这时候如果我们得到真实的物理焦距需要进行一定的转换.在介绍两者之间的转换关系前,先介绍一下等效焦距的由来. 如上图,假设在某一个镜头,其成像面会出现图…

操作系统 - 文件管理

文件管理 考纲内容 文件 文件的基本概念&#xff1b;文件元数据和索引节点(inode) 文件的操作&#xff1a;建立&#xff0c;删除&#xff0c;打开&#xff0c;关闭&#xff0c;读&#xff0c;写 文件的保护&#xff1b;文件的逻辑结构&#xff1b;文件的物理结构目录 目录的基…

Multipass虚拟机磁盘扩容

Multipass 是一个用于轻松创建和管理 Ubuntu 虚拟机的工具&#xff0c;特别适合开发环境。要使用 Multipass 扩大虚拟机的磁盘容量&#xff0c;你需要经历几个步骤&#xff0c;因为 Multipass 自身并不直接提供图形界面来调整磁盘大小。不过&#xff0c;你可以通过结合 Multipa…

UE5 Http Server

前言 最近要用UE 作为一个服务器去接收来自外部的请求&#xff0c;从而在UE中处理一些内容&#xff0c;但是之前只做过请求&#xff0c;哪整过这玩意&#xff0c;短期内还得出结果&#xff0c;那怎么搞嘞&#xff0c;本着省事的原则就找找呗&#xff0c;有没有现成的&#xff0…

Golang | Leetcode Golang题解之第123题买卖股票的最佳时机III

题目&#xff1a; 题解&#xff1a; func maxProfit(prices []int) int {buy1, sell1 : -prices[0], 0buy2, sell2 : -prices[0], 0for i : 1; i < len(prices); i {buy1 max(buy1, -prices[i])sell1 max(sell1, buy1prices[i])buy2 max(buy2, sell1-prices[i])sell2 m…

【Linux】进程间通信(System V IPC)

这节我们开始学习System V IPC方案。 分别是共享内存&#xff0c;消息队列与信号量 会着重讲解共享内存&#xff0c;但是消息队列与信号量只会说明一下原理。 原因&#xff1a;System V是新设计的一套标准 与文件的整合度不高只能进行本地通信 更何况&#xff0c;我们现在有…

IP代理池是什么?

从事跨境行业的朋友们总会有一个疑问&#xff0c;为什么自己所合作的IP代理商的IP在使用的过程中账号会有莫名封禁的问题&#xff0c;会不会是自己在使用的过程中错误的操作违反了平台的规则&#xff0c;其实不然有可能会是IP代理池纯净度不高的问题&#xff0c;有可能自己在使…

基于Jenkins+Kubernetes+GitLab+Harbor构建CICD平台

1. 实验环境 1.1 k8s环境 1&#xff09;Kubernetes 集群版本是 1.20.6 2&#xff09;k8s控制节点&#xff1a; IP&#xff1a;192.168.140.130 主机名&#xff1a;k8s-master 配置&#xff1a;4C6G 3&#xff09;k8s工作节点 节点1&#xff1a; IP&#xff1a;192.1…

基于字典树可视化 COCA20000 词汇

COCA20000 是美国当代语料库中最常见的 20000 个词汇&#xff0c;不过实际上有一些重复&#xff0c;去重之后大概是 17600 个&#xff0c;这些单词是很有用&#xff0c;如果能掌握这些单词&#xff0c;相信会对英语的能力有一个较大的提升。我很早就下载了这些单词&#xff0c;…

C++一个StringBad类

设计一个字符串类,下面的代码是一个不好的设计,起名StringBad。 //stringbad.h #pragma once //一个设计有问题的string类 #include <iostream> using namespace std;class StringBad { public:StringBad();//默认构造函数StringBad(const char* s);//构造函数~StringBa…

Java web应用性能分析之【jvisualvm远程连接云服务器】

Java web应用性能分析之【java进程问题分析概叙】-CSDN博客 Java web应用性能分析之【java进程问题分析工具】-CSDN博客 前面整理了java进程问题分析和分析工具&#xff0c;现在可以详细看看jvisualvm的使用&#xff0c;一般java进程都是部署云服务器&#xff0c;或者托管IDC机…

编译选项导致的结构体字节参数异常

文章目录 前言问题描述原因分析问题解决总结 前言 在构建编译工程时&#xff0c;会有一些对应的编译配置选项&#xff0c;不同的编译器&#xff0c;会有对应的配置项。本文介绍GHS工程中编译选项配置不对应导致的异常。 问题描述 在S32K3集成工程中&#xff0c;核1的INP_SWC…

【TB作品】MSP430F149,ADC采集,光强GY-30,DS18B20温度采集

功能 读取了GY-30 DS18B20 P6.0ADC P6.1ADC 显示到了LCD12864 硬件 //GY30 //SCL–P1.0 //SDA–P1.1 //VCC–3.3V //GND–GND //ADDR–不接 //DS18B20 //DATA–P1.6 //VCC–3.3V //GND–GND //ADC //DATA–P1.6 //P6.0 P6.1 ADC输入口 部分程序 #include <msp430.h>…

Java基础教程:算术运算符快速掌握

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

【Linux】文件系统和软硬链接

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…

计算机毕业设计 | springboot+vue会议室管理系统(附源码)

1&#xff0c;绪论 1.1 项目背景 随着企业规模的不断扩大&#xff0c;会议室管理愈加复杂。传统的手工预约会议室的方式已经无法满足现代企业的需求&#xff0c;因此&#xff0c;开发一套会议室系统方案变得尤为重要。会议室系统可以实现会议室的在线预约、会议室资源的有效利…

每周统计-20240531

用于测试程序的稳定性&#xff1a; 龙虎榜&#xff1a; 成交额&#xff1a; 封成比&#xff1a; 收盘前放量&#xff1a; 开盘抢筹&#xff1a; 封单额&#xff1a;

Linux下的配置工具menuconfig+配置文件(Kconfig/.config/defconfig)

我们都知道,嵌入式开发中,或者说C语言中,配置基本都是通过宏定义来决定的,在MCU开发中,代码量比较小,配置项也比较少,我们直接修改对应的宏定义即可。 但是,Linux开发中,操作系统、驱动部分还有应用部分加起来,代码量极大,配置项目也非常多,这时候,就需要对这些配…