初级排序算法之堆排序

堆排序的思想

堆排序的具体算法,思想是每次取出堆的最顶层根节点,即数组下标为0,然后与最后一个节点即i+1交换。

参考地址

建堆过程:

  1. 首先将原始队列构建成完全二叉树
  2. 然后从第一个非叶子节点开始,比较当前节点和其孩子节点,将最大的元素放在当前节点,交换当前节点和最大节点元素。

    注意:如果根节点是a[0],那么第一个非叶子节点就是倒数第二层的最后一个根节点,下标为length/2-1

  3. 将当前元素前面所有的元素都进行2的过程,这样就生成了最大堆
   /**
     * @param data 原始数组序列
     * @brief 构建堆
     */
    public static void buildHeap(int[] data) {
        /**
         * 获取最后一个非叶子节点
         */
        int begin = data.length / 2;
        for (int i = begin; i >= 0; i--) {
            adjustHeap(data, data.length, i);
        }
    }

    /**
     * @param data     要调整的数组
     * @param heapSize 长度
     * @param index    需要调整的节点的下标
     * @brief 调整堆
     */
    public static void adjustHeap(int[] data, int heapSize, int index) {

        /**
         * 节点index的左孩子下标
         */
        int leftChildSubscript = 2 * index + 1;
        /**
         *节点index的右孩子下标
         */
        int rightChildSubscript = 2 * index + 2;

        /**
         * 最大元素的初始下标
         */
        int largestSubscript = index;
        /**
         * 找到最大元素
         */
        /**
         * 如果当前根节点小于左孩子的值,那么最大元素的下标为左孩子的下标.
         */
        if ((leftChildSubscript < heapSize) && (data[largestSubscript] < data[leftChildSubscript])) {
            largestSubscript = leftChildSubscript;
        }
        /**
         *如果当前根节点小于右孩子的值,那么最大元素的下标为右孩子的下标.
         */
        if ((rightChildSubscript < heapSize) && (data[largestSubscript] < data[rightChildSubscript])) {
            largestSubscript = rightChildSubscript;
        }

        /**
         * 将最大元素调整至根节点.
         * 根节点不是最大的,那么就调整.
         */
        if (index != largestSubscript) {
            /**
             * 将根节点的值与子节点中的最大值进行调整.
             */
            swapElements(data, index, largestSubscript);
            /**
             */
            adjustHeap(data, heapSize, largestSubscript);
        }
    }

    public static void swapElements(int[] data, int index1, int index2) {
        int temp = data[index1];
        data[index1] = data[index2];
        data[index2] = temp;
    }

堆排序的过程:

首先将原始序列构建为一个堆。

  1. 将堆顶元素和最后一个元素交换,列表长度减1。由此无序区减1,有序区加1
  2. 剩余元素重新调整建堆
  3. 继续1和2,直到所有元素都完成排序
    /**
     * @param data 原始数组
     * @brief 堆排序
     */
    public static void heapSort(int[] data) {
        int length = data.length;
        /**
         * 构建堆
         */
        buildHeap(data);
        while (length >= 1) {
            /**
             * 将堆的最后一个元素与堆顶元素交换.
             */
            swapElements(data, 0, length - 1);

            length--;
            /**
             * 将剩余元素调整为堆
             */
            adjustHeap(data, length, 0);
        }
    }

时间复杂度分析

建堆的时间复杂度最差为O(N),最好为O(1)

堆排序的时间复杂度是O(NlogN)

堆排序为原地排序,空间复杂度为O(1)

版权声明:欢迎交流

时间: 2024-11-05 06:30:26

初级排序算法之堆排序的相关文章

深入理解排序算法(一):初级排序算法

