IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 堆排序详解 -> 正文阅读

[数据结构与算法]堆排序详解

什么是堆?

堆是一种完全二叉树「即每个节点的所在下标与满二叉树节点的下标一致」

根据堆的性质,可以将堆分成大根堆小根堆

  • 大根堆:每个节点的值大于等于它的左右孩子的值
  • 小根堆:每个节点的值小于等于它的左右孩子的值

大根堆

上图就是一个大根堆,我们可以将其映射到数组 array 中

大根堆对应的数组

根据大根堆的性质,我们很容易得到以下结论:

array[i] >= array[2 * i + 1] && array[i] >= array[2 * i + 2]

堆排序的基本思想

堆排序大体上可以分为三步:

  1. 将待排序的数组构建成一个大根堆,这样堆顶的元素就是最大的元素。
  2. 将堆顶元素和最后一个元素交换,然后将除去最后一个元素的剩下节点重新构造为一个大根堆
  3. 重复步骤 2 ,直至排序完成。「第一次可以得到最大的元素,第二次可以得到第二大的元素,依此类推」

类比:这个过程就像是,在一群人中找到一个最高的,让他和坐最后一排的人交换位置;然后在剩下的人中找到身高第二高的,让他和坐在倒数第二排的人交换位置;依此类推。

堆排序的详细实现

假设待排序数组 array =[5,8,2,4,3,6,7,1]

待排序数组

1 将待排序数组构建成一个大根堆

首先,将待排序数组变成一个完全二叉树

转换为完全二叉树

接下来,我们需要保证:每个节点的值比它的左右孩子的值要大。这里你可能会想,我们可以从最上层开始,比较父节点和子节点的大小关系,将较大的元素放在父节点上。这种方法看似是对的,但是我们从上往下遍历的过程中,上层的子节点可能被更大的值替换,导致部分子节点比父节点要大「即无法保证堆顶的值是最大的」。如下图所示

从上到下替换

因此,我们必须从下到上进行比较。为此,我们需要找到最后一个父节点,然后倒叙整理父子节点的大小关系。那么该怎么找到最后一个父节点呢?因为,在大根堆中array[i] >= array[2 * i + 1] && array[i] >= array[2 * i + 2],所以当叶子节点坐标为 length - 1 时**「下标最大的叶子节点」**,其父节点的坐标为 (length / 2) - 1。「根据 i * 2 + 1 = length - 1i * 2 + 2 = length - 1

找到最后一个父节点后,比较它和左右节点的值,如果左右节点的值比它大,将左右节点的较大值与它交换;否则不进行任何操作,对于 array ,会交换 7 和 2 的位置

交换 7 和 2 的位置

然后交换 8 和 5 的位置

交换 8 和 5 的位置

注意,如果交换节点后,下一层的子节点比父节点要大,还要继续进行交换。

将堆顶元素和最后一个元素交换,然后将除去最后一个元素的剩下节点重新构造为一个大根堆

将堆顶元素和最后一个元素进行交换

将堆顶元素和最后一个元素进行交换

  1. 重复步骤 2 ,直至排序完成。

我们用一个动态图感受一下整个过程

堆排序

代码实现

Kotlin

class Solution {
    fun heapSort(array: IntArray) {
        if (array.isEmpty()) return
        var length = array.size
        buildMaxHeap(array, length)
        for (i in length - 1 downTo 0) { // 这里可以写成 downTo 1 因为到 1 时已经交换完毕
            swap(array, 0, i) // 交换根顶和当前最后的元素
            length--
            heapify(array,0,length) // 因为交换,可能不满足大根堆的条件,对堆顶元素进行调整
        }
    }

    private fun buildMaxHeap(array: IntArray, length: Int) {
        val fatherIndex = (length / 2) + 1 // 找到最后一个父节点所在下标
        for (i in fatherIndex downTo 0) {
            heapify(array, i, length)
        }
    }

    private fun swap(array: IntArray, i: Int, j: Int) {
        val temp = array[i]
        array[i] = array[j]
        array[j] = temp
    }

    private fun heapify(array: IntArray, i: Int, length: Int) {
        val left = 2 * i + 1 // 左节点
        val right = 2 * i + 2 // 右节点
        var largeIndex = i // 父节点与左右节点中的最大值对应的下标
        if (left < length && array[left] > array[largeIndex]) largeIndex = left
        if (right < length && array[right] > array[largeIndex]) largeIndex = right
        if (largeIndex != i) {
            swap(array, largeIndex, i) // 交换后,可能导致下层不是大根堆
            heapify(array, largeIndex, length)
        }
    }
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 11:03:35  更:2022-07-03 11:05:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:11:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码