栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

堆排序算法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

堆排序算法

堆排序(Heap Sort),是由罗伯特·弗洛伊德(Robert W.Floyd)和威廉姆斯(J.Williams)于1964年提出的一种基于堆结构的排序方法。直接选择排序在 n n n 个元素中,选出关键字最小(最大)的记录需要 O ( n ) O(n) O(n) 的时间。而利用堆这种数据结构所设计的一种排序算法,小根堆(大根堆)选出关键字最小(最大)的记录只需要 O ( l o g n ) O(logn) O(logn) 的时间。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点

在堆排序过程中,存在大跨度的数据移动,是一种不稳定的排序算法

堆分为两种

  • 大根堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列
  • 小根堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列

算法步骤

  1. 由存储于数组中的初始序列,建成一个大根堆(小根堆)
  2. 将堆顶的最大(或最小)元素与序列中最后一个记录交换,最大(或最小)元素放在数组末尾的有序段中
  3. 将序列中除末尾的有序段之外的剩余记录重新调整为大根堆(小根堆)
  4. 反复执行步骤2、3,共 n − 1 n-1 n−1次,若初始建立的是大根堆,则得到一个递增序列;若初始建立的是小根堆,则得到一个递减的序列

测试用例: 使用堆排序算法将数组 { 36,80,45,66,22,9,36,16 } 进行升序排序










代码实现

    
    public int[] siftDown(int[] nums, int position, int size){
        int child;
        int temp = nums[position];  // 将该非叶子节点值保存
        // 循环遍历当前非叶子节点的子节点,实质上是遍历该非叶子节点的所有属于非叶子节点的子节点
        for ( ; position * 2 + 1 < size; position = child){
            child = position * 2 + 1;   // 获取当前非叶子节点的左孩子节点
            if (child != size - 1 && nums[child + 1] > nums[child]) // 如果右孩子节点的值 > 左孩子节点的值,选取大者
                child++;    // 定位较大孩子节点
            if (nums[child] > temp) nums[position] = nums[child];   // 如果较大的孩子节点比父节点大,则孩子节点替换父节点的位置
            else break; // 如果父节点已是子节点中最大,直接退出循环
        }
        nums[position] = temp;  // 如果修改了父节点的值,回填相应的子节点
        return nums;
    }

    
    public int[] heapSort(int[] nums, int size){
        int i;
        int temp;
        // 初始建堆,从最后一个非叶子节点开始遍历
        for (i = size/2 - 1; i >= 0; i--)
            nums = siftDown(nums, i, size);

        for (i = size-1; i >= 0; i--){    // 一共需要遍历size-1次(删除堆顶元素之后反复调整堆)
            temp = nums[0];         // 将堆顶元素与子序列中最后一个元素交换
            nums[0] = nums[i];
            nums[i] = temp;
            nums = siftDown(nums, 0, i);    // 将nums[0...i]重新调整为大根堆
        }
        return nums;
    }

时间复杂度
堆排序的时间主要由建堆和反复调整两部分时间开销构成。由 n n n 个元素建成的堆,其深度为 h = ⌊ l o g n ⌋ + 1 h=lfloor logn rfloor + 1 h=⌊logn⌋+1,根节点向下调整时能移动的最大层数为 h − 1 h-1 h−1,元素的最大比较次数为 2 ( h − 1 ) 2(h-1) 2(h−1) 次;第 i i i 层最多有 2 i − 1 2^{i-1} 2i−1 个节点,对于,对于第 i i i 层的节点,向下调整堆进行性的元素比较的次数最多为 2 ( h − i ) 2(h-i) 2(h−i),因此,建堆的元素比较的次数最多为 T ( n ) T(n) T(n),它满足以下表达式

T ( n ) T(n) T(n) = ∑ i = 1 i = h − 1 2 n − i ∗ 2 ( h − i ) sum_{i=1}^{i=h-1} 2^{n-i} * 2(h-i) i=1∑i=h−1​2n−i∗2(h−i) <= ∑ i = 1 i = h − 1 2 n ∗ 2 ( h − i ) sum_{i=1}^{i=h-1} 2^n * 2(h-i) i=1∑i=h−1​2n∗2(h−i) <= 4 n 4n 4n

建堆的时间复杂度为 O ( n ) O(n) O(n)。反复调整堆的操作体现在 heapSort 的第2个for循环中,共计调用siftDown()函数 n − 1 n-1 n−1 次,该循环的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。因此,堆排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

空间复杂度
在堆排序的过程中,只需要一个元素大小的辅助空间用于存放堆顶的最大元素,因此空间复杂度为 O ( 1 ) O(1) O(1)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1028127.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号