马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
目次
一、堆排序的基本原理
二、堆排序的实现步骤
三、堆排序的时间复杂度和空间复杂度
四、堆排序的工作流程
五、堆排序的优缺点
六、堆排序的应用场景
堆排序(Heap Sort)是一种基于堆数据结构的排序算法。堆是一种特别的完全二叉树,堆排序使用堆的性质通过一系列操纵将数组元素按升序或降序排列。堆排序的时间复杂度为 O(n log n),是一种不稳固的排序算法,且其空间复杂度为 O(1),因此在某些场景下非常有用。
一、堆排序的基本原理
堆排序的核心是堆(Heap)这一数据结构,堆有两种情势:
(1)最大堆(Max-Heap):每个节点的值大于或等于其子节点的值,根节点的值是整个堆的最大值。
(2)最小堆(Min-Heap):每个节点的值小于或等于其子节点的值,根节点的值是整个堆的最小值。
堆排序一般使用最大堆来排序数组。堆排序的过程可以分为两个重要步骤:
(1)构建最大堆:将无序数组转换成最大堆。
(2)排序过程:反复将堆顶元素(最大值)与当前堆的末了一个元素互换,然后调整堆,直到堆中只剩下一个元素。
二、堆排序的实现步骤
(1)构建最大堆:起首将输入的无序数组构造成最大堆。此时数组中的最大元素位于根节点。
(2)互换堆顶元素与末了一个元素:将堆顶元素与堆的末了一个元素互换,并减小堆的有用元素数目。
(3)堆化:将根节点与其子节点进行比较,调整堆的结构,使其重新满足最大堆的性质。
(4)重复步骤2和3:直到堆的有用元素数目为1,整个数组已经排序完成。
三、堆排序的时间复杂度和空间复杂度
(1)时间复杂度:构建最大堆的时间复杂度是 O(n),而每次堆化的时间复杂度是 O(log n),因此总的时间复杂度为 O(n log n)。
(2)空间复杂度:堆排序是原地排序算法,因此其空间复杂度为 O(1)。四、堆排序的Java实现
下面是堆排序的Java实当代码:
- public class HeapSort {
- // 堆化过程,保证以i为根的子树满足堆的性质
- private static void heapify(int[] arr, int n, int i) {
- int largest = i; // 初始化最大值为根节点
- int left = 2 * i + 1; // 左子节点的位置
- int right = 2 * i + 2; // 右子节点的位置
- // 如果左子节点大于根节点
- if (left < n && arr[left] > arr[largest]) {
- largest = left;
- }
- // 如果右子节点大于当前最大值
- if (right < n && arr[right] > arr[largest]) {
- largest = right;
- }
- // 如果最大值不是根节点,交换并继续堆化
- if (largest != i) {
- int temp = arr[i];
- arr[i] = arr[largest];
- arr[largest] = temp;
- // 递归堆化受影响的子树
- heapify(arr, n, largest);
- }
- }
- // 堆排序主函数
- public static void heapSort(int[] arr) {
- int n = arr.length;
- // 构建最大堆
- for (int i = n / 2 - 1; i >= 0; i--) {
- heapify(arr, n, i);
- }
- // 逐步将堆顶元素与最后一个元素交换,并调整堆
- for (int i = n - 1; i >= 1; i--) {
- // 将堆顶元素与当前未排序部分的最后一个元素交换
- int temp = arr[0];
- arr[0] = arr[i];
- arr[i] = temp;
- // 调整堆
- heapify(arr, i, 0);
- }
- }
- // 打印数组
- private static void printArray(int[] arr) {
- for (int i = 0; i < arr.length; i++) {
- System.out.print(arr[i] + " ");
- }
- System.out.println();
- }
- public static void main(String[] args) {
- int[] arr = {4, 10, 3, 5, 1};
- System.out.println("Original array:");
- printArray(arr);
- heapSort(arr);
- System.out.println("Sorted array:");
- printArray(arr);
- }
- }
复制代码 四、堆排序的工作流程
让我们通过一个简朴的例子来理解堆排序的工作流程。
1. 构建最大堆
假设我们有一个数组 arr = [4, 10, 3, 5, 1]。
(1)初始数组:[4, 10, 3, 5, 1]
(2)构建最大堆的过程中,我们从 i = n/2 - 1 开始,依次调整每个节点,直到根节点。
(3)调整后的堆:[10, 5, 3, 4, 1],此时堆顶的元素是最大值。
2. 排序过程
互换堆顶元素与末了一个元素,并调整堆。
(1)第一次互换:互换堆顶和末了一个元素后,数组变为:[1, 5, 3, 4, 10]。然后对剩余元素进行堆化,调整后的堆是:[5, 4, 3, 1, 10]。
(2)第二次互换:互换堆顶和倒数第二个元素,数组变为:[1, 4, 3, 5, 10],调整后的堆是:[4, 1, 3, 5, 10]。
(3)第三次互换:互换堆顶和倒数第三个元素,数组变为:[3, 1, 4, 5, 10],调整后的堆是:[3, 1, 4, 5, 10]。
(4)第四次互换:互换堆顶和倒数第四个元素,数组变为:[1, 3, 4, 5, 10],此时只有一个元素剩下,排序完成。
最终,数组变为升序排列:[1, 3, 4, 5, 10]。
五、堆排序的优缺点
长处:
(1)时间复杂度稳固:无论输入数据如何,堆排序的时间复杂度始终为 O(n log n),不受数据分布影响。
(2)空间复杂度低:堆排序是原地排序算法,其空间复杂度为 O(1),无需额外的辅助空间。
(3)得当大数据处置惩罚:由于堆排序的时间复杂度稳固且不依赖于数据的初始状态,它实用于大数据量的排序。
缺点:
(1)不是稳固排序:堆排序不包管相称元素的相对顺序,因此不实用于需要稳固排序的场景。
(2)常数因素较大:虽然堆排序的时间复杂度是 O(n log n),但其常数因素较大,通常比快速排序和归并排序要慢,尤其在处置惩罚小数据集时。
六、堆排序的应用场景
(1)优先队列实现:堆可以用来实现优先队列,特别是在需要频仍获取最大或最小值的场景中(例如,Dijkstra算法、Huffman编码)。
(2)外部排序:当数据量过大,不能全部加载到内存时,堆排序可以有用地对外部存储的海量数据进行排序。
总结
堆排序是一种基于堆数据结构的排序算法,具有 O(n log n) 的时间复杂度和 O(1) 的空间复杂度。尽管堆排序是一个不稳固的排序算法,但其高效性和原地排序特性使它在某些特定场景中非常有用,尤其是在需要频仍访问最大值或最小值的应用中。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |