美文网首页Java 杂谈
排序算法之堆排序

排序算法之堆排序

作者: alonwang | 来源:发表于2019-06-13 07:43 被阅读3次

堆排序基于完全二叉树

若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

将一维数组看做一颗完全二叉树 如数组[9,15,7,3,25,13,8,21],可以观察出以下规律

arr[i]为arr[2*i+1],arr[2*i+2]的父节点

image.png

堆的定义

最大堆父节点大于等于子节点,体现在数组中就是 arr[i] >= arr[2*i+1]&&arr[i] >= arr[2*i+2]

最小堆 父节点小于等于子节点,体现在数组中就是arr[i <= arr[2*i+1]&&arr[i] <= arr[2*i+2]

上例对应的最大堆为

image.png

堆排序是如何实现的?

假设为正序排列,将数组看做完全二叉树

  1. 构建为最大堆,此时首节点arr[0]就是最大的值
  2. 依次将首节点与无序最大堆的中最后一个节点交换,然后调整堆使其满足最大堆要求

这样就构建了一个从尾节点到首节点依次减小的堆,正好满足数组的正序排列要求

如何构建最大堆?

  1. 从最后一个非叶节点(arr[n/2-1]])开始,提升其子节点(可能为非叶节点)中的最大值到当前节点,并将当前节点值下放的可能的最底层.
  2. 对前面的非叶节点重复 1

这样就构造出了最大堆

在首节点交换后,如何调整堆?

当首节点交换后,最后一个节点已经有序,可以忽略了.此时堆中只有首节点是不符合最大堆的定义的.对首节点应用构建最大堆的步骤即可,注意要忽略掉已经有序的尾节点

算法实现

/**
 * 将一维数组看做一颗二叉树 父节点和子节点的关系为 Nk~=N2k+1,N2k+2
 * 1. 构建堆
 * 2. 调整堆
 */
public class SimpleHeapSort {
    public static void main(String[] args) {
        int[] arr = new int[]{6545,1,4456, 5, 4, 65, 63,5445};
        heapSort(arr);
        for (int n : arr) {
            System.out.println(n);
        }
    }

    private static void heapSort(int[] arr) {
        //从最后一个节点开始扫描,构建最大堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjustHeap(arr, i, arr.length);
        }
        //依次将堆顶最大值移到当前的末尾,构建有序数组
        for (int j = arr.length - 1; j > 0; j--) {
            swap(arr, 0, j);
            adjustHeap(arr, 0, j);
        }
    }

    private static void adjustHeap(int[] arr, int i, int length) {
        int temp = arr[i];
        int k = 2 * i + 1;
        int j = i;
        while (k < length) {
            if (k+1<length&&arr[k] < arr[k + 1]) {
                k = k + 1;
            }
            if (temp < arr[k]) {
                arr[j] = arr[k];
                j = k;
            }else{
                break;
            }
            k = k * 2 + 1;
        }
        arr[j] = temp;

    }

    private static void swap(int[] arrays, int i, int j) {
        int temp = arrays[i];
        arrays[i] = arrays[j];
        arrays[j] = temp;
    }
}

重建堆的时间复杂度为O(NlogN)

树的高度为k=lgN+1,从根到叶的筛选,元素比较次数至多2(k-1)次,交换记录至多k次,排序过程中的筛选次数不超过下式:

2(lg(N-1)+lg(N-2)+lg(N-3)+lg(2))<2n()lgN

建堆的时间复杂度为O(N):


链接:

https://www.nowcoder.com/questionTerminal/385157a6b64540c3b233bd12f8a83ee7

来源:牛客网如果从底部最后的父节点开始建堆,那么我们可以大概算一下: 假如有N个节点,那么高度为H=logN,最后一层每个父节点最多只需要下调1次,倒数第二层最多只需要下调2次,顶点最多需要下调H次,而最后一层父节点共有2(H-1)个,倒数第二层公有2(H-2),顶点只有1(2^0)个,所以总共的时间复杂度为s = 1 * 2^(H-1) + 2 * 2^(H-2) + ... + (H-1) * 2^1 + H * 2^0 将H代入后s= 2N - 2 - log2(N),近似的时间复杂度就是O(N)。

相关文章

  • 堆排序

    转载:图解排序算法(三)之堆排序 预备知识 堆排序 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选...

  • iOS算法总结-堆排序

    iOS算法总结-堆排序 iOS算法总结-堆排序

  • 3.11 堆的概念及堆排序思路

    Chapter3: 更好的查找与排序算法 11. 堆的概念及堆排序 [1] 图解排序算法(三)之堆排序 讲得很好,...

  • 3.2-选择排序-堆排序

    参考链接 选择排序:堆排序(Heap Sort) 白话经典算法系列之七 堆与堆排序 堆排序与快速排序,归并排序一样...

  • 2018-06-30

    排序算法之堆排序 堆排序是利用堆的数据结构而设计的一种排序算法,堆排序是一种选择排序。可以利用数组的特点快速定位制...

  • 排序算法-堆排序

    参考: Java排序算法(五):堆排序 【算法与数据结构】图说堆排序 【数据结构】排序算法:希尔、归并、快速、堆排...

  • 数据结构与算法

    常见排序算法 堆排序 算法大全 算法大汇总

  • 数据结构

    Q:堆排序 A:1 堆排序算法(图解详细流程)2 堆排序 Q:排序算法时间复杂度与稳定性 选择排序为什么不稳定:举...

  • web开发需要知道的几个算法

    算法分类 快速排序算法 深度优先算法 广度优先算法 堆排序算法 归并排序算法

  • 排序算法之5:堆排序 HeapSort

    研究了半天,一步一步试验DEBU,才明白堆排序的原理,整理记录一下;相关参考:排序算法之堆排序(Heapsort)...

网友评论

    本文标题:排序算法之堆排序

    本文链接:https://www.haomeiwen.com/subject/xigdfctx.html