图解堆排序

本文介绍一下常见的堆排序的原理及实现代码。

简介

堆排序是一种树形选择排序方法,要了解堆排序就不得不了解一下堆。简单的说,堆是一种完全二叉树,根据父子节点之间的大小关系的不同还可以细分为大顶堆小顶堆。大顶堆是指任一节点的值都大于或等于其左右孩子的值,小顶堆是指任一节点的值都小于或等于其左右孩子的值。下图分别是大顶堆和小顶堆的结构。

堆排序过程

我们以大顶堆为例,演示一下堆排序过程。

现在我们有一个待排序数组[2,7,4,3,1,9,5],初始状态是这样的:

进行堆排序时,一般需要对节点从下到上,从右到左进行调整,我们先调整右下角的部分。

右下角的部分就调整好了,我们看左下角是符合父节点大于孩子节点的,所以跳过看上一层的。

我们交换了2和9之后要注意被换下来的2是比4和5小的,所以要把5和2再交换一下。

这下就是一个大顶堆了,根节点就是我们要找的最大值,我们把根节点和右下角的节点互换位置,做一下“沉淀”。注意,此时我们已经将最大的节点放到最后了。

接下来我们只需要进行适当的调整大顶堆就可以了。我们注意到此时的根节点是相当比较小的,只需要把左右孩子中较大的和它交换位置,然后重复这个过程就可以了。

做完上面的步骤我们发现根节点的值又是当前堆的最大元素了,我们把根节点7和最后一个节点交换,7成了倒数第二个节点,重复上面的过程,就能得到一个排好序的数组了。

Java代码实现

public class HeapSort {
	
    public static void heapSort(int[] arr) {

        //1.将无序序列构建为一个大顶堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjustHeap(arr, i, arr.length);
        }

        //2.将堆顶元素与末尾元素交换,最大元素沉淀到末尾
        //3.重复这个过程
        for (int j = arr.length - 1; j > 0; j--) {
            int temp = arr[j];
            arr[j] = arr[0];
            arr[0] = temp;
            adjustHeap(arr, 0, j);
        }
    }

    //将一个数组(二叉树),调整为一个大顶堆
    public static void adjustHeap(int arr[], int i, int length) {

        int temp = arr[i];//先取出当前元素的值,保存在临时变量
        //开始调整
        //说明:
        //1、k是i结点的左子结点
        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
        	//右节点比左节点的值大
            if (k + 1 < length && arr[k] < arr[k + 1]) {
                k++;//k指向右子结点
            }
            if (arr[k] > temp) {//如果子结点大于父结点
                arr[i] = arr[k];//把较大的值赋值给当前结点
                i = k;//i指向k,继续循环比较
            } else {
                break;
            }
        }

        //当for循环结束后,已经将以i为父结点的树的最大值放在了最顶(局部)
        arr[i] = temp;//将temp值放到调整后的位置
    }
	
	public static void main(String[] args) {
		int[] arr = {2,7,4,3,1,9,5};
		heapSort(arr);
		System.out.println(Arrays.toString(arr));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值