• 排序算法之堆排序


    堆排序

    时间复杂度 O(nlogN)

    大顶堆:

    大顶堆是一个完全二叉树,其左右子节点小于或等于根节点,左右子节点之间并无关系

    由此可知大顶堆的根节点为最大值

    例:

    int[] a = {3,4,2,7,1,6,5,0};
    

    其构建的初始堆为

    3 4 2 7 1 6 5 0
    

    调整为大顶堆:

    7 4 6 3 1 2 5 0 
    

    了解了大顶堆后,再来看堆排序的步骤:

    • 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
    • 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
    • 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

    在上图中,就是将0与7调换,然后a[7] = 7;a[0] = 0;很显然此时不满足大顶堆性质,于是对a[0]~a[6]进行堆调整,调整后6为根节点,再将a[6]与a[0]交换,此时a[6]=6,a[7] = 7;可见是有序的,重复该步骤即可。

    详细实现见源码

    java实现:

    public class HeapSort {
        public static void main(String[] args){
            int[] a = {3,4,2,7,1,6,5,0};
            heapSort(a);
        }
    
        /**
         * 堆大小
         */
        private  static int  len;
    
        /**
         * 堆排序
         * @param arr
         * @return
         */
        public static int[] heapSort(int[] arr) {
            // 构建大顶堆
            buildMaxHeap(arr);
    
            for (int i = arr.length - 1; i > 0; i--) {
                // 首尾元素交换,这样arr[length-1]就是最大值
                swap(arr, 0, i);
                // 减少下次堆调整的大小,忽略上一条语句交换得到的最大值,此时数组从后面逐渐变成有序的
                len--;
                // 因为根节点变动,所以需要重新调整
                heapify(arr, 0);
            }
            return arr;
        }
    
        /**
         * 给定一个数组构造大顶堆
         * @param arr
         */
        private static void buildMaxHeap(int[] arr) {   
            System.out.println("buildMaxHeap start");
            len = arr.length;
            for (int i = len/2; i >= 0; i--) {
                heapify(arr, i);
            }
            System.out.println("buildMaxHeap end");
        }
    
        /**
         * 堆调整 
         * @param arr 待调整的元素
         * @param i 调整第i位节点及其左右节点,根节点 i = 0
         */
        private static void heapify(int[] arr,int i) {     // 堆调整
            print(arr);
            int left = 2 * i + 1, // // i节点的左子结点
                    right = 2 * i + 2, // i节点的右子结点
                    largest = i; // 记录这三个节点最大的那个
            // 如果第i节点的左节点存在且左节点比它大,记录largest
            if (left < len && arr[left] > arr[largest]) {
                largest = left;
            }
            // 如果第i节点的右节点存在且比arr[largest]大,记录largest
            // 注意largest既可能为根节点i,也可能为i的左节点,总之这三个节点要保证堆的性质,找到这三个节点最大的那个置于根节点,记录largest
            if (right < len && arr[right] > arr[largest]) {
                largest = right;
            }
    
    
            if (largest != i) {
                // 如果largest != i,则说明节点i小于其左右节点,因此需要交换位置,保证根节点最大
                swap(arr, i, largest);
                // 因为此时堆发生了变动,所以需要重建交换的子节点,保证该节点保证堆性质
                heapify(arr, largest);
            }
        }
    
        /**
         * 数组交换
         * @param arr
         * @param i 数组下标
         * @param j 数组下标
         */
        private static void swap(int[] arr, int i, int j) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    
       
        /**
         * 数组输出
         * @param array
         */
        private static void print(int[] array){
    
            for(int a : array){
                System.out.print(a+" ");
    
            }
            System.out.print("
    ");
    
        }
    }
    

    输出:

    buildMaxHeap start
    3 4 2 7 1 6 5 0 
    3 4 2 7 1 6 5 0 
    3 4 2 7 1 6 5 0 
    3 4 6 7 1 2 5 0 
    3 4 6 7 1 2 5 0 
    3 7 6 4 1 2 5 0 
    3 7 6 4 1 2 5 0 
    7 3 6 4 1 2 5 0 
    7 4 6 3 1 2 5 0 
    buildMaxHeap end
    0 4 6 3 1 2 5 7 
    6 4 0 3 1 2 5 7 
    6 4 5 3 1 2 0 7 
    0 4 5 3 1 2 6 7 
    5 4 0 3 1 2 6 7 
    5 4 2 3 1 0 6 7 
    0 4 2 3 1 5 6 7 
    4 0 2 3 1 5 6 7 
    4 3 2 0 1 5 6 7 
    1 3 2 0 4 5 6 7 
    3 1 2 0 4 5 6 7 
    0 1 2 3 4 5 6 7 
    2 1 0 3 4 5 6 7 
    0 1 2 3 4 5 6 7 
    1 0 2 3 4 5 6 7 
    0 1 2 3 4 5 6 7 
    
    Process finished with exit code 0
  • 相关阅读:
    javascript 构造函数,工厂模式,稳妥构造函数浅析
    javascript基本概念
    struts2 类型转换
    struts action
    struts2 配置(部分)
    struts2基本构成
    charapter 1
    java 内部类
    mysql zip 解压安装 (win10)
    python之random模块
  • 原文地址:https://www.cnblogs.com/lifan1998/p/10444557.html
Copyright © 2020-2023  润新知