堆排序学习记录

堆的定义

堆是一种叫完全二叉树的数据结构,可以分为大根堆,小根堆,而堆排序就是基于这种结构而产生的一种程序算法。

堆的种类

大根堆:每个节点的值都大于其子节点的值(权重)

 小跟堆:每个节点的值都小于其子节点的值

说明

        从数据存储来看,数组存储方式树的存储方式可以相互转换,即数组可以转换成树,树也可以转换成数组。

以大根堆为例子

 堆排序思路:

        如何利用堆这种数据结构进行排序?

堆排序是建立在大根堆(小根堆)上的,我们知道在根节点就是此数组最大的数,此时可以确定一个位置,当我们把第一个位置和最后一个位置进行交换后,如下图所示,发现,除去最后一个元素,从根节点开始,可以很快的重新构建一个大根堆

 重新构建大根堆如图所示

此时新大根堆的的最大值也已经确定,为根节点的值(35),此时我们重复上一步骤,把最大的数与数组(此时的数组是指除去45的数组)最后的数交换,除去最后一个数,组成新的数组,从根节点开始,又可以很快的重新构建一个大根堆..

重复这个步骤,最终可得到有序的数组

最后思路我们有了,但是如何把无序的数组构建成大根堆呢?

大根堆的创建应该从下往上,不能直接从根节点开始,否则有的不符合大顶堆的定义

  1. 从最后一棵子树开始,从后往前调整(从数组角度来看)
  2. 每次调整从上往下调整(从堆角度来看)
  3. 调整为大根堆

文字表达不力,请各位直接看图,直观了解

图片来自博客http://t.csdn.cn/7iRl6

总结步骤

1、初始化数组,创建大顶堆。
    1.1大顶堆的创建从下往上比较,不能直接用无序数组从根节点比较,否则有的不符合大顶堆的定义。
2、交换根节点和倒数第一个数据,现在倒数第一个数据就是最大的。
3、重新建立大顶堆。
    3.1 因为只有 array[0] 改变,其它都符合大顶堆的定义,所以可以根节点 array[0] 重新建立。
4、重复2、3的步骤,直到只剩根节点 array[0],即 i=1。

下面给出Java示例代码

public class HeapSort {
    public static void main(String[] args) {
        int arr[] = {2, 5, -1, 35, 23, 3, 6, 45, 8, 9};
        heapSort(arr);
    }

    //编写一个堆排序的方法
    public static void heapSort(int arr[]) {
        int temp = 0;
        System.out.println("堆排序");
        //首次构建大顶堆
        for (int i = arr.length / 2 - 1; 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);
        }
        System.out.println("调整: " + Arrays.toString(arr));

    }
    //将一个数组(二叉树),调整成一个大顶堆
    /**
     * @param arr    待调增的数组
     * @param i      表示非叶子结点在数组中索引
     * @param length  表示要构建的大顶堆(数组)的长度
     */
    public static void adjustHeap(int[] arr, int i, int length) {
        int temp = arr[i];

        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
            if (k + 1 < length && arr[k] < arr[k + 1]) {
                k++;
            }
            if (arr[k] > temp) {
                arr[i] = arr[k];
                i = k;
            } else {
                break;
            }
        }

        arr[i] = temp;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值