zoukankan      html  css  js  c++  java
  • 堆排序

    本文参考 https://www.cnblogs.com/chengxiao/p/6129630.html 感谢大佬精心绘图!

    主要思想:

    ​ 1、将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆

    ​ 2、将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端,同时接着重新调整堆的结构

    ​ 3、继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序

    每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆

    image-20200717131533231

    该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

    大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

    小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

    二叉树相关知识:

    第一个非叶子节点 m = arr.length / 2 -1

    第一个非叶子节点的左孩子节点 n = 2 * m + 1

    package com.jason.sort;
    
    /**
     * @Authot CodeDuck
     * @Date 2020/7/17-13:20
     */
    public class HeapSort {
    
        public static void main(String[] args) {
            int[] arr = {11, 7, 18, 3, 5, 4, 10, 9};
            sort(arr);
            for (int a : arr) {
                System.out.println(a);
                ;
            }
        }
    
        /**
         * @Description: 堆排序
         * @Param: arr数组
         * @return: void
         */
        public static void sort(int[] arr) {
    
            // 1、构建大顶堆
            for (int i = arr.length / 2 - 1; i >= 0; i--) {
                // 从第一个非叶子结点从下至上,从右至左调整结构
                adjustHeap(arr, i, arr.length);
            }
    
            // 2、调整堆结构+交换堆顶元素与末尾元素
            for (int i = arr.length - 1; i > 0; i--) {
                swap(arr, 0, i);
                adjustHeap(arr, 0, i);
            }
        }
    
        /**
         * @Description: 调整为大顶堆
         * @Param: arr数组
         * @Param: i 所要调整的节点
         * @Param: length:数组长度
         * @return: void
         */
        public static void adjustHeap(int[] arr, int i, int length) {
    
            int temp = arr[i]; // 获取当前交换的节点val
            for (int k = 2 * i + 1; k < length; k = 2 * k + 1) { // 获取当前节点的左孩子节点
    
                // 若左孩子节点小于右孩子节点,k指向右孩子节点
                if (k + 1 < length && arr[k] < arr[k + 1]) { 
                    k++;
                }
    
                if (arr[k] > temp) {  // 如果当前孩子节点大于父节点
                    arr[i] = arr[k];  // 将父节点的值 赋值于 被交换孩子节点
                    i = k;            // 将 i 指向被交换孩子节点
                } else {
                    break;
                }
            }
            arr[i] = temp; // 将temp赋值于被交换孩子节点
        }
    
    
        /**
         * @Description: 交换元素
         * @Param: arr 元素组
         * @Param: i,j数组下标
         * @return: void
         */
        public static void swap(int[] arr, int i, int j) {
    
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    

    堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。

    建立N个元素的二叉堆花费时间:O(n)

    在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为O(NlogN)

    因此,堆排序在面对最好和最坏的情况下都是稳定的

  • 相关阅读:
    linq to entity group by 时间
    Entity Framework Core for Console
    EF Core 多个DbContext迁移命令
    .net for TCP服务端 && 客户端
    创建Windows Service
    EF Code First 快速创建
    在Docker中创建Mongo容器的后续设置
    Docker入门
    Python之collections.defaultdict
    Hough transform(霍夫变换)
  • 原文地址:https://www.cnblogs.com/code-duck/p/13329727.html
Copyright © 2011-2022 走看看