手撕堆排序
手撕堆排序
题目描述
给你一个整数数组 nums
,请你运用堆排序将该数组升序排列。
示例 1:
1 | 输入:nums = [5,2,3,1] |
示例 2:
1 | 输入:nums = [5,1,1,2,0,0] |
提示:
1 <= nums.length <= 50000
-50000 <= nums[i] <= 50000
算法思路
运用堆排序在原数组的基础上完成排序的思路主要分为两步:
- 建立大根堆;
- 然后将大根堆最大的元素,也就是第一个元素,与大根堆中最后一个元素进行调换,然后将剩下的
len - 1
个数重新调整为大根堆。重复这个过程,最后会得到一个有序的序列。
然后主要的过程分为两个,一个是建立大根堆的过程,一个是调整大根堆的过程。
首先是向下调整的过程:
对于下标为index
的元素,如果要将这个元素以下的元素重新调整为大根堆,那么就需要将index
的元素与它的两个子节点中较大元素进行比较。如果num[index] < num[maxChild]
,那么就需要调换元素。然后通过这个方法,将这个元素以下的所有元素都检查一遍。
需要注意一点,如果这个数组是从下标
0
开始,那么对于下标index
的元素,它的两个子节点的下标就是2 * index + 1
和2 * index + 2
。如果这个数组是从下标
1
开始,那么对于下标index
的元素,它的两个子节点的下标就是2 * index
和2 * index + 1
。
如果理解了向下调整的过程,那么就很容易理解建堆的过程:
将这个数组中前一半的元素进行向下调整的过程就可以得到大根堆。
然后就可以得出参考代码。
如果想通过图像或者动画加深了解,可以浏览下述链接:
参考代码
1 | void adjustHeap(vector<int>& num, int len, int index){ |
复杂度分析
时间复杂度:
空间复杂度:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 二进制的叮当喵!