堆排序算法详细分析

article/2025/10/29 18:22:51

一、堆相关概念

1.堆

堆是完全二叉树,即除最后一层外,其它层都是满的,且最后一层从左到右依次都有元素。如下图所示。
在这里插入图片描述

堆是用数组来实现的,图中下标就为数组的下标,其对应数组[5, 1, 7, 2, 8, 6, 3, 9, 4],可以看出节点i的左子节点对应2i+1节点,右子节点为2i+2,父节点为(i-1)/2。

2.大顶堆与小顶堆

大顶堆:若堆中每个非叶子节点的值均大于等于其子节点的值,则称这个堆为大顶堆。
在这里插入图片描述
小顶堆:若堆中每个非叶子节点的值均小于等于其子节点的值,则称这个堆为小顶堆。
在这里插入图片描述
大顶堆与小顶堆对左右子节点值的大小没有要求。

二、堆排序的基本思想

1.根据大顶堆和小顶堆的概念,可知它们的根节点对应整个堆最大值与最小值。

2.将长度为n的待排序数组调节成大顶堆(或小顶堆),将数组头元素与末尾元素互换,最大值(最小值)就放在了最后。

3.继续将数组的前n-1位调成大顶堆(或小顶堆),将数组头元素与第n-1个元素互换,将次大值(次小值)放在对应位置,按此方法,一直循环调节与互换,直到待调节元素为1个。

4.最后将得到升序(降序)的数列。

三、代码实现分析

1.将堆调节成大顶堆(以大顶堆为例)

(1) 方法概述

一个堆调节成大顶堆的过程是比较复杂的。
函数:这里定义一个函数,该函数可以将以堆中某个非叶子节点为根节点的子树调节成大顶堆(只是部分为大顶堆)。

思路:从最后一个叶子节点开始调节,接着调节这个节点的前一个节点(即数组中的前一个元素,且最后一个非叶子节点的前面都是非叶子节点),直到调节到整个堆根节点(即数组头元素)。
优点:这样可以保证每次调节节点时,该节点的左右子树都是大顶堆。

要点:调节该非叶子节点i,就是将其与左右子节点中的最大值放在该节点,此处若该节点为最大值,则以该节点为根节点的树就是大顶堆,不用进行调整。若该节点不为最大值,则会与左右子节点中最大值发生互换,这可能会影响左右子树是否还为大顶堆,此时需要进一步调整左右子树,调整方法与前面相同。直到调整到叶子节点,此时以非叶子节点i为根节点的树,就成为了大顶堆。

堆中最后一个非叶子节点的索引:arr.length/2 - 1。

(2) 图解

以arr = [5, 1, 7, 2, 8, 6, 3, 9, 4]为例:
在这里插入图片描述
arr.length/2 - 1 = 3,第一个飞叶子节点索引为3。交换后:
在这里插入图片描述

调整索引为2的:不变
在这里插入图片描述

调整索引为1的:
在这里插入图片描述
这里左子树因互换而不满足大顶堆,需调整:
在这里插入图片描述
调节索引为0的:
在这里插入图片描述
调节其左子树:
在这里插入图片描述
索引为4的是叶子节点,结束调整。
调节完索引为0的节点,调节结束,大顶堆形成。

(3) 代码

调节节点函数:

