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

目录

1、什么是堆

2、大顶堆

3、小顶堆

4、排序思想:

5、代码实现


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 方法用于在堆排序中调整堆的结构,确保它仍然满足大顶堆的性质。

我的其他博客地址:

堆排序详细讲解(一文足矣JAVA)-CSDN博客

你秃头了吗?秃了就强了-CSDN博客

希尔排序(Java)-CSDN博客

  • 12
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
堆排序是一种常见的排序算法,具有稳定性高、效率高等优点。下面介绍一下使用Java实现的小根堆排序。 首先,我们需要定义一个小根堆类,用于存储待排序的数据。该类需要包含以下几个方法: 1. `Heap()`:构造函数,用于初始化小根堆。 2. `insert(int val)`:插入操作,将一个新的元素插入到小根堆中。 3. `deleteMin()`:删除操作,删除小根堆中的最小元素,并返回该元素的值。 4. `size()`:获取小根堆中元素的个数。 5. `isEmpty()`:判断小根堆是否为空。 接下来,我们就可以使用小根堆对待排序的数据进行排序了。具体的步骤如下: 1. 将待排序的数据存入小根堆中。 2. 依次从小根堆中删除最小元素,并将其存入数组中。 3. 最后,将数组反转,即可得到排序后的结果。 下面是具体的Java代码实现: ```java public class HeapSort { public static void heapSort(int[] arr) { Heap heap = new Heap(arr.length); for (int i = 0; i < arr.length; i++) { heap.insert(arr[i]); } for (int i = 0; i < arr.length; i++) { arr[i] = heap.deleteMin(); } // 反转数组 reverse(arr); } // 反转数组 private static void reverse(int[] arr) { int left = 0; int right = arr.length - 1; while (left < right) { int temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; left++; right--; } } // 小根堆类 static class Heap { private int[] heap; private int size; public Heap(int capacity) { heap = new int[capacity + 1]; size = 0; } public void insert(int val) { if (size == heap.length - 1) { throw new RuntimeException("Heap is full"); } int i = ++size; while (i != 1 && val < heap[i / 2]) { heap[i] = heap[i / 2]; i /= 2; } heap[i] = val; } public int deleteMin() { if (isEmpty()) { throw new RuntimeException("Heap is empty"); } int min = heap[1]; int last = heap[size--]; int i = 1; int child = 2; while (child <= size) { if (child < size && heap[child] > heap[child + 1]) { child++; } if (last > heap[child]) { heap[i] = heap[child]; i = child; child *= 2; } else { break; } } heap[i] = last; return min; } public int size() { return size; } public boolean isEmpty() { return size == 0; } } } ``` 使用该算法对数组进行排序: ```java int[] arr = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; HeapSort.heapSort(arr); System.out.println(Arrays.toString(arr)); // 输出 [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薅你两根毛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值