Sorting 排序算法: Heap Sort 堆排序

news/2024/5/19 2:32:11 标签: 排序算法, java, 堆排序

Sorting 排序算法: Heap Sort 堆排序

文章目錄

  • Sorting 排序算法: Heap Sort 堆排序
    • 簡介
    • 參考
  • 正文
    • 算法思想原理
      • 输入
      • 算法思想
      • 算法流程
      • 算法复杂度分析
    • Java 实现
  • 結語

簡介

今天来介绍一个相对于其他比较排序算法比较特别的一个排序算法-堆排序(HeapSort),堆排序顾名思义借助了堆(Heap)的数据结构性质,并借由建堆(build-heap)的复杂度 O(n)和中间抽取最大值需要恢复堆的性质(maxHeapify)的复杂度 O(logn),组合操作使得堆排序的时间复杂度能够渐进趋近于比较排序的极限 O(nlogn)

參考

正文

算法思想原理

输入

java">/* 传入参数 */
int[] A // 原数组(可以是任何类型的数据,这边使用 int 类型为示例)

/* 限制 */
int n // 数组长度

算法思想

堆排序的核心思想是使用最大堆(升序排序时)的性质,每次将最大值也就是根节点取出,以最后一个元素替代并恢复最大堆的性质,而所有的数抽出的顺序正好是由大到小,以此来完成排序。

  • 图解:(绿色为已排序好的部分

算法流程

伪代码

Heap-Sort(A)
    Build-Max-Heap(A)
    for i = A.length - 1 to 0
        Swap A[0] and A[i]
        MaxHeapify(A) while heap size = i

算法复杂度分析

先说结论:

  1. 时间复杂度:O(nlogn)
  2. 空间复杂度:1 (额外空间复杂度,不考虑原数组的空间)
  3. 原址排序
  4. 不稳定的
  • 时间复杂度:O(nlogn)

一开始进行建堆的复杂度为 O(n),后面需要取 n 次最大值,每次恢复堆性质的复杂度为 O(logn),故算法时间复杂度为 O(n) + n * O(logn) = O(nlogn)

  • 空间复杂度:1、原址排序

由于建堆、抽取最大值并恢复堆性质等操作都是在原数组进行,没有使用额外空间,故算法是空间复杂度为 1 且为原址排序

  • 不稳定的

由于恢复堆性质的过程中出现相同值依旧会向下交换,会打乱相同值的相对顺序,所以堆排序不稳定的

Java 实现

java">package sorting;

/**
 * 堆排序
 */
public class HeapSort {

    /**
     * 主方法
     *
     * @param A
     */
    public static void sort(int[] A) {
        // 建最大堆
        for (int i = parent(A.length - 1); i >= 0; i--) {
            maxHeapify(A, A.length, i);
        }
        for (int i = 0; i < A.length; i++) {
            // 抽取最大值并恢复堆
            swap(A, 0, A.length - i - 1);
            maxHeapify(A, A.length - i - 1, 0);
        }
    }

    /**
     * 将指定下标的数下降到适当的位置
     *
     * @param A
     * @param len
     * @param pos
     */
    private static void maxHeapify(int[] A, int len, int pos) {
        if (left(pos) >= len) return;
        int max = pos;
        if (A[max] <= A[left(pos)]) max = left(pos);
        if (right(pos) < len && A[max] <= A[right(pos)]) max = right(pos);
        if (max != pos) {
            swap(A, pos, max);
            maxHeapify(A, len, max);
        }
    }

    /**
     * 交换
     *
     * @param A
     * @param i
     * @param j
     */
    private static void swap(int[] A, int i, int j) {
        int tmp = A[i];
        A[i] = A[j];
        A[j] = tmp;
    }

    /**
     * 父节点下标
     *
     * @param pos
     * @return
     */
    private static int parent(int pos) {
        return (pos - 1) / 2;
    }

    /**
     * 左子节点下标
     *
     * @param pos
     * @return
     */
    private static int left(int pos) {
        return pos * 2 + 1;
    }

    /**
     * 右子节点下标
     *
     * @param pos
     * @return
     */
    private static int right(int pos) {
        return pos * 2 + 2;
    }
}
java">public class HeapSortTest {
    @Test
    public void test_1() {
        int[] A = new int[]{1,3,5,7,9,2,4,6,8,0};
        int[] ans = new int[]{0,1,2,3,4,5,6,7,8,9};
        System.out.println("origin: " + Arrays.toString(A));
        HeapSort.sort(A);
        System.out.println("sorted: " + Arrays.toString(A));
        assertArrayEquals(ans, A);
    }
}
  • 输出
