首页 > 其他分享 >大根堆排序

大根堆排序

时间:2024-08-25 22:51:29浏览次数:11  
标签:index arr int 堆排序 param 叶子 节点

原理

假设待排序目标为数组arr,可将其视为一个完全二叉树。在大根堆排序中,根节点为最大值,我们循环将根取出,并减少大根堆的长度和调整堆使之堆维持大根堆,直至取出堆中全部节点数据。因为我们每次都是取出大根堆的最大值,故取出数据便有序了。

完全二叉树父节点和叶子节点的索引关系:
已知叶子节点索引index,则父节点索引 (index-1)/2
已知父节点索引index,则左叶子节点索引2*index+1,右叶子节点索引2*index+2

步骤

    创建大根堆

         从零开始遍历数组,将当前节点视为叶子节点,并于其父节点比较,大于则与父节点交换          值,并将父节点视为叶子节点,重复比较操作,直至根节点;小于则结束本次遍历。

    /**
     * 向堆中插入元素,并维持大根堆
     * 原理:数组末尾插入的新元素和其父元素对比,大则交换位置
     * @param arr 存储堆元素的数组
     * @param index 插入位置
     */
    public static void heapInsert(int[] arr, int index){
        while (arr[index] > arr[(index-1)/2]){
            swap(arr, index, (index-1)/2);
            index = (index-1)/2;
        }
    }

    /**
     * 交换2个位置的值
     * @param arr 目标数组
     * @param i 位置1
     * @param j 位置2
     */
    public static void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    堆排序

        排序是通过循环将大根堆的根交换至堆尾,每次循环将堆长减1,并调整剩余堆使之维持大根      堆。

    /**
     * 堆排序
     * @param arr 存储堆元素的数组
     */
    public static void heapSort(int[] arr){
        if (arr == null || arr.length<2){
            return;
        }
        // 1.创建大根堆
        for (int i=0;i<arr.length;i++){
            heapInsert(arr,i);
        }

        System.out.println("创建时的大根堆:"+Arrays.toString(arr));

        // 开始排序
        int heapSize = arr.length;
        // 2.先交换一次堆顶的元素和堆的最后一个元素,再令大根堆长度减1
        swap(arr,0,--heapSize);
        // 3.重复交换和调整过程,每次将最大值放置大根堆尾,再使堆长度减1,再调整堆使之保持大根堆,最终使堆从不小到大排列
        while (heapSize>0){
            // 调整0~heapSize的元素保持大根堆
            heapify(arr,0, heapSize);
            // 交换
            swap(arr,0,--heapSize);
        }

        System.out.println("堆排序完成后的堆:"+Arrays.toString(arr));
    }

    /**
     * 调整堆:每次堆顶和堆尾交换后,堆长度减1,重新调整堆,使之保持大根堆
     * @param arr 目标数组
     * @param index 根节点
     * @param heapSize 堆长
     */
    public static void heapify(int[] arr, int index, int heapSize){
        // 左叶子节点
        int leftIndex = 2*index + 1;
        // 0~heapSize-1是大根堆,当左叶子节点位置小于大根堆的长度,则进行调整;否则index就是叶子节点,退出循环。
        while (leftIndex < heapSize){
            // 寻找左叶子节点和右叶子节点的最大值,当右叶子节点存在且大于左叶子节点,largestIndex才为右叶子节点,否则为左叶子节点
            int largestIndex = leftIndex+1<heapSize&&arr[leftIndex+1]>arr[leftIndex]?leftIndex+1:leftIndex;

            // 左右叶子节点最大值和index节点比较值的大小,来判断是否进行交换
            largestIndex = arr[largestIndex] >arr[index]?largestIndex:index;
            // 若当前节点大于左右叶子节点的话,就无需交换了
            if (largestIndex == index){
                break;
            }

            swap(arr, largestIndex, index);

            // 交换后当前位置跳到叶子节点,重复以上动作,直至结束。
            index = largestIndex;
            leftIndex = 2*index+1;
        }
    }

