Démonstration animée du tri par tas Visualisez votre code avec des animations

图码-数据结构可视化动画版

堆排序是一种基于 二叉堆 数据结构的比较排序技术 它类似于 选择排序 ,我们首先找到最小元素并将最小元素放在开头。 对其余元素重复相同的过程。

堆排序算法

要解决该问题,请遵循以下想法:

首先使用heapify将数组转换为堆数据结构,然后逐个删除Max-heap的根节点并替换为堆中的最后一个节点,然后对堆的根进行heapify。 重复此过程,直到堆的大小大于 1。

  • 从给定的输入数组构建一个堆。
  • 重复以下步骤,直到堆只包含一个元素:
    • 将堆的根元素(最大的元素)与堆的最后一个元素交换。
    • 删除堆的最后一个元素(现在位于正确的位置)。
    • 堆化堆的剩余元素。
  • 排序数组是通过反转输入数组中元素的顺序获得的。

堆排序的详细工作原理

为了更清楚地理解堆排序,让我们采用一个未排序的数组并尝试使用堆排序对其进行排序。
考虑数组:arr[] = {4, 10, 3, 5, 1}。

构建完整二叉树: 从数组构建完整二叉树。

堆排序算法|  构建完全二叉树

堆排序算法| 构建完全二叉树

转换为最大堆: 之后,任务是从未排序的数组构造一棵树,并尝试将其转换为 最大堆。

  • 要将堆转换为最大堆,父节点应始终大于或等于子节点
    • 在此示例中,由于父节点 4 小于子节点 10, 因此将它们交换以构建最大堆。
  • 现在,作为父级的 4 小于子级 5 ,因此再次交换这两个值,结果堆和数组应如下所示:
堆排序算法|  Max Heapify构造二叉树

堆排序算法| Max Heapify构造二叉树

执行堆排序: 删除每一步中的最大元素(即,将其移动到结束位置并将其删除),然后考虑剩余元素并将其转换为最大堆。

  • 从最大堆中 删除根元素 (10) 。 为了删除这个节点,尝试将它与最后一个节点交换,即 (1)。 删除根元素后,再次对其进行堆化,将其转换为最大堆。
    • 结果堆和数组应如下所示:
堆排序算法|  从 root 和 max heapify 中删除最大值

堆排序算法| 从 root 和 max heapify 中删除最大值

  • 重复上面的步骤,就会像下面这样:
堆排序算法|  从根和最大堆中删除下一个最大值

堆排序算法| 从根和最大堆中删除下一个最大值

  • 现在再次删除根(即3)并执行heapify。
堆排序算法|  重复上一步

堆排序算法| 重复上一步

  • 现在,当根再次被删除时,它就被排序了。 排序后的数组将类似于 arr[] = {1, 3, 4, 5, 10}
堆排序算法|  最终排序数组

堆排序算法| 最终排序数组

堆排序的实现

C++

// C++ program for implementation of Heap Sort
 
#include <iostream>
using namespace std;
 
// To heapify a subtree rooted with node i
// which is an index in arr[].
// n is size of heap
void heapify(int arr[], int N, int i)
{
 
    // Initialize largest as root
    int largest = i;
 
    // left = 2*i + 1
    int l = 2 * i + 1;
 
    // right = 2*i + 2
    int r = 2 * i + 2;
 
    // If left child is larger than root
    if (l < N && arr[l] > arr[largest])
        largest = l;
 
    // If right child is larger than largest
    // so far
    if (r < N && arr[r] > arr[largest])
        largest = r;
 
    // If largest is not root
    if (largest != i) {
        swap(arr[i], arr[largest]);
 
        // Recursively heapify the affected
        // sub-tree
        heapify(arr, N, largest);
    }
}
 
// Main function to do heap sort
void heapSort(int arr[], int N)
{
 
    // Build heap (rearrange array)
    for (int i = N / 2 - 1; i >= 0; i--)
        heapify(arr, N, i);
 
    // One by one extract an element
    // from heap
    for (int i = N - 1; i > 0; i--) {
 
        // Move current root to end
        swap(arr[0], arr[i]);
 
        // call max heapify on the reduced heap
        heapify(arr, i, 0);
    }
}
 
