堆排序(堆的构造及代码实现)

🍓 简介:java系列技术分享(👉持续更新中…🔥)
🍓 初衷:一起学习、一起进步、坚持不懈
🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏
🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝

🍓 更多文章请点击
在这里插入图片描述在这里插入图片描述

文章目录

  • 一、堆的简介
  • 二、堆的实现
    • 2.1 insert插入方法的实现
    • 2.2 删除最大元素方法的实现
    • 2.3 代码实现
    • 2.4 测试-新增和删除最大值
  • 三、堆排序
    • 3.1 实现思路
    • 3.2 堆构造过程
    • 3.3 堆排序过程
    • 3.4 代码实现
    • 3.5 测试

2

一、堆的简介

堆通常可以被看做是一棵完全二叉树的数组对象。

堆的特性:

  1. 它是完全二叉树,除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不是满的,那么要求左满右不满。
    在这里插入图片描述
  2. 它通常用数组来实现。
    • 具体方法就是将二叉树的结点按照层级顺序放入数组中,根结点在位置1,它的子结点在位置2和3,而子结点的子结点则分别在位置4,5,6和7,以此类推。

    • 如果一个结点的位置为k,则它的 父结点的位置为[k/2],而它的 两个子结点的位置则分别为2k和2k+1。这样,在不使用指针的情况下,我们也可以通过计算数组的索引在树中上下移动:从a[k]向上一层,就令k等于k/2,向下一层就令k等于2k或2k+1。

    • 每个结点都大于等于它的两个子结点。这里要注意堆中仅仅规定了每个结点大于等于它的两个子结点,但这两个子结点的顺序并没有做规定,跟我们之前学习的二叉查找树是有区别的。
      在这里插入图片描述

二、堆的实现

2.1 insert插入方法的实现

堆是用数组完成数据元素的存储的,但是堆中对元素的顺序是有要求的,每一个结点的数据要大于等于它的两个子结点的数据,所以每次插入一个元素,都会使得堆中的数据顺序变乱,这个时候我们就需要通过一些方法让刚才插入的这个数据放入到合适的位置。

所以,如果往堆中新插入元素,我们只需要不断的比较新结点a[k]和它的父结点a[k/2]的大小,然后根据结果完成数据元素的交换,就可以完成堆的有序调整。

在这里插入图片描述

2.2 删除最大元素方法的实现

  • 由堆的特性我们可以知道,索引1处的元素,也就是根结点就是最大的元素,当我们把根结点的元素删除后,需要有一个新的根结点出现,这时我们可以暂时把堆中最后一个元素放到索引1处,充当根结点,但是它有可能不满足堆的有序性需求,这个时候我们就需要通过一些方法,让这个新的根结点放入到合适的位置。
  • 所以,当删除掉最大元素后,只需要将最后一个元素放到索引1处,并不断的拿着当前结点a[k]与它的子结点a[2k]和a[2k+1]中的较大者交换位置,即可完成堆的有序调整。

在这里插入图片描述

2.3 代码实现

public class Heap<T extends Comparable<T>> {//存储堆中的元素private T[] items;//记录堆中元素的个数private int N;public Heap(int capacity) {this.items = (T[]) new Comparable[capacity + 1];this.N = 0;}//判断堆中索引i处的元素是否小于索引j处的元素private boolean less(int i, int j) {return items[i].compareTo(items[j]) < 0;}//交换堆中i索引和j索引处的值private void exch(int i, int j) {T temp = items[i];items[i] = items[j];items[j] = temp;}//往堆中插入一个元素public void insert(T t) {items[++N] = t;swim(N);}//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置private void swim(int k) {//通过循环,不断的比较当前结点的值和其父结点的值,如果发现父结点的值比当前结点的值小,则交换位置while (k > 1) {//比较当前结点和其父结点if (less(k / 2, k)) {exch(k / 2, k);}k = k / 2;}}//删除堆中最大的元素,并返回这个最大元素public T delMax() {T max = items[1];//交换索引1处的元素和最大索引处的元素,让完全二叉树中最右侧的元素变为临时根结点exch(1, N);//最大索引处的元素删除掉items[N] = null;//元素个数-1N--;//通过下沉调整堆,让堆重新有序sink(1);return max;}//使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置private void sink(int k) {//通过循环不断的对比当前k结点和其左子结点2*k以及右子结点2k+1处中的较大值的元素大小,如果当前结点小,则需要交换位置while (2 * k <= N) {//获取当前结点的子结点中的较大结点int max;//记录较大结点所在的索引if (2 * k + 1 <= N) {if (less(2 * k, 2 * k + 1)) {max = 2 * k + 1;} else {max = 2 * k;}} else {max = 2 * k;}//比较当前结点和较大结点的值if (!less(k, max)) {break;}//交换k索引处的值和max索引处的值exch(k, max);//变换k的值k = max;}}
}

