vlambda博客
学习文章列表

十大经典排序(七)--堆排序

堆排序思路:

        堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。可以说是一种利用堆的概念来排序的选择排序。分为两种方法:


  • 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;

  • 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

算法步骤:

  1. 创建一个堆 H[0……n-1](大顶或者小顶),这里咱们构建大顶堆;

  2. 把堆首(最大值)和堆尾互换;

  3. 将堆的大小减 1,并对堆进行调整,目的是把新的数组顶端数据调整到相应位置;

  4. 重复步骤 2,直到堆的尺寸为 1。


题外话:小顶堆和大顶堆构建及维护代码基本一致,这里偷波懒,就不实现了,其实在Java中也有一些原生的类使用堆来实现的,如 PriorityQueue就是个基于优先级堆实现的优先级队列,有兴趣的同学可以看看


代码

 1private static void sort(int arr[]) {
2    if (arr == null || arr.length == 0) {
3        return;
4    }
5
6    int len = arr.length;
7    //构建堆的时候记得 得从下至上
8    for (int i = len - 1; i >= 0; i--) {
9        adj(arr, i, len);
10    }
11    for (int i = len - 1; i > 0; i--) {
12        //交换
13        swap(arr, 0, i);
14        len--;
15        //调整堆
16        adj(arr, 0, len);
17    }
18}
19
20//构建&调整堆
21private static void adj(int arr[], int i, int len) {
22    //保留原始值
23    int temp = arr[i];
24    //假设数组中用 i 为父节点
25    // 那么左子节点的下标就是 2 * i + 1
26    //右子节点下标就是 2 * i + 2
27    for (int k = 2 * i + 1; k < len; k = 2 * k + 1) {
28        //找到左右子节点中最大的那个
29        if (k + 1 < len && arr[k] < arr[k + 1]) {
30            k++;
31        }
32        //如果子节点中有比父节点大的,进行值交换
33        if (arr[k] > temp) {
34            arr[i] = arr[k];
35            //注意 i 的替换
36            i = k;
37        }
38    }
39    arr[i] = temp;
40}
41
42//交换 这里没有采用额外变量,和异或法原理类似
43//有兴趣同学可以试试异或法
44private static void swap(int[] arr, int i, int j) {
45    arr[i] = arr[i] + arr[j];
46    arr[j] = arr[i] - arr[j];
47    arr[i] = arr[i] - arr[j];
48}

时间复杂度:O(nlogn) 

空间复杂度:O(1)


以上仅是个人思路解法,觉得还不错欢迎点赞关注分享


往期精彩推荐