1. 基本原理

堆排序就是利用堆的特性进行一个无序序列的排序工作。

堆的特点

堆分为最大堆和最小堆,其实就是完全二叉树

  1. 最大堆要求节点的元素都要不小于其孩子

  2. 最小堆要求节点元素都不大于其左右孩子

两者对左右孩子的大小关系不做任何要求,其实很好理解。

有了上面的定义,我们可以得知,处于最大堆的根节点的元素一定是这个堆中的最大值。

其实我们的堆排序算法就是抓住了堆的这一特点,每次都取堆顶的元素,将其放在序列最后面,然后将剩

余的元素重新调整为最大堆,依次类推,最终得到排序的序列。

基本思想

  1. 将初始待排序关键字序列(a1,a2,⋯,an)(a_1,a_2,\cdots, a_n)构建成大顶堆,此堆为初始的无序区

  2. 将堆顶元素a[1]a[1]与最后一个元素a[n]a[n]交换,此时得到新的无序区(a1,a2,⋯,an−1)(a_1,a_2,\cdots, a_{n-1})和新的有序区(an)(a_n)

  3. 由于交换后新的堆顶a[1]a[1]可能违反堆的性质,因此需要对当前无序区(a1,a2,⋯,an−1)(a_1,a_2,\cdots, a_{n-1})调整为新堆,然后再次将a[1]a[1]与无序区最后一个元素交换,得到新的无序区(a1,a2,⋯,an−2)(a_1,a_2,\cdots, a_{n-2})新的有序区(an−1,an−2)(a_{n-1},a_{n-2})。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

一个例子

这里有一个无序的序列,[16,7,3,20,17,8][16,7,3,20,17,8]

首先构造一个二叉树:

然后依据构造的二叉树,从下至上调整,得到一个初始化的最大堆。

再讲堆顶的数和堆底的数互换。

但是,此时的堆可能不符合要求,需要再从新调整:

再重复,将堆顶和堆底互换(当然了,在之前,堆的大小要减1)

又一次进行调整:

重复,将堆顶和堆底互换(当然了,在之前,堆的大小又要减1)

再调整:

再换:

再调整:

再换:

到这,一个堆排序就完成了,最终得到一个最小堆。

2. Python 实现

程序

#定义一个对单一节点的父节点以及其孩子大小交换的函数
def initialMaxHeap(a,startIndex,endIndex):leftChildIndex=2*startIndex+1 #父节点为i,左边孩子的位置为2*i+1#判断左边孩子是否有右边的孩子if leftChildIndex+1<=endIndex and a[leftChildIndex+1]>a[leftChildIndex]:leftChildIndex+=1       if a[leftChildIndex]>a[startIndex]:#左右孩子值大于父节点的值的时候,交换,使得这个二叉树的最大值位于父节点上temp=a[startIndex]a[startIndex]=a[leftChildIndex]def myHeapSort(a):#a是要排序的序列listLength=a.__len__()while True:if listLength==1:break;finalNodeHavingChild=(listLength)//2-1 #寻找最下一层的父节点#从下到上调整堆for i in range(finalNodeHavingChild,-1,-1):#print(a[i])initialMaxHeap(a,i,listLength-1)#将堆顶的数换到堆底temp=a[0]a[0]=a[listLength-1]a[listLength-1]=temp#这个调整之后,可能不满足最大堆的定义,需要再从上到下再调整一次#从上到下调整堆for j in range(0,finalNodeHavingChild+1):#print(a[j])initialMaxHeap(a,j,listLength-1)#将堆的数量减少listLength-=1return a    def generatingRandomNumber(sampleNumber,lower,upper):#sampleNumber :是生成的随机序列的长度#lower和upper分别是生成随机序列的下限与上限#最后,函数会返回一个随机的无序的序列a。import randoma=[]aSize=a.__len__()while 1:aSize=a.__len__()if aSize>=sampleNumber:breakelse:temp=int(random.randint(lower,upper))a.append(temp)return aif __name__=="__main__":a=generatingRandomNumber(20,1,100)print()print('the sequence before sorting is:\n')print(a)print()print('the sequence after sorting is:\n')print(myHeapSort(a))

结果为:

结果正确!!!

排序动态图

3. 时间复杂度分析

在构建堆(初始化大顶堆)的过程中,完全二叉树从最下层最右边的非终端结点开始构建,将它与其孩子进行比较和必要的互换,对于每个非终端结点来说,其实最多进行两次比较和一次互换操作,因此整个构建堆的时间复杂度为: O(n)O(n)。大概需进行 n2∗2=n\frac{n}{2} * 2 = n 次比较和 n2\frac{n}{2} 次交换。

在正式排序时,nn 个结点的完全二叉树的深度为⌊log2n⌋+1⌊log_2n⌋+1并且有 nn个数据则需要取 n−1n-1 次调整成大顶堆的操作,每次调整成大顶堆的时间复杂度为O(log2n)。因此,重建堆的时间复杂度可近似看做: O(nlog2n)O(nlog_2n)。

