个人知识总结:堆排序

1 堆的概念

堆排序中的"堆"是指二叉堆,是一棵被完全填满的二叉树(完全填满不是指满二叉树),也就是完全二叉树,深度为logN。

  • 完全二叉树

  • 图示

    以层级遍历如果出现空节点,后面节点都为空就是一棵完全二叉树。    

最大堆,最小堆

  • 父节点的值大于左右节点值的堆称为最大堆,也就是说根节点的值是树中的最大值
  • 父节点的值小于左右节点值的堆称为最小堆,也就是说根节点的值是树中的最小值图示

图示

                                   最大堆                                                                           最小堆

堆排序是通过最大堆或是最小堆进行排序的

2 堆排序基本思路

完全二叉树可以由一个数组去实现

因此一个堆可以由一个数组表示,并且在数组表示的形式有一定的规律:

 约定  父节点在数组中的索引用 k 表示      左节点的索引为 m      右节点的索引为  n          

  1. 左节点的索引为  m= 2*k+1
  2. 右节点的索引为  n = 2*k+2
  3. 父节点的索引为  k=  (m -1)/2   或者  (n-1)/2 

升序的实现

由上述最大堆定义可知:根节点保存树中数据的最大值 ,所以可以将根节点与最后一个节点的值互换,最后一个节点保存了最大值,然后使 除最后一节点的堆再次形成最大堆,根节点可以得到第二大的值,然后与新的最大堆的最后一个数据互换,以此类推得到一个升序的有序队列。

 具体过程

①将数据存入数组

②将数组数据初始化为最大堆结构

③将根节点数据与最后一节点数据交换

④调整堆使剩下的再次形成最大堆

。。。。。。直到所需调整的堆的大小为1,即无需再排序 

堆排序减少了大量重复的排序,没有受到影响的子树不会去深度访问

public class HeapSortTest {
    public static void sort(int []arr){
        //构建最大堆(初始化)从最后一个非叶子节点开始
        for(int i=(arr.length-1)/2;i>=0;i--){
            partAdjust(arr,i,arr.length);
        }
        //将最大值交换到末尾 并调整剩下成为最大堆
          for(int j=arr.length-1;j>=0;j--){
              swap(arr,0,j);
              partAdjust(arr,0,j);
          }

    }
    //局部调整 使父节点的值比左右节点大
    public static void partAdjust(int []arr,int i,int length){
        int temp=arr[i];
        //每次都跳到左节点
        for( int k=2 * i + 1;k<length;k=2*k+1){
            //选出左右节点较大的值    k+1<length原因是如果不存在右节点k+1会越界
            if (k+1<length&&arr[k] <arr[ k+1]) {
                k++;
            }
            //如果子节点中的值比父节点大 将值赋给父节点 并且调整节点指向下一个左节点
            if(temp<arr[k]){
                arr[i]=arr[k];
                i=k;
            }
            //在最大堆的条件下 如果父节点值比子节点都大,就不需要再往下比较
            else break;
           
        }
        //最终temp存放的值的位置
        arr[i]=temp;

    }
    public static void swap(int[]arr,int a,int b){
        int temp =arr[a];
            arr[a]=arr[b];
            arr[b]=temp;
    }
//main函数
    public static void main(String[] args) {
        int []arr1= {10,1,7,8,4,7,4,8,3,5,9};
        int arr[]=new int[100000];
        int j=0;
        for(int i=arr.length-1;i>=0;i--){
            arr[i]=j;
            j++;
        }
        sort(arr1);
        System.out.println(Arrays.toString(arr1));
        System.out.println("----------");
        System.out.println(new Date().getTime());
        sort(arr);
        System.out.println(new Date().getTime());
        System.out.println(Arrays.toString(arr));
    }
}


//output
[1, 3, 4, 4, 5, 7, 7, 8, 8, 9, 10]
----------
1556102486756
1556102486786
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22。。。。。。]

在构建最大堆,是从最后一个非叶子节点开始   所以是从         (最后一个元素的索引   -   1 ) /  2  开始

 for(int i=(arr.length-1)/2;i>=0;i--){
            partAdjust(arr,i,arr.length);
        }

猜你喜欢

转载自blog.csdn.net/qq_41800087/article/details/89494447