排序六 堆排序

目录

  • 堆的概念
  • 要点
  • 算法分析
  • 堆排序算法的总体情况
  • 时间复杂度
  • 算法稳定性
  • 完整参考代码
  • JAVA版本
  • 参考资料
  • 相关阅读

堆的概念

在介绍堆排序之前,首先需要说明一下,堆是个什么玩意儿。

是一棵顺序存储完全二叉树

其中每个结点的关键字都不大于其孩子结点的关键字,这样的堆称为小根堆

其中每个结点的关键字都不小于其孩子结点的关键字,这样的堆称为大根堆

举例来说,对于n个元素的序列{R0, R1, ... , Rn}当且仅当满足下列关系之一时,称之为堆:

(1) Ri <= R2i+1 且 Ri <= R2i+2 (小根堆)

(2) Ri >= R2i+1 且 Ri >= R2i+2 (大根堆)

其中i=1,2,…,n/2向下取整;

如上图所示,序列R{3, 8, 15, 31, 25}是一个典型的小根堆。

堆中有两个父结点,元素3和元素8。

元素3在数组中以R[0]表示,它的左孩子结点是R[1],右孩子结点是R[2]。

元素8在数组中以R[1]表示,它的左孩子结点是R[3],右孩子结点是R[4],它的父结点是R[0]。可以看出,它们满足以下规律

设当前元素在数组中以R[i]表示,那么,

(1) 它的左孩子结点是:R[2*i+1];

(2) 它的右孩子结点是:R[2*i+2];

(3) 它的父结点是:R[(i-1)/2];

(4) R[i] <= R[2*i+1] 且 R[i] <= R[2i+2]。

要点

首先,按堆的定义将数组R[0..n]调整为堆(这个过程称为创建初始堆),交换R[0]和R[n];

然后,将R[0..n-1]调整为堆,交换R[0]和R[n-1];

如此反复,直到交换了R[0]和R[1]为止。

以上思想可归纳为两个操作:

(1)根据初始数组去构造初始堆(构建一个完全二叉树,保证所有的父结点都比它的孩子结点数值大)。

(2)每次交换第一个和最后一个元素,输出最后一个元素(最大值),然后把剩下元素重新调整为大根堆。

当输出完最后一个元素后,这个数组已经是按照从小到大的顺序排列了。

先通过详细的实例图来看一下,如何构建初始堆。

设有一个无序序列 { 1, 3, 4, 5, 2, 6, 9, 7, 8, 0 }。

构造了初始堆后,我们来看一下完整的堆排序处理:

还是针对前面提到的无序序列 { 1, 3, 4, 5, 2, 6, 9, 7, 8, 0 } 来加以说明。

相信,通过以上两幅图,应该能很直观的演示堆排序的操作处理。

核心代码

public void HeapAdjust(int[] array, int parent, int length) {
    int temp = array[parent]; // temp保存当前父节点
    int child = 2 * parent + 1; // 先获得左孩子
 
    while (child < length) {
        // 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
        if (child + 1 < length && array[child] < array[child + 1]) {
            child++;
        }
 
        // 如果父结点的值已经大于孩子结点的值,则直接结束
        if (temp >= array[child])
            break;
 
        // 把孩子结点的值赋给父结点
        array[parent] = array[child];
 
        // 选取孩子结点的左孩子结点,继续向下筛选
        parent = child;
        child = 2 * child + 1;
    }
 
    array[parent] = temp;
}
 
public void heapSort(int[] list) {
    // 循环建立初始堆
    for (int i = list.length / 2; i >= 0; i--) {
        HeapAdjust(list, i, list.length - 1);
    }
 
    // 进行n-1次循环,完成排序
    for (int i = list.length - 1; i > 0; i--) {
        // 最后一个元素和第一元素进行交换
        int temp = list[i];
        list[i] = list[0];
        list[0] = temp;
 
        // 筛选 R[0] 结点,得到i-1个结点的堆
        HeapAdjust(list, 0, i);
        System.out.format("第 %d 趟: \t", list.length - i);
        printPart(list, 0, list.length - 1);
    }
}

算法分析

堆排序算法的总体情况

排序类别

排序方法

时间复杂度

空间复杂度

稳定性

复杂性

平均情况

最坏情况

最好情况

选择排序

堆排序

O(nlog2n)

O(nlog2n)

O(nlog2n)

O(1)

不稳定

较复杂

时间复杂度

堆的存储表示是顺序的。因为堆所对应的二叉树为完全二叉树,而完全二叉树通常采用顺序存储方式。

当想得到一个序列中第k个最小的元素之前的部分排序序列,最好采用堆排序。

因为堆排序的时间复杂度是O(n+klog2n),若k≤n/log2n,则可得到的时间复杂度为O(n)

算法稳定性

堆排序是一种不稳定的排序方法。

因为在堆的调整过程中,关键字进行比较和交换所走的是该结点到叶子结点的一条路径,

因此对于相同的关键字就可能出现排在后面的关键字被交换到前面来的情况。

完整参考代码

JAVA版本

代码实现

以下范例是对上文提到的无序序列 { 1, 3, 4, 5, 2, 6, 9, 7, 8, 0 } 进行排序。

View Code


运行结果

排序前:    1   3   4   5   2   6   9   7   8   0  
第 1 趟:   8   7   6   5   2   1   4   3   0   9  
第 2 趟:   7   5   6   3   2   1   4   0   8   9  
第 3 趟:   6   5   4   3   2   1   0   7   8   9  
第 4 趟:   5   3   4   0   2   1   6   7   8   9  
第 5 趟:   4   3   1   0   2   5   6   7   8   9  
第 6 趟:   3   2   1   0   4   5   6   7   8   9  
第 7 趟:   2   0   1   3   4   5   6   7   8   9  
第 8 趟:   1   0   2   3   4   5   6   7   8   9  
第 9 趟:   0   1   2   3   4   5   6   7   8   9  
排序后:    0   1   2   3   4   5   6   7   8   9  