排序算法三:堆排序基本原理以及Python实现相关推荐

  1. 排序算法(五)——堆排序算法详解及Python实现

    本文目录 一.简介 二.算法介绍 三.代码实现 排序算法系列--相关文章 一.简介 堆排序(Heap Sort)算法,属于选择排序类,不稳定排序,时间复杂度O(nlogn). 堆排序由Floyd和Wi ...

  2. 3.图解排序算法(三)之堆排序

    作者: dreamcatcher-cx 出处: http://www.cnblogs.com/chengxiao/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在页面明显位 ...

  3. 十大排序算法之堆排序

    十大排序算法之堆排序 本文采用Java书写选择排序,其他语言类似可以借鉴着写 思想:所谓堆排序就是通过构造最大堆(升序)或者最小堆(降序)来进行排列的方法.可能有些童鞋不知道何为最大堆,何为最小堆.这 ...

  4. Java常见排序算法之堆排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  5. 排序算法之---堆排序(很重要的一个结构,新手入门必备)

    排序算法之---堆排序(很重要的一个结构,新手入门必备) 先来简单的介绍一下堆结构: 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlo ...

  6. 数据结构与算法:十大排序算法之堆排序

    数据结构与算法:十大排序算法之堆排序 堆排序可以说是选择排序的优化 package TopTenSortingAlgorithms;import java.util.Arrays; import ja ...

  7. 排序算法(6)堆排序

    排序算法(6)堆排序---选择排序的高级版 思想:利用数据结构堆的思想来排序,堆排序利用了大堆(或小堆)堆顶记录的关键字最大(或最小)这一特征,使得当前无序的序列中选择关键最大(或最小)的记录变得简单 ...

  8. 排序算法:堆排序(Python)

    思路:堆排序是指利用堆这种数据结构所设计的一种排序算法.堆积是一个近似完全二叉树的结构,即子结点的键值或索引总是小于(或者大于)它的父节点.将待排序的序列构造成一个最大堆,此时序列的最大值为根节点.依 ...

  9. 选择排序法python详解-Python选择排序算法(三)

    优化选择排序算法,大致思路是每次循环分别找到最大值和最小值,放到列表的头部和尾部 代码如下: #! coding:utf8 import random def select_sort(arr): fo ...

  10. pythonsort函数时间复杂度_合并排序算法——时间复杂度详解和python代码实现

    递归形式 递归形式是算法中常用到的一种构造思路.递归允许函数或过程对自身进行调用,是对算法中重复过程的高度概括,从本质层面进行刻画,避免算法书写中过多的嵌套循环和分支语法.因此,是对算法结构很大的简化 ...

最新文章

  1. R语言使用caret包对GBM模型进行参数调优实战:Model Training and Parameter Tuning
  2. MyBatis—insert语句返回主键和selectKey标签
  3. Day 20: 斯坦福CoreNLP —— 用Java给Twitter进行情感分析
  4. 麻省理工告诉我们男女配对的真相!
  5. android主动显示流程,Activity加载显示基本流程
  6. centos7.3 docker安装grafana
  7. linux如何结束音乐是什么函数,与音乐有关的linux命令
  8. tensorflow和python版本不一样_相比Tensorflow2和PyTorch,TensorFlow1.x版本有什么弊端?...
  9. 正则表达式学习笔记003--问号和加号的认识与应用
  10. css—left和margin-left的区别
  11. Vue:安装Vue Devtools调试工具简便方法解决Cannot find module webpack-cli,@vue-devtools/build-tools等
  12. 编程珠玑 第一部分 基础
  13. 图解 Cisco IOS 命名规范
  14. c语言开发 kdj,[转载]随机指标KDJ,及其MA、EMA、SMA、DMA介绍
  15. 成功解决ValueError: Only TF native optimizers are supported in Eager mode
  16. 安卓或苹果IOS的APP应用如何取名字?好的名字技巧?
  17. 电子邮件附件下载器简介
  18. C++成员变量指针和成员函数指针
  19. Taro跨端开发探索19——商城小程序确认订单页面开发
  20. r语言 C4.5 剪枝是用什么算法_推荐收藏 | 决策树,逻辑回归,PCA算法面经

热门文章

  1. ADF BC:创建绑定到业务组件的UI表
  2. Java中使用Map and Fold进行功能性编程
  3. Spring基于 XML 的声明式事务控制(配置方式)
  4. java索引序列_视图、序列、索引
  5. C语言边角料:结构体中指针类型的成员变量,它的类型重要吗?
  6. C语言 | 为什么写这三行代码
  7. android module中获取 app_Android组件化架构 - 4. 动态创建
  8. c程序怎么改为java程序_如何将Java程序的入口点更改为C签名?
  9. 4g的服务器mysql配置文件,服务器物理内存16G mysql数据库my.cnf配置及参数说明
  10. 支持nvme的linux_Linux nvme驱动初探