origin: [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
sorted: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

結語

虽然堆排序的渐进时间复杂度与快速排序相同,不过在实际应用上却较少使用,因为建堆和恢复堆性质算法所隐藏的系数较大。最大/最小堆(max/min-heap)数据结构的另一个较常用的用途是最大/最小优先队列(Priority Queue),透过维持最大/最小堆的性质可以在 O(1) 的时间复杂度找到队列中最大/最小的值,并仅仅使用 O(logn) 的代价恢复堆的性质,有关优先队列的内容会放在堆数据结构的时候再详细介绍。


http://www.niftyadmin.cn/n/735522.html

相关文章

三维重建基础与极几何

蓝色 紫色 红色 写在前面&#xff1a;本篇Blog仅作为学习笔记&#xff0c;学习内容来自于北邮CV-XUEBA团队的三维重建(精简版&#xff0c;鲁鹏)课程。 三维重建基础 三维重建总结 主要涉及以下几个关键问题&#xff1a; 解决第三个关键问题(对应关系)的方法 极几何 极几何…

Windows Developer Day - Windows AI Platform

本次 Windows Developer Day&#xff0c;最值得期待的莫过于 Windows AI Platform 了&#xff0c;可以说是千呼万唤始出来。观看直播的开发者们&#xff0c;留言最多的也是 Windows AI Platform。 下面结合微软提供的展示过程&#xff0c;文档和 Git Sample 来详细分析一下。 基…

相机模型和标定

蓝色 紫色 红色 写在前面&#xff1a;本篇Blog仅作为学习笔记&#xff0c;学习内容来自于北邮CV-XUEBA团队的三维重建(精简版&#xff0c;鲁鹏)课程。 摄像机几何 内参&#xff1a;与相机 自身特性 相关的参数 (eg. 焦距、像素大小等) 外参&#xff1a;在世界坐标系中的参数…

Kotlin在处理GET和POST请求的数据问题

1.网络请求获取到的数据流处理 java写法 1 BufferedReader br new BufferedReader(new InputStreamReader(in, "utf-8")); 2 3 String line; 4 StringBuffer sb new StringBuffer(); 5 while ((line br.readLi…

ADT: LinkedList 链表

ADT: LinkedList 链表 文章目录ADT: LinkedList 链表简介参考正文链表结构抽象接口实现要素单向链表双向链表Java 实现链表接口单向链表双向链表结语简介 几乎所有高级语言都提供数组(Array)作为基础数据结构&#xff0c;从存储的角度来看数组就是一个连续的存储单元&#xff…

ADT: Binary-Search-Tree 二叉搜索树

ADT: Binary-Search-Tree 二叉搜索树 文章目录ADT: Binary-Search-Tree 二叉搜索树简介参考正文二叉搜索树(BST)结构抽象接口实现要素Java 实现interface Tree 树接口interface BinarySearchTree 二叉搜索树接口class BinarySearchTreeImpl 二叉搜索树实现class BinarySearchTr…

双目立体视觉系统 运动恢复结构问题 (SfM)

蓝色 紫色 红色 写在前面&#xff1a;本篇Blog仅作为学习笔记&#xff0c;学习内容来自于北邮CV-XUEBA团队的三维重建(精简版&#xff0c;鲁鹏)课程。 两种典型的基于图像的三维重建方法 1. 基于平行视图的三维重构方法 利用 两个视点 来观察物体&#xff0c;采用和人类视觉…

恢复阿里云RDS的数据备份文件到本地数据库

前言 写之前先说说这篇文章的来由&#xff0c;公司客户准备发布一些活动&#xff0c;采用在线报名的方式&#xff0c;由于前期表结构设计的不合理&#xff0c;后期优化对表结构的改动&#xff0c;导致部分活动用户报名数据丢失&#xff0c;于是想恢复mysql被误删的数据&#xf…