总结

建堆时间复杂度:O(n)

排序时间复杂度:O(nlog2n)

时间复杂度 = O(n)+O(nlog2n)=O(nlog2n)

空间复杂度:O(1)

标签:index,arr,int,堆排序,param,叶子,节点
From: https://blog.csdn.net/qq_25261793/article/details/141535813

相关文章

  • 堆排序的插入和删除
    插入:    1. 检查你的顺序表是否还有位置去插入,如果没有需要扩展    2.插入到已有序列的后一位置    3.和其父节点进行比较,是否满足大根堆/小根堆规则    4.不满足则需要交换数值删除:    1.将最后一个元素覆盖将要删除的元......
  • 详解堆排序(内附代码实现)
    堆排序有两个过程下标为i的节点的父节点下标:(i-1)/2整除下标为i的节点的左孩子下标:i*2+1下标为i的节点的右孩子下标:i*2+2待排序序列为:​ 23814910716141.建大顶堆​ 首先建立无序堆 然后建立大顶堆:从右往左,从下往上,递归的选择子节点最大的往上浮首先14大......
  • 蒜法笔记(Java)- 堆排序
    逻辑    堆是一种所有父节点都大于等于(大根堆)或小于等于(小根堆)其子节点的完全二叉树。堆排序(升序)就是一种将数组视为一个完全二叉树,将其变为一个大根堆后将堆顶放到数组尾,重复n次后数组有序的排列方法,时间复杂度为O(nlogn)。(感觉好像冒泡哦)    简述:将数组视......
  • C语言实现排序之堆排序算法
    一、堆排序算法基本思想堆排序是一种比较有效的排序方法,其基本思想是:构建最大堆:首先将待排序的数组构建成一个最大堆,即对于每个非叶子节点,它的值都大于或等于其子节点的值。排序:然后将堆顶元素(最大值)与堆的最后一个元素交换位置,将其移出堆,并调整剩余元素以保持最大堆的性质......
  • 堆排序以及向上、向下调整算法的时间复杂度推导及实现(超详细)
    什么是堆排序?堆排序是由堆这种数据结构所设计的一种排序算法堆的分类:大根堆:每个父结点的值都大于子结点小根堆 :每个父结点的值都小于子结点 在了解完堆之后,需要先了解建堆,建堆有向上建堆建大堆或者小堆,也有向下建堆建大堆或者小堆 建大堆还是小堆看子结点和父结点的......
  • 排序算法 堆排序 HeapSort -- C语言实现
    堆排序堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:大顶堆:每个节点的值都大于或等于其子......
  • 常见的排序算法——堆排序(五)
    本文记述了堆排序改用前序表示法基本思想和一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。◆思想堆排序算法按照层次操作堆中的元素,即物理位置k的节点与位置2k或2k+1的节点交换。然而用前序表示的堆,其父子节点的位置关系不能简单地计算出来。因此,当算法......
  • 常见的排序算法——堆排序(四)
    本文记述了针对堆排序同时实施减少数据交换和Floyd方法的一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。◆思想减少数据交换的操作,请参考堆排序(二);Floyd方法,请参考堆排序(三)(此处略去详细说明)。◆实现排序代码采用《算法(第4版)》的“排序算法类模板”实现。(......
  • 常见的排序算法——堆排序(三)
    本文记述了针对堆排序实施Floyd方法的基本思想和一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。◆思想“大多数在下沉排序期间重新插入堆的元素会被直接加入到堆底。Floyd在1964年观察发现,我们正好可以通过免去检查元素是否到达正确位置来节省时间。”(引......
  • 常见的排序算法——堆排序(二)
    本文记述了针对堆排序微小改动的基本思想和一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。◆思想堆的下沉操作中用到了昂贵的数据交换操作,此改动参考无交换的插入排序的思想,实现了减少数据交换的下沉操作。先将要下沉的元素存放在临时空间中,再将下降过程中遇......