堆排序从理论思想到Java代码实现

什么是堆?

堆是一种特殊的完全二叉树,
即自上而下, 自左到右, 依次将每一个节点, 叠满整棵树, 这种树叫完全二叉树
当完全二叉树的每一个节点大于等于或者小于等于自己的左右子树时, 称该完全二叉树为堆
当堆的顶端是最大值时, 它叫大顶堆
当堆的顶端是最小值时, 它叫小顶堆

堆可以用来解决什么样的问题?

TOP K问题(面试老常客了, 希望你不是和我一样面向面试学习。。。

堆排序的理论思想

虽然堆排序引入了堆的概念, 但是并不是真正的去构建一个二叉树, 它只是实现了一个"假想的逻辑堆 a[i] >= a[2 * i + 1] && a[i] >= a[2 * i + 2]
先来个无序的堆!
我们把它从上往下, 从左往右给它标上号(根为i),

在这里插入图片描述

like this!

并且可以把它换成一个无序数组
在这里插入图片描述

我们准备把它构造成一个合格的大顶堆
先构建一个大顶堆, 构建一个大顶堆的步骤, 需要从下至上的构建, 所以我们需要从第一个非叶子结点出发。(在这个图中就是1号节点(值为9的哪个
在这里插入图片描述
第一个非叶子节点处理完了, 现在我们来处理第二个非叶子节点
在这里插入图片描述
在这里插入图片描述
构建好大顶堆之后, 我们再将堆顶的元素也就是最大元素放入堆的最后一个位置, 从而生成了第一个有序的元素, 如此再重新调整混乱的大顶堆, 再依次地调整好的大顶堆–堆顶元素放入尾部
在这里插入图片描述
是不是感觉就得到了第一个最大值(TOP K的内味儿有了!
更换完堆顶元素后, 再对堆依次进行调整
在这里插入图片描述
这样不停的替换调整, 最后将得到一个有序的数组
在这里插入图片描述

我们来总结一下!

1).将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

2).将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

3).重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

实现堆排序的代码

package baguwen;

import java.util.Arrays;

public class HeapSort {



    public static void main(String[] args) {
        int arr[] = {4, 6, 8, 5, 9};
        //Link Start!
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void heapSort(int arr[]) {
        int temp = 0;

        //将无序序列构建成一个堆, 根据升序降序需求选择大顶堆或小顶堆
        for (int i = arr.length / 2; i >= 0; i--) {
            //除开叶子节点, 从下往上, 从左往右对无序数组(堆)进行排序
            adjustHeap(arr, i, arr.length);
        }

        for (int j = arr.length - 1; j > 0; j--) {
            //对排序后的把根节点和序号最大的叶子节点进行交换
            //(这样就获得了一个最大的数
            temp = arr[j];
            arr[j] = arr[0];
            arr[0] = temp;
            //交换完后对剩下的堆进行整理(除去了序号最大的叶子节点)
            adjustHeap(arr, 0, j);
        }
    }

    public static void adjustHeap(int[] arr, int i, int length) {

        //k = i * 2 + 1是i节点的左子节点
        //k = k * 2 + 1相当于k节点的左子节点
        for (int k = i * 2 + 1; k < length; k =k * 2 + 1) {
            //比较两个叶子节点他们值的大小(如果存在), k指向那个较大的那个
            if (k + 1 < length && arr[k] < arr[k + 1]) {
                k++;
            }
            //如果叶子节点大于它的父节点, 那么进行交换
            if (arr[k] > arr[i]) {
                int temp = arr[i];
                arr[i] = arr[k];
                arr[k] = temp;
                i = k;
                //如果不大于则进行下一次循环(就不需要进行交换了
            }else {
                break;
            }
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值