/*** 将以i为根节点对应的树调节成大顶堆* @param arr 待调整的数组* @param i 非叶子节点在数组中的位置* @param length 表示待调整树的长度(越来越小)** 第i节点的左子节点为【2*i+1】,右子节点为【2*i+2】*/public static void adjustHeap(int[] arr, int i, int length) {int temp = arr[i];//先取出当前元素的值,保存在临时变量//开始调整for (int index = i * 2 + 1; index < length; index = index * 2 + 1) {if (index + 1 < length && arr[index] < arr[index + 1]) {//找左子节点和右子节点的最大值index++;}if (arr[index] > temp) {//子节点大于当前节点的值arr[i] = arr[index];arr[index] = temp;i = index;//i指向index,继续循环比较,调整成大顶堆} else {break;}}}public static void main(String[] args){int[] arr = {5, 1, 7, 2, 8, 6, 3, 9, 4};//将整个堆调成大顶堆for (int i = arr.length / 2 - 1; i >= 0; i--) {adjustHeap(arr, i, arr.length);}}

2.堆排序算法

1.直接嵌套循环(不推荐)

 public static void heapSort(int[] arr){System.out.println("堆排序");for(int length = arr.length;length > 1;length--){//调节成大顶堆for(int i = length/2-1;i>=0;i--){adjustHeap(arr, i ,length);}int temp = arr[0];arr[0] = arr[length - 1];arr[length - 1] = temp;}}

调节完成后,进行交换,再调节的短一个的数组(length–),此种方法容易理解,但耗时很大。

2.从0开始调节
我们注意到从第二次开始调节开始(下图为第二次调节开始时),根节点的左右子树都满足大顶堆的概念,无需进行从下至上的排序,直接从根节点开始调节即可。

代码:

    public static void heapSort(int[] arr){int temp;//将树调成大顶堆for (int i = arr.length / 2 - 1; i >= 0; i--) {adjustHeap(arr, i, arr.length);}//从0开始反复调节for (int k = arr.length - 1; k > 0; k--) {temp = arr[0];arr[0] = arr[k];arr[k] = temp;adjustHeap(arr, 0, k);}}

四、完整代码

public class HeapSort {public static void main(String[] args) {int[] arr = {5, 1, 7, 2, 8, 6, 3, 9, 4};heapSort(arr);System.out.println(Arrays.toString(arr));}public static void heapSort(int[] arr){int temp;//将树调成大顶堆for (int i = arr.length / 2 - 1; i >= 0; i--) {adjustHeap(arr, i, arr.length);}for (int k = arr.length - 1; k > 0; k--) {temp = arr[0];arr[0] = arr[k];arr[k] = temp;adjustHeap(arr, 0, k);}}public static void adjustHeap(int[] arr, int i, int length) {int temp = arr[i];//先取出当前元素的值,保存在临时变量//开始调整for (int index = i * 2 + 1; index < length; index = index * 2 + 1) {if (index + 1 < length && arr[index] < arr[index + 1]) {//找左子节点和右子节点的最大值index++;}if (arr[index] > temp) {//子节点大于当前节点的值arr[i] = arr[index];arr[index] = temp;i = index;//i指向k,继续循环比较,调整成大顶堆} else {break;}}}
}

http://chatgpt.dhexx.cn/article/UpHZwxvO.shtml

相关文章

数据结构——堆排序(算法)

基本介绍 1&#xff09;、堆排序是利用堆这种数据结构而设计的一种排序算法&#xff0c;堆排序是一种选择排序&#xff0c;它的最好、最坏、平均时间复杂度均为O(nlogn)&#xff0c;它也是不稳定排序。2&#xff09;、堆是具有以下性质的完全二叉树&#xff1a;每个节点的值都…

C++:堆排序算法详解

图解排序算法(三)之堆排序 预备知识 堆排序 堆排序是利用堆这种数据结构而设计的一种排序算法&#xff0c;堆排序是一种选择排序&#xff0c;它的最坏&#xff0c;最好&#xff0c;平均时间复杂度均为O(nlogn)&#xff0c;它也是不稳定排序。首先简单了解下堆结构。 堆 堆是具有…

排序算法:堆排序算法实现及分析

堆排序介绍 堆排序&#xff08;Heap Sort&#xff09;就来利用堆&#xff08;假设利用大顶堆&#xff09;进行排序的方法。它的基本思想是&#xff0c;将待排序的序列构成一个大顶堆。此时&#xff0c;整个序列的最大值就是堆顶的根结点。将它移走&#xff08;其实就是将其与堆…

堆排序算法 总结

最近面试&#xff0c;老是被问到堆排序算法。 回答时老是感觉思路不清楚&#xff0c;现在总结一下&#xff0c;把思路弄清楚的。 1.堆排序是利用堆的特性对记录序列进行排序的一种排序方法。 好的那么堆得特性是什么呢&#xff1f; 堆得定义&#xff1a; 堆是满足下列性质的数…

Java实现堆排序算法

堆排序是计算机编程中一种流行且高效的排序算法。学习如何编写堆排序算法需要了解两种类型的数据结构-数组和树。 我们要排序的初始数字集存储在数组中&#xff0c;例如[10, 3, 76, 34, 23, 32]&#xff0c;排序后&#xff0c;我们得到一个排序后的数组[3,10,23,32,34,76] 堆排…

精通八大排序算法系列:二、堆排序算法

精通八大排序算法系列&#xff1a;二、堆排序算法 作者:July 、二零一一年二月二十日本文参考&#xff1a;Introduction To Algorithms&#xff0c;second edition。------------------- 此精通排序算法系列&#xff0c;前一节&#xff0c;已讲过了一、快速排序算法&#xff0c…

堆排序算法详解

一、堆排序算法原理和动态图解 将待排序的序列构造成一个大顶堆。此时&#xff0c;整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素交换&#xff0c;此时末尾元素就是最大值)&#xff0c;然后将剩余的n-1个序列重新构造成一个堆&#xff0c;这样就…

【堆排序算法】(C语言实现)

堆排序 一.堆排序1.堆的概念及性质1.1堆的概念1.2堆的性质 二.向下调整和向上调整两大算法1. 向下调整算法2.1 向下调整算法基本思路 2. 向上调整算法2.2 向上调整的基本思路 三.堆的实现&#xff08;小堆&#xff09;1.头文件包含2. 接口实现 四.任意树调整为堆&#xff08;小…

堆排序算法

堆排序 堆排序&#xff08;Heapsort&#xff09;是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构&#xff0c;并同时满足堆积的性质&#xff1a;即子结点的键值或索引总是小于&#xff08;或者大于&#xff09;它的父节点。 基本思想 利用大顶堆…

3.图解排序算法(三)之堆排序

作者&#xff1a; dreamcatcher-cx 出处&#xff1a; http://www.cnblogs.com/chengxiao/ 本文版权归作者和博客园共有&#xff0c;欢迎转载&#xff0c;但未经作者同意必须保留此段声明&#xff0c;且在页面明显位置给出原文链接。 原文链接&#xff1a;https://www.cnblogs.…

排序算法:堆排序

相关博客&#xff1a; 排序算法&#xff1a;冒泡排序、插入排序、选择排序、希尔排序 排序算法&#xff1a;归并排序、快速排序 排序算法&#xff1a;桶排序、计数排序、基数排序 排序算法&#xff1a;堆排序 十大排序算法小结 一、堆&#xff1a; 1、什么是堆&#xff1…

排序算法 —— 堆排序(图文超详细)

文章目录 堆排序1. 排序思路2. 如何建成大根堆2.1. 将待排序的数据看成一个完全二叉树。2.2. 建堆思想2.3. 建堆步骤2.3.1.先将最后一棵子树建成大根堆2.3.2.将其余子树建成大根堆2.3.3. 代码分析 3 如何实现堆排序3.1 排序思路3.2 代码实现的思路3.3 代码分析3.4 排序过程 4. …

十大经典排序算法----堆排序(超详细)

目录 1. 堆排序的基础知识 1.1 大顶堆&&小顶堆 1.2 向下调整算法 1.3 物理结构与逻辑结构的关系 2. 堆排序详解 2.1 堆排序整体思路 2.2 思路详解 2.2.1 建堆 2.2.2 大堆or小堆 2.2.3 输出数据 3. 时间复杂度分析 4. 完整代码 5. 彩蛋 1. 堆排序的基础知识…

【转载】堆排序算法(图解详细流程)

堆排序的时间复杂度O(N*logN),额外空间复杂度O(1)&#xff0c;是一个不稳定性的排序 目录 一 准备知识 1.1 大根堆和小根堆 二 堆排序基本步骤 2.1 构造堆 2.2 固定最大值再构造堆 三 总结 四 代码 一 准备知识 堆的结构可以分为大根堆和小根堆&#xff0c;是一个完全…

堆排序算法(图解详细流程)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 堆排序基本介绍大顶堆举例说明小顶堆举例说明堆排序的基本思想堆排序步骤图解说明堆排序的基本思路总结 堆排序基本介绍 堆排序是利用堆这种数据结构而设计的一种排…

堆排序详细图解(通俗易懂)

什么是堆 堆是一种叫做完全二叉树的数据结构&#xff0c;可以分为大根堆&#xff0c;小根堆&#xff0c;而堆排序就是基于这种结构而产生的一种程序算法。 堆的分类 大根堆:每个节点的值都大于或者等于他的左右孩子节点的值 小根堆:每个结点的值都小于或等于其左孩子和右孩子…

PreferenceActivity(二)

看到很多书中都没有对PreferenceActivity做介绍&#xff0c;而我正好又在项目中用到&#xff0c;所以就把自己的使用的在这总结一下&#xff0c;也方便日后查找。 PerferenceActivity是什么&#xff0c;看下面的截图&#xff1a; Android系统截图&#xff08;左&#xff09; …

android设置页面之PreferenceActivity及Preference

离上篇博客刚好一周&#xff0c;希望后面会记录更多的内容&#xff0c;也算自己的Android笔记吧。 本篇主要记录一般的android设置页面PreferenceActivity的使用以及与之剪不断&#xff0c;理还乱的Preference。 &#xff08;一&#xff09;如何使用 Android系统自带的设置应用…

android中PreferencesActivity的使用(一)

在使用android手机的时候&#xff0c;尤其是在操作软件设置时&#xff0c;我们经常见到这样的界面&#xff1a; 这是怎么来实现的的呢&#xff1f;其实android已经提供了相应的类和方法&#xff0c;当进行简单数据存储时&#xff08;比如&#xff1a;软件配置参数&#xff09;a…

PreferenceActivity用法简介(二)

本测试主要是为了测试PreferenceActivity的使用&#xff0c;其中设置了播放背景音乐和开启wifi的设置&#xff0c;也就是本文要讲的 PreferenceActivity。 Android提供了放摆放的工具来定义所有的程序的首选项&#xff0c;并支持既不不许要编写代码的情况写显示这些首选项。可…