7.堆排序

本文详细介绍了堆排序算法的原理,包括大顶堆和小顶堆的定义,二叉排序树的特性,以及如何将数组调整为大顶堆。堆排序方法通过构建和调整大顶堆,实现元素的有序排列。提供的Java代码示例展示了堆排序的完整过程,包括调整堆和交换元素等步骤,并通过测试用例验证了算法的效率,对于大数据量排序,堆排序能在O(nlogn)的时间复杂度内完成任务。
摘要由CSDN通过智能技术生成

堆排序的时间复杂度是:线性对数阶 o(nlong)

一、大小堆定义

大堆:父节点都大于或等于子节点

小堆:父节点都小于或等于子节点

二、二叉排序树

首先要学习堆排序需要了解二叉排序树

二叉排序树的规律:

1.左子节点的值等于:n*2+1

2.右子节点的值等于:n*2+2

3.第n个元素的父节点的值等于:(n-1)/2

三、堆排序方法执行之前需要将数组调整成大顶堆

思想是:

1.先取出当前的元素临时存起来

2.开始循环,循环开始从左子树开始,就是顺序二叉树左子树规律:k = k*2+1,步长也是左子树

1)如果左子树大于右子树的话,就让他把下标移到右子树

2)判断这个值是否大于当前元素,存储起来的数,大于就替换

3.调整到大顶堆是让父子数的值大于或者等于左子树

/**
 * //将一个数组(二叉树),调整成大顶堆
 * 大顶堆的概念是:父节点必须大于或者等于子节点
 *
 * @param arr    待调整的数组
 * @param i      表示非叶子节点在数组中的索引
 * @param length 表示对多少个元素进行调整,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) {
        //!!!注意 :k+1<length是关键代码,少了这个的话排序会出问题
        if (k + 1 < length && arr[k] < arr[k + 1]) {//如果左子节点小于右子节点
            k++;//把数组的下标移动到右子节点下
        }
        if (arr[k] > temp) {//如果子节点大于父节点的话,就要把字节点和父节点进行替换
            arr[i] = arr[k];
            i = k;
        } else {
            break;
        }
        //当for循环之后,已经把最大值放到了i里
        arr[i] = temp;//现在的i已经不是一开始的i,已经变成了需要调整位置的下标
    }
}

四、实现堆排序(大顶堆)

堆排序的思想就是:当调整成大顶堆之后,父节点一定大于或等于子节点,那么第一个数就是最大值,把开头的数和末尾的数进行替换。替换完成之后最后的数就是最大数,剔除最大数之后,在把剩余的数调整成大顶堆,再重复之前的操作,直到最后排序完成

/**
     * 堆排序的方法
     * 第一步:先把数组按照大顶堆或者小顶堆的顺序排列
     * 第二步:排列完成之后把开头的数和末尾的数进行交换
     * 第三步,打印结果
     *
     * @param arr
     */
    public static void heapSort(int[] arr) {
        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--) {
            //进行交换
            int temp = 0;
            temp = arr[j];//末尾的数
            arr[j] = arr[0];//开头的数和末尾的数进行交换
            arr[0] = temp;
            adjustheap(arr, 0, j);//再次进行排序,把最大的值放到第一个
        }
//        System.out.println(Arrays.toString(arr));
    }

五、完整的测试代码

public class HeapSort {

    public static void main(String[] args) {
        int[] arr = {4, 6, 8, 5, 9};
        heapSort(arr);
        int[] array = new int[8000000];
        for (int i = 1; i < 8000000; i++) {
            array[i] = (int) (Math.random() * 80000);
        }
        long time = new Date(System.currentTimeMillis()).getTime();
        heapSort(array);
        long time1 = new Date(System.currentTimeMillis()).getTime();
        System.out.println("堆排序花费的时间是 " + (time1 - time) + " 毫秒");

    }

    /**
     * 堆排序的方法
     * 第一步:先把数组按照大顶堆或者小顶堆的顺序排列
     * 第二步:排列完成之后把开头的数和末尾的数进行交换
     * 第三步,打印结果
     *
     * @param arr
     */
    public static void heapSort(int[] arr) {
        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--) {
            //进行交换
            int temp = 0;
            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 表示对多少个元素进行调整,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) {
            //!!!注意 :k+1<length是关键代码,少了这个的话排序会出问题
            if (k + 1 < length && arr[k] < arr[k + 1]) {//如果左子节点小于右子节点
                k++;//把数组的下标移动到右子节点下
            }
            if (arr[k] > temp) {//如果子节点大于父节点的话,就要把字节点和父节点进行替换
                arr[i] = arr[k];
                i = k;
            } else {
                break;
            }
            //当for循环之后,已经把最大值放到了i里
            arr[i] = temp;//现在的i已经不是一开始的i,已经变成了需要调整位置的下标
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值