2.4 测试-新增和删除最大值

public static void main(String[] args) {Heap<String> heap = new Heap<String>(20);heap.insert("A");heap.insert("B");heap.insert("C");heap.insert("D");heap.insert("E");heap.insert("F");heap.insert("G");String del;while ((del = heap.delMax()) != null) {System.out.print(del + ",");}}

在这里插入图片描述

三、堆排序

String[] arr = {“S”,“O”,“R”,“T”,“F”,“X”,“A”,“M”,“P”,“L”,“E”},请对数组中的字符按从小到大排序。

3.1 实现思路

  1. 构造堆;

  2. 得到堆顶元素,这个值就是最大值;

  3. 交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到合适的位置;

  4. 对堆进行调整,重新让除了最后一个元素的剩余元素中的最大值放到堆顶;

  5. 重复2~4这个步骤,直到堆中剩一个元素为止。

在这里插入图片描述

3.2 堆构造过程

创建一个新数组,把原数组的数据拷贝到新数组,再从新数组长度的一半处开始往1索引处扫描(从右往左),然后对扫描到的每一个元素做下沉调整即可。
在这里插入图片描述

3.3 堆排序过程

对构造好的堆,我们只需要做类似于堆的删除操作,就可以完成排序。

  1. 将堆顶元素和堆中最后一个元素交换位置

  2. 通过对堆顶元素下沉调整堆,把最大的元素放到堆顶(此时最后一个元素不参与堆的调整,因为最大的数据已经到了数组的最右边)

  3. 重复1~2步骤,直到堆中剩最后一个元素。

在这里插入图片描述

3.4 代码实现