// A utility function to print array of size n
void printArray(int arr[], int N)
{
    for (int i = 0; i < N; ++i)
        cout << arr[i] << " ";
    cout << "\n";
}
 
// Driver's code
int main()
{
    int arr[] = { 12, 11, 13, 5, 6, 7 };
    int N = sizeof(arr) / sizeof(arr[0]);
 
    // Function call
    heapSort(arr, N);
 
    cout << "Sorted array is \n";
    printArray(arr, N);
}


            

C

Java

Python3

C#

JavaScript

PHP

输出

排序后的数组是
5 6 7 11 12 13

堆排序 的复杂度分析

时间复杂度: O(N log N)
辅助空间: O(log n),由于递归调用堆栈。 然而,对于迭代实现来说,辅助空间可以是O(1)。

关于堆排序的要点:

  • 堆排序是一种就地算法。 
  • 它的典型实现不稳定,但可以使其稳定(请参阅
  • 通常比实现良好的 QuickSort 慢 2-3 倍。 缓慢的原因是缺乏参考位置。

堆排序的优点:

  • 高效的时间复杂度: 在所有情况下,堆排序的时间复杂度均为 O(n log n)。 这使得对大型数据集进行排序变得高效。 log n 因子 来自二叉堆的高度,它确保算法即使在元素数量较多的情况下也能保持良好的性能。
  • 内存使用 – 内存使用量可以最小化,因为除了保存要排序的初始项目列表所需的内存之外,它不需要额外的内存空间来工作
  • 简单性——  它比其他同样高效的排序算法更容易理解,因为它不使用递归等先进的计算机科学概念。

堆排序的缺点:

  • 成本高昂 :堆排序的成本很高。
  • 不稳定 :堆排序不稳定。 它可能会重新排列相对顺序。
  • 高效: 在处理高度复杂的数据时,堆排序不是很高效。 

与堆排序相关的常见问题

Q1. 堆排序分为哪两个阶段?

堆排序算法由两个阶段组成。 在第一阶段,数组被转换为最大堆。 在第二阶段,最高的元素(即树根处的元素)被删除,剩余的元素用于创建新的最大堆。

Q2。 为什么堆排序不稳定?

堆排序算法不是一个稳定的算法。 此算法不稳定,因为在堆中执行的操作可能会更改等效键的相对顺序。

Q3。 堆排序是“分而治之”算法的一个例子吗?

堆排序根本 不是 分而治之的算法。 它使用堆数据结构来有效地对其元素进行排序,而不是使用“分而治之的方法”来对元素进行排序。

Q4。 哪种排序算法更好——堆排序还是归并排序?

答案在于它们的时间复杂度和空间要求的比较。 归并排序比堆排序稍快。 但另一方面,合并排序需要额外的内存。 根据要求,应选择使用哪一种。

Q5. 为什么堆排序比选择排序更好?

堆排序与选择排序类似,但有更好的方法来获取最大元素。 它利用堆数据结构在常数时间内获取最大元素 


Que votre objectif soit la réussite d'un examen, le développement professionnel ou un intérêt purement personnel, ce site de visualisation des structures de données et des algorithmes sera une ressource inestimable.

Rendez-vous sur ce site et commencez votre voyage d'apprentissage !

Voici les plus courants : 【Description en langage C】Structures de données et algorithmes Implémentation JAVA des structures de données Fondamentaux des structures de données et algorithmes (Université de Qingdao - Wang Zhuo) Structures de données et algorithmes Structures de données selon Wang Dao Implémentation en langage C des structures de données Cours intensif de structures de données pour les examens de fin de semestre Tutoriel vidéo sur les structures de données en langage C Yan Weimin sur les structures de données Hao Bin sur les structures de données Examen d'entrée en master sur les structures de données Algorithmes et fondamentaux des structures de données en JAVA Structures de données selon Wang Dao 2022 Apprentissage des structures de données Structures de données selon Xiao Jiayu Wang Zhuo Apprentissage des structures de données Structures de données à l'Université du Zhejiang Révision des structures de données Structures de données selon Ma Shibin Cours zéro sur les structures de données Structures de données et algorithmes Introduction aux structures de données Explication des exercices de structures de données pour l'examen d'entrée en master Révision de fin de semestre des structures de données Niveau 2 en informatique