思路
最大堆:根结点为最大值
最大堆的第一个跟节点(最大值)和最后一个元素(最小值)交换位置
「推导」
[3,1,4,5,7]
(3) --> (1) --> (5)
--> (7)
--> (4)
根节点为2
i = 0, 7>5>1,交换节点
(3) --> (7) --> (5)
--> (1)
--> (4)
i = 1, 7>4>3
5>1>3
(7) --> (5) --> (3)
--> (1)
--> (4)
最大值和最小值换位置
arr:[7]
(1) --> (5) --> (3)
--> (4)
重新遍历成最大堆:
(5) --> (3) --> (1)
--> (4)
最大值和最小值换位置
arr:[7,5]
(1) --> (3)
--> (4)
重新遍历成最大堆:
(4) --> (3)
--> (1)
最大值和最小值换位置
arr:[7,5,4]
(3) --> (1)
「代码」
function sortArray(nums: number[]): number[] {
let len = nums.length;
if (len <= 1) {
return nums;
}
//nums遍历成最大堆
//从有子元素的节点开始
//根据上述例子,从(1) --> (5) 这个节点开始生成最大堆,1的下标为1
// --> (7)
let i = ~~((len >> 1) - 1);
while (i >= 0) {
maxHeapify(nums, i, len);
i--;
}
//从最后一个元素开始
for (let i = len - 1; i > 0; i--) {
//交换首尾交换
[nums[0], nums[i]] = [nums[i], nums[0]];
//重新生成最大堆
maxHeapify(nums, 0, i);
}
function maxHeapify(arr: number[], start: number, end: number) {
//父节点
let fatherIndex = start;
// 左子节点
let leftSonIndex = fatherIndex * 2 + 1;
if (leftSonIndex >= end) {
//越界
return;
}
let sonIndex: number = leftSonIndex;
//右子节点
if (leftSonIndex + 1 < end && arr[leftSonIndex + 1] > arr[leftSonIndex]) {
//从右子节点开始遍历
sonIndex = leftSonIndex + 1;
}
//如果父节点小于子节点,交换
if (arr[fatherIndex] < arr[sonIndex]) {
[arr[fatherIndex], arr[sonIndex]] = [arr[sonIndex], arr[fatherIndex]];
//开始从子节点开始再次生成最大堆
maxHeapify(arr, sonIndex, end);
}
}
return nums;
}
时间复杂度:O(nlogn) 空间复杂度:O(1) 不稳定