# heapsort

heapsort 堆排序

1.基本描述

​ 堆排序 heap sort 指利用堆这种数据结构所设计的一种排序算法。

​ 要求完全二叉树

​ 这边我只写最大堆

​ 堆排序归分在选择排序

​ 稳定性 不稳定

​ 时间复杂度
$$
O(nlog_2n)
$$
​ 空间复杂度
$$
O(1)
$$

2. 最大堆进行升序排序思想:

  1. 初始化堆 ,将数列 [0,n-1] 构造成最大堆

  2. 交换数据, 将array[0]和array[n-1]交换, 然后将 array[0…n-2] 重新调整为最大堆,以此类推

  3. 这里有一点需要注意,无论是初始化堆,还是交换数据,都调用maxHeapDown,他的参数是 array[] , int start ,int end. 这里 三个参数一个都不能少,start 我觉得这里不好,应该形容为node节点。end可以理解,在交换数据时,需要调整的堆大小是不断变小。 start 这个参数比较微妙。我的理解是调整这个节点在其子节点中的位置,并在原来的位置替换合理的节点(注 不是他最后的位置的节点)。而由于在交换数据时,本身堆除了跟节点,就是符合最大堆特性。就像初始化堆一样,需要从底往上初始化。(这边的参数也是参考 如果天空不死)

    由于已经符合,所以直接调整节点 array[0] 即可。

    所以初始化堆也好,交换数据也好,本质上就是在筛选调整节点位置。这只是我的理解。,,,,堆排序初始化需要从下往上才能初始化最大堆。而交换数据相当于初始化堆的最后一步再现。

    注意要点

    •   for (i=n/2-1;i>=0;i--) //初始化堆  是--。从坐标最大的非叶子节点开始调节
                  maxheapDown(array,i,n-1); // 注意参数,遍历所有非叶节点
      

      开始的循环是 i=n/2-1 并且是i-- 循环.

      这个 i 的取值 要区别 联系到 最大堆 的概念

      (01) 索引为i的左孩子的索引是 (2i+1);
      (02) 索引为i的左孩子的索引是 (2
      i+2);
      (03) 索引为i的父结点的索引是 floor((i-1)/2);

      这个最后的非叶子节点的计算。最后一个叶子节点为 n-1 , 坐标(n-1-1)/2 =n/2-1

      ​ 传入的参数是 i,n-1

    •   for (i=n-1;i>0;i--){  //交换数据
                  int tmp=array[0];
                  array[0]=array[i];
                  array[i]=tmp;
                  maxheapDown(array,0,i-1); // 只有根节点不符合最大堆的要求
              }
          }
      

      for 循环从 n-1 开始。>0 是因为n-1 个数位置正确,剩下一个也正确。 i–

      传入参数 0,i-1

3. 代码剖析

​ heapSortAsc

    private static void heapSortAsc(int[] array) {
        int i;
        int n=array.length;
        for (i=n/2-1;i>=0;i--) //初始化堆  是--。从坐标最大的非叶子节点开始调节
            maxheapDown(array,i,n-1); // 注意参数,遍历所有非叶节点

        for (i=n-1;i>0;i--){  //交换数据
            int tmp=array[0];
            array[0]=array[i];
            array[i]=tmp;
            maxheapDown(array,0,i-1); // 只有根节点不符合最大堆的要求
        }
    }

​ maxheapDown

private static void  maxheapDown(int[] array,int start,int end){    //start 理解为 node 节点更好。 或者干脆改过来吧
        int c=start;                                                    //调整某个节点在适当分支
        int left=2*c+1;                                                 //这样0,i-1 参数更加容易理解
        int tmp=array[c];
        for (;left<=end;c=left,left=2*left+1){
            if (left<end&&array[left]<array[left+1])   //left<end  必须放在前面
            {
                left++; //选择大的往上面替换。
            }
            if(tmp>=array[left])
                break;
            else {
                array[c]=array[left];
                array[left]=tmp; // 疑问二,tmp一直不变
            }
        }
    }

原文地址:https://www.cnblogs.com/EsMussSeinHui/p/11156235.html