使用堆排序

堆排序要求我们从给定的元素列表中建立一个堆,然后持续检查堆属性,使整个堆始终保持排序状态。与普通堆不同的是,一旦新插入的值满足条件,我们就会停止检查堆属性,而在堆排序过程中,我们会继续对下一个元素进行检查。堆排序的伪代码如下所示:

Heapsort(A as array)
    BuildHeap(A)
    for i = n-1 to 0
        swap(A[0], A[i])
        n = n - 1
        Heapify(A, 0)

BuildHeap(A as array)
    n = elements_in(A)
    for i = floor(n/2) to 0
        Heapify(A,i)

Heapify(A as array, i as int)
    left = 2i+1
    right = 2i+2
    max = i

    if (left <= n) and (A[left] > A[i])
        max = left

    if (right<=n) and (A[right] > A[max])
        max = right

    if (max != i)
        swap(A[i], A[max])
        Heapify(A, max)

伪代码显示,每当我们试图对元素列表进行排序时,启动过程都取决于堆的构建。每次向堆中添加一个项目时,我们都会通过 heapify 函数检查该项目是否满足堆属性。一旦堆构建完成,我们就会检查所有元素的堆属性。现在,让我们根据前面的伪代码来实现堆排序:

Unresolved include directive in modules/ROOT/pages/ch10/ch10-06.adoc - include::example$Chapter10/3.php[]

现在让我们使用 heapSort 函数对数组进行排序。由于我们是以引用方式传递参数,因此函数不会返回任何内容。实际数组将在操作结束时进行排序:

Unresolved include directive in modules/ROOT/pages/ch10/ch10-06.adoc - include::example$Chapter10/3.php[]

如果我们运行这段代码,命令行会有如下输出:

9 26 34 37 44 65 86 129 143

如果我们想将排序改为降序,只需更改 heapify 函数中的比较值即可。如果我们考虑一下 heapSort 算法的时间和空间复杂度,就会发现堆排序是复杂度最好的排序算法:

最好时间复杂度

\$Ω(nlog(n))\$

最坏时间复杂度

\$O (nlog(n))\$

平均时间复杂度

\$Θ(nlog(n))\$

空间复杂度(最差情况)

\$O(1)\$

与合并排序相比,堆排序具有更好的空间复杂性。因此,许多开发人员更喜欢使用堆排序来对项目列表进行排序。