堆排序详细讲解(一文足矣JAVA)

简介: 堆排序详细讲解(一文足矣JAVA)



1、什么是堆

在计算机科学中,堆(Heap)是一种特殊的数据结构,通常是一个可以被看作近似完全二叉树的数组对象。在堆中,父节点的值总是大于或等于子节点的值(大顶堆),或者父节点的值总是小于或等于子节点的值(小顶堆)。

堆分为两种主要类型:

2、大顶堆

在大顶堆中,父节点的值大于或等于其任何一个子节点的值。因此,堆的根节点包含的是整个堆中的最大值。

3、小顶堆

在小顶堆中,父节点的值小于或等于其任何一个子节点的值。因此,堆的根节点包含的是整个堆中的最小值。

堆常常用于实现优先队列和堆排序等算法。堆排序正是利用堆的特性进行的一种排序算法。

堆的特点:

  • 堆是一个完全二叉树,即除了最后一层,其他层的节点都是满的,最后一层的节点尽量靠左排列。
  • 在堆中,父节点和子节点之间存在特定的大小关系,满足堆的性质。

堆的操作包括插入(将新元素添加到堆中)和删除(从堆中移除某个元素)。这两个操作会触发堆的调整,以保持堆的结构和性质。

在实现上,堆通常以数组的形式存储,可以通过数组索引的关系来找到父节点和子节点。这种数组表示法使得堆的操作更加高效。

4、排序思想:

它的排序思想主要分为两个步骤:

1、构建堆;

2、排序;

构建堆:

  • 首先,将待排序的数组看作是一个完全二叉树,并从最后一个非叶子节点开始向前遍历。
  • 对于每个节点,进行一次“堆化”操作,即将当前节点与其子节点比较,如果当前节点的值小于(或大于,取决于是小顶堆还是大顶堆)子节点的值,则交换它们的位置。
  • 重复这个过程,直到整个数组变成一个满足堆性质的堆。这一步的时间复杂度为O(n),其中n是数组的长度。

排序:

  • 构建好堆之后,堆顶元素是最大值(大顶堆)或最小值(小顶堆)。
  • 将堆顶元素与堆的最后一个元素交换位置,然后将剩余元素重新调整为堆,除了最后一个元素,其余部分仍然保持堆的性质。
  • 重复上述步骤,每次将堆中最大(或最小)的元素放到数组的末尾,直到整个数组有序。

堆排序的关键在于构建和调整堆的过程。构建堆的时间复杂度是O(n),排序阶段进行n-1次交换和堆调整,每次的时间复杂度是O(log n)。因此,堆排序的总体时间复杂度是O(n log n),其中n是数组的长度。

堆排序是一种原地排序算法,不需要额外的辅助数组。它的优点在于对于大规模数据集的排序比较高效,但缺点是相对于一些其他排序算法,它对于小规模数据集的性能可能不如其他算法。此外,堆排序是不稳定的排序算法。

5、代码实现

public class HeapSort {
    public static void heapSort(int[] array) {
        int n = array.length;
        // 构建大顶堆
        buildMaxHeap(array, n);
        // 排序
        for (int i = n - 1; i > 0; i--) {
            // 将堆顶元素(最大值)与数组末尾元素交换
            swap(array, 0, i);
            // 重新调整堆,排除已排序的部分
            maxHeapify(array, i, 0);
        }
    }
    // 构建大顶堆
    private static void buildMaxHeap(int[] array, int n) {
        for (int i = n / 2 - 1; i >= 0; i--) {
            maxHeapify(array, n, i);
        }
    }
    // 堆调整,使得以i为根节点的子树满足大顶堆的性质
    private static void maxHeapify(int[] array, int n, int i) {
        int largest = i; // 初始化父节点为最大值
        int leftChild = 2 * i + 1; // 左子节点
        int rightChild = 2 * i + 2; // 右子节点
        // 找出左右子节点中的最大值
        if (leftChild < n && array[leftChild] > array[largest]) {
            largest = leftChild;
        }
        if (rightChild < n && array[rightChild] > array[largest]) {
            largest = rightChild;
        }
        // 如果最大值不是父节点,则交换它们的位置并继续调整
        if (largest != i) {
            swap(array, i, largest);
            maxHeapify(array, n, largest);
        }
    }
    // 交换数组中两个元素的位置
    private static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    // 测试堆排序
    public static void main(String[] args) {
        int[] array = {4, 10, 3, 5, 1};
        System.out.println("Original Array: " + Arrays.toString(array));
        heapSort(array);
        System.out.println("Sorted Array: " + Arrays.toString(array));
    }
}

这段代码首先调用 buildMaxHeap 构建初始的大顶堆,然后进行堆排序,最终得到一个有序数组。 maxHeapify 方法用于在堆排序中调整堆的结构,确保它仍然满足大顶堆的性质。


相关文章
|
4月前
|
搜索推荐 算法 Java
堆排序实战:轻松实现高效排序,附详细Java代码
嗨,大家好!我是小米,一名热爱技术分享的程序员。今天要带大家了解堆排序——一种基于二叉堆的数据结构,具有O(n log n)时间复杂度的选择排序算法。堆排序分为构建大顶堆和排序两个阶段:先建堆使根节点为最大值,再通过交换根节点与末尾节点并调整堆来逐步排序。它稳定高效,空间复杂度仅O(1),适合对稳定性要求高的场合。虽然不如快速排序快,但在避免递归和节省空间方面有优势。一起动手实现吧!如果有任何疑问,欢迎留言交流!
98 2
|
6月前
|
搜索推荐 算法 Java
Java中的快速排序、归并排序和堆排序是常见的排序算法。
【6月更文挑战第21天】Java中的快速排序、归并排序和堆排序是常见的排序算法。快速排序采用分治,以基准元素划分数组并递归排序;归并排序同样分治,先分割再合并有序子数组;堆排序通过构建堆来排序,保持堆性质并交换堆顶元素。每种算法各有优劣:快排平均高效,最坏O(n²);归并稳定O(n log n)但需额外空间;堆排序O(n log n)且原地排序,但不稳定。
50 3
|
6月前
|
Java
堆排序(java)
堆排序(java)
|
7月前
|
算法 Java
<八大排序>万字详解(Java实现).插入排序、希尔排序、堆排序、快速排序、归并排序、计数排序...
<八大排序>万字详解(Java实现).插入排序、希尔排序、堆排序、快速排序、归并排序、计数排序
31 0
|
7月前
|
搜索推荐 算法 Java
java排序算法:快速排序、归并排序、堆排序等
排序算法:快速排序、归并排序、堆排序等
97 0
|
存储 算法 Java
数据结构——堆、堆排序和优先级队列(代码为Java版本)
数据结构——堆、堆排序和优先级队列(代码为Java版本)
|
人工智能 算法 搜索推荐
java基础算法系列(四)(堆排序的简单讲解)
java基础算法系列(四)(堆排序的简单讲解)
|
算法 搜索推荐 Java
【算法】堆排序的原理与Java实现
堆排序(Heap Sort)是一种基于堆数据结构的排序算法。堆是一种完全二叉树,其中父节点的值总是大于(或小于)其子节点的值。堆排序的基本思想是先将待排序的数组构建成一个最大堆(或最小堆),然后重复从堆顶取出最大(或最小)元素,放到已排序的部分,再调整剩余元素构建新的堆,直到所有元素都被放置到正确的位置。
120 0
|
Java 测试技术 vr&ar
大顶堆升序、小顶堆降序的堆排序(以Java描述为例版本)
大顶堆升序、小顶堆降序的堆排序(以Java描述为例版本)
170 0