[本系列博文会对常见的排序算法进行分析与总结,并会在最后提供几道相关的一线互联网企业面试/笔试题来巩固所学及帮助我们查漏补缺.项目地址:https://github.com/absfree/Algo.由于个人水平有限,叙述中难免存在不清晰准确的地方,希望大家可以指正,谢谢大家:)] 一.概述 我们在日常开发中经常需要对一组数据对象进行排序,这里的数据对象不仅包括数字,还可能是字符串等抽象数据类型(Abstract Data Type).由于排序是很多其他操作(比如二分查找)能够高效进行的基础,因

排序算法系列——堆排序

记录学习点滴,菜鸟成长记 堆排序引入了另一种算法设计技巧:使用一种我们称之为“堆”的数据结构来进行数据管理. 堆排序算是真正意义上的利用数据结构来求解数组排序的方法. “插入排序”和“归并排序”可以看做是一种“计算机体力活”,体现的思想更多的是去模拟最简单的人类思维,比如插入排序过程中的比较,归并中子问题合并时的比较. “堆排序”可以看做是“计算机脑力活”,他利用了一种结构化的语言来表达,这种结构化带来一些性质,比如左右孩子.比[堆大小的一半向下取整]大的下标都是叶节点不需要维护其最大堆性质等.

[读书笔记]算法(Sedgewick著)·第二章.初级排序算法

本章开始学习排序算法 1.初级排序算法 先从选择排序和插入排序这两个简单的算法开始学习排序算法.选择排序就是依次找到当前数组中最小的元素,将其和第一个元素交换位置,直到整个数组有序. 1 public static void sort(Comparable a[]){ 2 int N = a.length; 3 for(int i = 0; i < N; i ++){ 4 int min = i; //最小元素索引 5 for(int j = i + 1; j < N; j++){ 6 if(

算法手记(5)初级排序算法

排序是将一组对象按照一定的规则重新排列的过程.即使目前完全可以使用标准库中的排序函数,学习排序算法仍然有着较大意义:   排序算法的学习可以帮助你全面了解比较算法性能的方法: 类似的技术上能有效解决其他类型的问题: 排序算法通常是我们解决问题的第一步: 更重要的是这些算法都很经典,优雅和高效. 排序在商业数据处理分析和现代科学中占有重要的地位,其中快速排序算法被誉为20世纪科学和工程领域十大算法之一.今天我们要看的就是相对简单但很经典的初级排序算法,包括选择排序,插入排序及Shell排序. 准备

初级排序算法1-定义排序规则

初级排序算法-定义排序规则 排序就是将一组对象按照某种逻辑序列重新排列的过程. Table of contents 介绍 为什么学它 排序算法类的模板 验证 性能评估 介绍 现在计算机的广泛使用使得数据无处不在,而整理数据的第一步通常就是进行排序 所有的计算机都实现了各种排序算法以供系统和用户使用 为什么学它 即使你只是使用标准库中的排序算法,学习排序算法仍然有三大实际意义 对排序算法的分析将有助于你全面理解比较算法性能的方法 类似的技术也能有效解决其他类型的问题 排序算法常常是我们使用算法解决

初级排序算法之选择排序

初级排序算法 本质是对要排序的数组进行嵌套循环,内层循环负责局部的排序,外层循环负责剩余的无序元素的递减.所以你只要理解嵌套循环和比较大小就能很快的掌握初级排序算法. 选择排序 一个无序的数组 a = [0, 4, 6, 3, 8, 2, 3, 9], 你也可以把a的元素想象成任何现实中可比较的具体物体.例如,有10根长短不一的木条,我们如何对它们进行排序?一个最直接的思想,先拿出最短的放到最前面,在剩余的木条中再拿出最短的放在第二位...直到最后一根木条.从中我们可以看出,1. 我们需要再一次

排序算法之堆排序(Heapsort)解析

一.堆排序的优缺点(pros and cons) (还是简单的说说这个,毕竟没有必要浪费时间去理解一个糟糕的的算法) 优点: 堆排序的效率与快排.归并相同,都达到了基于比较的排序算法效率的峰值(时间复杂度为O(nlogn)) 除了高效之外,最大的亮点就是只需要O(1)的辅助空间了,既最高效率又最节省空间,只此一家了 堆排序效率相对稳定,不像快排在最坏情况下时间复杂度会变成O(n^2)),所以无论待排序序列是否有序,堆排序的效率都是O(nlogn)不变(注意这里的稳定特指平均时间复杂度=最坏时间复

排序算法: 堆排序法

一,使用堆排序法之前,需要了解堆的特性: 1,堆一般都用数组的方式来存储,堆分为“最大堆”和“最小堆”: 2,以“最大堆”为例: (1)一个节点最多有两个子节点,即左右节点,每个节点都是一个堆: (2)父节点的值不小于子节点的值: (3)一个i节点,其父节点为(i-1)/2,左节点(2*i+1),右节点(2*i+2) 一个最大堆例子: 数组 int a[]: 83 78 81 48 17 27 二,将一个数组形成堆(以最大堆为例) 数组a[]: 27 48 81 78 17 83 形成最大堆思路

算法(第4版)-2.1 初级排序算法

2.1.1 游戏规则 1. 排序成本模型:在研究排序算法时,我们需要计算比较和交换的数量.对于不交换元素的算法,我们会计算访问数组的次数. 2. · 原地排序算法:除了函数调用所需的栈和固定数目的实例变量之外无需额外内存的原地排序算法: · 其他排序算法:需要额外内存空间来储存另一份数组副本. 2.2.2 选择排序 public class Selection { public static void sort(Comparable[] a) { // 将a[]按升序排列 int N = a.l