转载于:https://www.cnblogs.com/dd2hm/p/6882212.html

(转载)排序六 堆排序相关推荐

  1. 插入排序,希尔排序,堆排序

    本文将介绍三种排序算法--插入排序,希尔排序,堆排序.本文所有例子都是使用升序 一.插入排序 算法思想 维护一个有序数组,将要插入的数据与有序数组自最后一个元素直到合适位置的数一一比较. eg: 有序 ...

  2. 排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序...

    先推荐一篇关于排序算法的文章:http://www.cppblog.com/guogangj/archive/2009/11/13/100876.html 本文思路部分来源于上篇文章,但测得的结果似乎 ...

  3. 牛客网Java刷题知识点之插入排序(直接插入排序和希尔排序)、选择排序(直接选择排序和堆排序)、冒泡排序、快速排序、归并排序和基数排序(博主推荐)...

    不多说,直接上干货! 插入排序包括直接插入排序.希尔排序. 1.直接插入排序: 如何写成代码: 首先设定插入次数,即循环次数,for(int i=1;i<length;i++),1个数的那次不用 ...

  4. 七内部排序算法汇总(插入排序、Shell排序、冒泡排序、请选择类别、、高速分拣合并排序、堆排序)...

    写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的随意序列,又一次排列成一个按keyword有序的序列.因此排序掌握各种排序算法很重要. 对以下介绍的各个排序,我们假定全部排 ...

  5. 冒泡排序、插入排序、选择排序、希尔排序、堆排序、归并排序等常用排序算法的比较

    掌握好常用的排序算法,在实际的项目开发中可以节省很多的时间.每一种排序算法在执行的效率上是存在差别的,这些微小的时间差,也许在平常的联系当中感觉不到,但是涉及到数据量比较大或者是在资源比较紧张的系统中 ...

  6. 八大排序:冒泡排序、插入排序、希尔排序、选择排序、堆排序、归并排序、快速排序、基数排序

    [前言] 所有代码段都以升序为例,数组下标从0开始.排序的稳定性即:任意两个相等的数据,排序前后的相对位置不发生变化. [冒泡排序(Bubble Sort)] 它重复地访问过要排序的元素序列,依次比较 ...

  7. java中的排序算法——简单选择排序,树形选择排序与堆排序(一)

    package com.sort; /**  * 选择排序:  * 简单选择排序,树形选择排序与堆排序  *   */ public class SelecSortDemo { /** * ----- ...

  8. 数据结构之选择排序:堆排序

    选择排序:堆排序 思维导图: 堆的概念: 堆的初始化: 堆排序的算法思想: 堆排序代码实现: 堆排序的插入: 堆排序的删除: 堆排序的性能: 思维导图: 堆的概念: 根>=左右孩子节点的顺序存储 ...

  9. 排序算法之选择排序(简单选择排序、堆排序)

    选择排序(简单选择排序.堆排序) 选择排序 简单选择排序 概念 算法实现 堆排序 概念 算法实现 后续 选择排序 选择排序的基本思想是:每一趟在待排序元素中选取关键字最小(或最大)的元素加入有序子序列 ...

  10. 经典排序算法 - 堆排序Heap sort

    经典排序算法 - 堆排序Heap sort 堆排序有点小复杂,分成三块 第一块,什么是堆,什么是最大堆 第二块,怎么将堆调整为最大堆,这部分是重点 第三块,堆排序介绍 第一块,什么是堆,什么是最大堆 ...

最新文章

  1. php 正则第一个,为什么这个正则表达式与php中的第一个结果不匹配?
  2. android 拖动缩放窗口大小,Android小应用----图片的拖动、缩放
  3. redis单机安装并配置服务脚本启动
  4. VGGNet原理及tensorflow实现
  5. 计算机与体育教育的关系,试论现代信息技术与体育教育的关系论文.doc
  6. android自定义View之自定义可置顶ScrollView,View滑动原理简析
  7. 软件poc测试方案,华为fusioncloud桌面云解决方案5.3poc测试方案v1.0
  8. aria2 php,ac68u之aria2安装教程-新手摸索篇 - 52asus - 华硕网络设备技术交流平台
  9. HAU2022冬训营字符串1
  10. 解决 win10 桌面 资源管理器未响应
  11. 微信小程序—写字板、手写签名(高仿毛笔效果)让汉字引领世界
  12. cherry-pick多次
  13. Java 8: 元空间(Metaspace)
  14. 图书管理系统(Java语言)
  15. 冲刺阶段 - 项目管理ITTO及数据流向图
  16. 个人电商项目(mxcmall)的环境配置
  17. 上班能做什么副业?上班太闲做个什么副业?
  18. 细数Mac上那些好用且免费的软件(四)
  19. 杰理发射器用于做对讲机【篇】
  20. boss直聘自动招聘助手

热门文章

  1. LVS详解(五)——LVS NAT模式实战
  2. 在kali下对Windows 卷没有写权限的解决办法
  3. 五个步骤,搭建企业的“大数据视野”
  4. Lync server 2013新建持久聊天室提示用户未启用SIP
  5. keepalived高可用配置注意事项
  6. 【贪心】hdu5969 最大的位或
  7. cocos2dx 3.x 开发环境搭建
  8. Delphi 与 DirectX 之 DelphiX(94): TDIB.DrawAdditive();
  9. MainStoryboard.storyboard could not be opened
  10. 在RedHat5中实现透明代理