public class HeapSort {//判断heap堆中索引i处的元素是否小于索引j处的元素private static boolean less(Comparable[] heap, int i, int j) {return heap[i].compareTo(heap[j]) < 0;}//交换heap堆中i索引和j索引处的值private static void exch(Comparable[] heap, int i, int j) {Comparable tmp = heap[i];heap[i] = heap[j];heap[j] = tmp;}//根据原数组source,构造出堆heapprivate static void createHeap(Comparable[] source, Comparable[] heap) {//把source中的元素拷贝到heap中,heap中的元素就形成一个无序的堆System.arraycopy(source, 0, heap, 1, source.length);//对堆中的元素做下沉调整(从长度的一半处开始,往索引1处扫描)for (int i = (heap.length) / 2; i > 0; i--) {sink(heap, i, heap.length - 1);}}//对source数组中的数据从小到大排序public static void sort(Comparable[] source) {//构建堆 因为0索引废弃,所以长度加1Comparable[] heap = new Comparable[source.length + 1];createHeap(source, heap);//定义一个变量,记录未排序的元素中最大的索引int N = heap.length - 1;//通过循环,交换1索引处的元素和排序的元素中最大的索引处的元素while (N != 1) {//交换元素exch(heap, 1, N);//排序交换后最大元素所在的索引,让它不要参与堆的下沉调整N--;//需要对索引1处的元素进行堆的下沉调整sink(heap, 1, N);}//把heap中的数据复制到原数组source中System.arraycopy(heap, 1, source, 0, source.length);}//在heap堆中,对target处的元素做下沉,范围是0~rangeprivate static void sink(Comparable[] heap, int target, int range) {while (2 * target <= range) {//1.找出当前结点的较大的子结点int max;if (2 * target + 1 <= range) {if (less(heap, 2 * target, 2 * target + 1)) {max = 2 * target + 1;} else {max = 2 * target;}} else {max = 2 * target;}//2.比较当前结点的值和较大子结点的值if (!less(heap, target, max)) {break;}exch(heap, target, max);target = max;}}}

3.5 测试

public class HeapSortTest {public static void main(String[] args) {//待排序数组String[] arr = {"S","O","R","T","F","X","A","M","P","L","E"};//通过HeapSort对数组中的元素进行排序HeapSort.sort(arr);//打印排序后数组中的元素System.out.println(Arrays.toString(arr));}
}

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

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

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

相关文章

亿发2023智能ERP生产系统解决方案实施,规范中大型企业生产精细化

随着制造水平的不断增强&#xff0c;传统工厂的管理方式已经不能满足现代制造的要求。为了确保公司战略目标的实现&#xff0c;中大型制造企业需要借助信息技术来强化对业务流程的管理&#xff0c;而生产制造ERP系统的实施已成为企业走向信息化的关键战略环节。 工厂信息化建设…

02. Springboot集成Flyway

目录 1、前言 2、什么是Flyway&#xff1f; 3、为什么要使用 Flyway&#xff1f; 4、简单示例 4.1、创建Spring Boot工程 4.2、添加Flyway依赖 4.3、Springboot添加Flyway配置 4.4、创建执行SQL脚本 4.5、启动测试 4.6、Flyway版本管理 5、SQL脚本文件命名规则 6、…

荣誉加冕!八方锦程再次荣获招聘与任用价值大奖

智享会ALL IN 2023 人力资源服务展汇聚了全国32个省市地区,21个行业的HR从业者、上下游客户,9月19-20日齐聚上海跨国采购会展中心,共同见证ALL IN 2023的盛大开幕! 作为人力资源行业的奋进者,八方锦程与智享会同行走过了几载春秋,始终致力于推进人力资源服务高质量发展。 在本…

面试题:HTTPS 是如何保证传输安全的?又被问了!

文章目录 1. HTTP 协议1.1 HTTP 协议介绍1.2 HTTP 中间人攻击1.3 防止中间人攻击 2. HTTPS 协议2.1 HTTPS 简介2.2 CA 认证体系 总结 1. HTTP 协议 在谈论 HTTPS 协议之前&#xff0c;先来回顾一下 HTTP 协议的概念。 1.1 HTTP 协议介绍 HTTP 协议是一种基于文本的传输协议&…

SpringBoot调用ChatGPT-API实现智能对话

目录 一、说明 二、代码 2.1、对话测试 2.2、单次对话 2.3、连续对话 2.4、AI绘画 一、说明 我们在登录chatgpt官网进行对话是不收费的&#xff0c;但需要魔法。在调用官网的API时&#xff0c;在代码层面上使用&#xff0c;通过API KEY进行对话是收费的&#xff0c;不过刚…

基于Java社区生鲜电商平台设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

网络爬虫-----爬虫的分类及原理

目录 爬虫的分类 1.通用网络爬虫&#xff1a;搜索引擎的爬虫 2.聚焦网络爬虫&#xff1a;针对特定网页的爬虫 3.增量式网络爬虫 4.深层网络爬虫 通用爬虫与聚焦爬虫的原理 通用爬虫&#xff1a; 聚焦爬虫&#xff1a; 爬虫的分类 网络爬虫按照系统结构和实现技术&#…

所有人别错过!云计算真的不错,前景钱途并存!

近年来&#xff0c;中国云计算产业发展迅猛&#xff0c;保持30%以上的年均增长率&#xff0c;成为全球增速最快的市场之一&#xff0c;云计算应用领域正向制造、政务、金融、医疗、教育等企业级市场延伸拓展。目前&#xff0c;云计算应用的普及促使开源技术广受关注&#xff0c…

Linux内核源码分析 (B.5)推演 slab 内存池的设计与实现

Linux内核源码分析 (B.5)推演 slab 内存池的设计与实现 文章目录 Linux内核源码分析 (B.5)推演 slab 内存池的设计与实现[toc] 1\. 前文回顾2\. 既然有了伙伴系统&#xff0c;为什么还需要 Slab ?3\. slab 对象池在内核中的应用场景4\. slab, slub, slob 傻傻分不清楚5\. 从一…

C语言的编译过程详解

当我们编译C程序时会发生什么&#xff1f;编译过程中的组件有哪些&#xff0c;编译执行过程是什么样的? 什么是编译 C语言的编译过程就是把我们可以理解的高级语言代码转换为计算机可以理解的机器代码的过程&#xff0c;其实就是一个翻译的过程。 …

低噪声 256 细分微步进电机驱动MS35774/MS35774A(汽车应用级别)

MS35774/MS35774A 是一款高精度、低噪声的两相步进 电机驱动芯片&#xff0c;芯片内置功率 MOSFET&#xff0c;长时间工作的平均电 流可以达到 1.4A&#xff0c;峰值电流 2A。芯片集成了过温保护、欠压 保护、过流保护、短地保护、短电源保护功能。 主要特点 ◼ 2 相步进电机…

揭秘期权卖方稳赚的方法策略!

期权的卖方&#xff08;也称为房东包租婆&#xff09;是指出售期权合约的人&#xff0c;其赚取的费用被称为期权权利金。也就是房租租金&#xff0c;作为卖方&#xff0c;您有义务在期限内按照合约规定的价格出售或购买标的资产&#xff0c;下文介绍期权卖方稳赚的方法策略有哪…

国外发达国家码农是真混得好么?

来看看花旗工作十多年的码农怎么说吧! 美国最大的论坛 Reddit&#xff0c;之前有一个热帖&#xff1a; 一个程序员说自己喝醉了&#xff0c;软件工程师已经当了10年&#xff0c;心里有 好多话想说&#xff0c;“我可能会后悔今天说了这些话。”他洋洋洒洒写了 一大堆&#xff…

Hive内置函数字典

写在前面&#xff1a;HQL同SQL有很多的类似语法&#xff0c;同学熟悉SQL后一般学习起来非常轻松&#xff0c;写一篇文章列举常用函数&#xff0c;方便查找和学习。 1. 执行模式 1.1 Batch Mode 批处理模式 当使用-e或-f选项运行$ HIVE_HOME / bin / hive时&#xff0c;它将以…

数据挖掘十大算法

参考&#xff1a; ICDM&#xff1a;数据挖掘十大算法

1、RocketMQ概述

第1章 RocketMQ概述 一、MQ概述 1、MQ简介 MQ&#xff0c;Message Queue&#xff0c;是一种提供消息队列服务的中间件&#xff0c;也称为消息中间件&#xff0c;是一套提供了消息生 产、存储、消费全过程API的软件系统。消息即数据。一般消息的体量不会很大。 2、MQ用途 从网上…

AI文本创作在百度App发文的实践

作者 | 内容生态端团队 导读 大语言模型&#xff08;LLM&#xff09;指包含数百亿&#xff08;或更多&#xff09;参数的语言模型&#xff0c;这些模型通常在大规模数据集上进行训练&#xff0c;以提高其性能和泛化能力。在内容创作工具接入文心一言AI能力后&#xff0c;可以为…

无涯教程-JavaScript - SIGN函数

描述 SIGN功能确定数字的符号。该函数返回- 如果数字为正,则为1 如果数字为0,则零(0) -1,如果数字为负 语法 SIGN (number)争论 Argument描述Required/OptionalNumberAny real number.Required Notes 如果指定的数字未被识别为数字值,则SIGN返回#VALUE!错误。 适用性 …

阿里云通义千问向全社会开放,近期将开源更大参数规模大模型

9月13日&#xff0c;阿里云宣布通义千问大模型已首批通过备案&#xff0c;并正式向公众开放&#xff0c;广大用户可登录通义千问官网体验&#xff0c;企业用户可以通过阿里云调用通义千问API。 通义千问在技术创新和行业应用上均位居大模型行业前列。IDC最新的AI大模型评估报告…

网络路径监控分析

不间断的连接应该是任何企业的首要任务。然而&#xff0c;确保网络中的源和目标之间持续、不间断的联系一直是网络通信中一个劳动密集型的过程。了解网络路径中的障碍、识别它们并迅速解决它们以维护健康、不间断的网络至关重要。 为什么要监控网络路径 维护网络运行状况是任…