堆排序

108 阅读1分钟

思路

最大堆:根结点为最大值

最大堆的第一个跟节点(最大值)和最后一个元素(最小值)交换位置

「推导」

[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) 不稳定