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 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【算法】Leetcode第215题堆排序内部原理分析(C++) -> 正文阅读

[数据结构与算法]【算法】Leetcode第215题堆排序内部原理分析(C++)

1.前言

在这里插入图片描述
第一种方法是基于快速排序的选择方法【算法】Leetcode第215题快速排序内部原理分析(C++)
在这里插入图片描述
按照Leetcode官方题解的说法,堆排序是常见的面试问题,所以还是分析一下原理。

排序问题可以使用一种容器适配器即优先级队列,它就是一个“披着队列外衣”的堆,因为优先级队列对外提供的接口只有从队头取元素、从队尾添加元素,再无其他取元素的方式,看起来像一个队列。默认情况下priority_queue利用max-heap(大项堆)完成对元素的排序。
堆是一棵完全二叉树,数中每个节点值都不小于(或不大于)其左右孩子的值。如果父节点的值大于或等于左右孩子的值,那就是大项堆;反之则是小项堆。

2.基本原理

2.1构建二叉堆

我们可以用一个完全二叉树去表示数组,根结点在位置0,它的子结点在位置1和2,而子结点的子结点则分别在位置3、4、5、6,以此类推,直到数组元素都用完。这样形成的二叉树,又称二叉堆。

二叉堆是一组能够用推有序的完全二叉树排序的元素,并在数组中按层级存储。在下文中,我们将二叉堆称为堆。

在一个堆中,位置k的结点的子结点的位置分别为2k + 1 和 2k + 2。 比如位置1的结点的子结点分别是位置3和位置4。倘若位置是从1开始,则这个关系变成2k和2k+1。因为数组的序号从0开始,所以还是用前者的公式表达关系。

一开始的数组是无序的,意味着构建出来的堆也是无序的,那么就需要对堆进行有序化。

2.2 由上至下的推有序化(下沉)

如果堆的有序状态因为某个节点变得比它的子结点更小而被打破,那么我们需要通过交换它和它的子结点较大值来修复堆。交换后,它可能会也比新的子结点小,所以要继续交换。这种状态不断地把小的节点往下交换,所以形象地描述为下沉。

当一个结点太小的时候,它需要沉(sink)到堆的更低层。

可以先看看官方题解是如何进行下沉操作的。

    void maxHeapify(vector<int>& a, int i, int heapSize) {
        int l = i * 2 + 1, r = i * 2 + 2, largest = i;
        if (l < heapSize && a[l] > a[largest]) {
            largest = l;
        } 
        if (r < heapSize && a[r] > a[largest]) {
            largest = r;
        }
        if (largest != i) {
            swap(a[i], a[largest]);
            maxHeapify(a, largest, heapSize);
        }
    }

对于元素a[i]进行判断,求得左孩子和右孩子为2i + 1和2i + 2。接着要进行越界判断,如果越界了,证明不存在左/右孩子。largest指向最大的值。

如果这个最大的值并不是a[i], 那就得执行下沉操作,下沉完后调用maxHeapify继续判断是否要继续下沉。

我觉得这里用个循环,让它不断下沉,直到不能再下沉,这样逻辑可能更加清晰。

这是对元素进行遍历,进入maxHeapify判断是否下沉操作,那为什么它是从heapSize/2判断呢?

 void buildMaxHeap(vector<int>& a, int heapSize) {
        for (int i = heapSize / 2; i >= 0; --i) {
            maxHeapify(a, i, heapSize);
        } 
    }

首先下沉操作是从下往上的,所以i是递减的。对于i = heapSize/2,它的两个子结点分别是heapSize + 1和heapSize + 2,明显可见数组已经不存在这两个下标的元素。所以从heapSize/2的元素时不存在子结点的,也就没有下沉的可能性。

2.3 删除操作

前面已经完成二叉堆的构建,这时元素在堆上已经是有序的,根结点是最大的数。

要想删除最大的元素,先把根结点和最后那个叶子结点交换,因为叶子结点删除了不影响,根节点删除了就乱套了。叶子结点放在根节点之后,它的大小是不足以坐在根节点的宝座上的,所以需要对它执行下沉操作,让它回到属于它的位置。

        for (int i = nums.size() - 1; i >= nums.size() - k + 1; --i) {
            swap(nums[0], nums[i]);
            --heapSize;
            maxHeapify(nums, 0, heapSize);
        }

3.整体代码

字母l实现太难看了,换成left。

class Solution {
public:
    void maxHeapify(vector<int>& a, int i, int heapSize) 
        int left = i * 2 + 1, right = i * 2 + 2, largest = i;
        if (left < heapSize && a[left] > a[largest]) {
            largest = left;
        } 
        if ( right < heapSize && a[ right] > a[largest]) {
            largest =  right;
        }
        if (largest != i) {
            swap(a[i], a[largest]);
            maxHeapify(a, largest, heapSize);
        }
    }

    void buildMaxHeap(vector<int>& a, int heapSize) {
        for (int i = heapSize / 2; i >= 0; --i) {
            maxHeapify(a, i, heapSize);
        } 
    }

    int findKthLargest(vector<int>& nums, int k) {
        int heapSize = nums.size();
        buildMaxHeap(nums, heapSize);
        for (int i = nums.size() - 1; i >= nums.size() - k + 1; --i) {
            swap(nums[0], nums[i]);
            --heapSize;
            maxHeapify(nums, 0, heapSize);
        }
        return nums[0];
    }
};

部分资料来自《算法 第4版》《代码随想录》
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/solution/shu-zu-zhong-de-di-kge-zui-da-yuan-su-by-leetcode-/
来源:力扣(LeetCode)

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-14 01:32:52  更:2022-04-14 01:50:33 
 
开发: 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/26 10:26:16-

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