堆排序不稳定的例子_【译】Python中的堆排序

1d9e4534ff1e2bef41a4c765133fbe2d.png

作者:Olivera Popović

翻译:老齐

介绍

堆排序是高效排序算法的另一个例子,它的主要优点是,无论输入数据如何,它的最坏情况运行时间都是O(n*logn)。

顾名思义,堆排序在很大程度上依赖于堆数据结构——优先级队列的常见实现。

毫无疑问,堆排序是一种简单的排序算法,而且与其他简单实现相比,堆排序是更有效,也很常见。

堆排序

堆排序的工作原理是从堆逐个“移除”元素并将它们添加到已排序的数组里,在进一步解释和重新访问堆数据结构之前,我们应该了解堆排序本身的一些属性。

它是一种原地算法(译者注:in-place algorithm,多数翻译为“原地算法”,少数也翻译为“就地算法”。这种算法是使用小的、固定数量的额外内存空间来转换资料的算法。),意味着它需要恒定数量的内存,即所需内存不取决于初始数组本身的大小,而取决于存储该数组所需的内存。

例如,不需要原始数组的副本,也不需要递归和递归调用堆栈。最简单的堆排序实现通常使用第二个数组来存储排序后的值。我们将使用这种方法,因为它在代码中更直观、更易于实现,但它也是百分百的原地算法。

堆排序不稳定,意思是相等的值,并不会在同样的相对位次上。对于整数、字符串等这些基本类型,不会出现这类问题,但当我们对复杂类型的对象排序时,可能会遇到。

例如,假设我们有一个自定义类Person带有agename属性,在一个数组中几个此类的实例对象,比如按顺序出现19岁的名叫“Mike”的人和一个19岁的名叫“David”的人。

如果我们决定按年龄对这些人进行排序,就不能在排序数组中保证“Mike”会出现在“David”之前,即使他们在初始数组中是按这个顺序出现的。“Mike”有可能出现在“David”之前,但不能保证百分之百如此。

ef95a7f415380643c17b6a826db394fe.png

堆数据结构

堆是计算机科学中最流行和最常用的一种数据结构——更不用说在软件工程面试中非常流行了

我们将讨论跟踪最小元素(最小堆)的堆,但它们也可以很容易地实现对最大元素(最大堆)的跟踪。

简单地说,最小堆是一种基于树的数据结构,其中每个节点比其所有子节点都小。通常使用二叉树。堆有三个基本操作——delete_minimum()get_minimum()add()

每次,你只能删除堆中的第一个元素,然后对其进行“重新排序”。在添加或删除元素后,堆对自己会“重新排序”,以便最小的元素始终处于第一个位置。

注意:这绝不意味着堆是排序的数组。每个节点都小于其子节点这一事实不足以保证整个堆是按升序排列的。

我们来看一个关于堆的例子:

7fb5064b53c415d6d72cb9820c4d5b5f.png

正如我们看到的,上面的例子确实符合堆的描述,但是没有排序。我们不会详细讨论堆实现,因为这不是本文的重点。当在堆排序中使用堆数据结构时,我们所利用的堆数据结构的关键优势是:下一个最小的元素始终是堆中的第一个元素。

实现

数组排序

译者注: 作者在本文中并没有严格区分Python中的列表和数组,而是将列表看做了数组,这对于列表中的元素是同一种类型的元素而言,无可厚非。对于排序,只有是同一种类型的元素,才有意义。

Python提供了创建和使用堆的方法,所以我们不必自己单独为了实现它们去写代码了:

  • heappush(list, item):向堆中添加一个元素,然后对其重新排序,使其保持堆状态。可用于空列表。
  • heappop(list):删除第一个(最小的)元素并返回该元素。此操作之后,堆仍然是一个堆,因此我们不必调用heapify()
  • heapify(list):将给定的列表变成一个堆。

现在我们知道了这些,堆排序的实现就相当简单了:

from heapq import heappop, heappushdef heap_sort(array):heap = []for element in array:heappush(heap, element)ordered = []# While we have elements left in the heapwhile heap:ordered.append(heappop(heap))return orderedarray = [13, 21, 15, 5, 26, 4, 17, 18, 24, 2]
print(heap_sort(array))

输出

[2, 4, 5, 13, 15, 17, 18, 21, 24, 26]

如我们所见,堆数据结构的繁重工作已经完成,我们所要做的只是添加所需的所有元素并逐个删除它们。它就像一台硬币计数机,根据输入的硬币的价值对它们进行分类,然后我们可以取出它们。

自定义对象排序

当使用自定义类时,事情会变得更加复杂。通常,为了使用我们的排序算法,建议不要重写类中的比较运算符,而是建议重写该算法,以便使用lambda函数比较。

但是,由于我们的实现依赖于内置堆方法,因此不能在这里这样做。

Python确实提供了以下方法:

  • heapq.nlargest(*n*, *iterable*, *key=None*):返回一个列表,其中包含由iterable定义的数据集中的n个最大元素。
  • heapq.nsmallest(*n*, *iterable*, *key=None*):返回一个列表,其中包含由iterable定义的数据集中的n个最小元素。

我们可以使用它来简单地获取n = len(array)最大/最小元素,但是方法本身不使用堆排序,本质上等同于只调用sorted()方法。

我们留给自定义类的唯一解决方案是实际重写比较运算符。遗憾的是,这使我们局限于对每个类只能进行一种比较。在我们的示例中,我们被局限于按年份对Movie对象进行排序。

但是,它确实让我们演示了在自定义类上使用堆排序。我们来定义Movie类:

from heapq import heappop, heappushclass Movie:def __init__(self, title, year):self.title = titleself.year = yeardef __str__(self):return str.format("Title: {}, Year: {}", self.title, self.year)def __lt__(self, other):return self.year < other.yeardef __gt__(self, other):return other.__lt__(self)def __eq__(self, other):return self.year == other.yeardef __ne__(self, other):return not self.__eq__(other)

现在,让我们稍微修改一下heap_sort()函数:

def heap_sort(array):heap = []for element in array:heappush(heap, element)ordered = []while heap:ordered.append(heappop(heap))return ordered

最后,让我们实例化一些电影,将它们放入一个数组中,然后对它们进行排序:

movie1 = Movie("Citizen Kane", 1941)
movie2 = Movie("Back to the Future", 1985)
movie3 = Movie("Forrest Gump", 1994)
movie4 = Movie("The Silence of the Lambs", 1991);
movie5 = Movie("Gia", 1998)array = [movie1, movie2, movie3, movie4, movie5]for movie in heap_sort(array):print(movie)

输出:

Title: Citizen Kane, Year: 1941
Title: Back to the Future, Year: 1985
Title: The Silence of the Lambs, Year: 1991
Title: Forrest Gump, Year: 1994
Title: Gia, Year: 1998

30965d6e1a379606d7dc496a5ccb64b4.png

与其他排序算法的比较

堆排序被广泛使用,主要原因是它的可靠性,尽管它经常被运行良好的“快速排序”法所超越(译者注: 本文的微信公众号“老齐教室”以系列文章,介绍各种排序算法,并且用Python语言实现,敬请关注)。

堆排序的主要优点是时间复杂度上的O(n*logn)上限以及安全性。Linux内核开发人员给出了使用堆排序而不是快速排序的以下理由:

堆排序的平均排序时间和最坏排序时间均为O(n*logn),虽然qsort的平均速度快了20%,但不得不容忍O(n*n)的最坏可能情形和额外的内存支出,这使它不太适合在操作系统内核中使用。

此外,快速排序算法法在可预测的情况下表现不佳。并且,如果对内部实现有足够的了解,你可能会意识到它造成的安全风险(主要是DDoS攻击),因为不良的O(n^2)行为很容易被触发。

经常被用来与堆排序比较的另一种算法是归并排序算法(译者注: 本微信公众号也会刊发相关文章给予介绍,敬请关注),它们具有相同的时间复杂度。

归并排序的优点是稳定、可并行运算,而堆排序两者都做不到。

另一个注意事项是:即使复杂度相同,堆排序在大多数情况下也比归并排序慢,因为堆排序具有较大的常数因子。

然而,堆排序比归并排序更容易实现,因此当内存比速度更重要时,它是首选。

结论

正如我们所看到的,堆排序不像其他高效的通用算法那么流行,但是它的可预测行为(而不是不稳定的行为)使它成为一个很好的算法,适用于内存和安全性比稍快的运行速度更重要的场合。

实现和利用Python提供的内置功能是非常直观的,我们实际上要做的就是将元素放在一个堆中并取出它们,就像对待硬币计数器一样。

原文链接:https://stackabuse.com/heap-sort-in-python/

★ 关注微信公众号:老齐教室。读深度文章,得精湛技艺,享绚丽人生。

57d224ca7ca45950ead3f431a200f068.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/551771.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安卓手机备份_安卓手机数据备份与恢复方法汇总和操作详解

世界那么大&#xff0c;谢谢你来看我&#xff01;&#xff01;关注我你就是个网络、电脑、手机小达人每次使用电脑时&#xff0c;我们都会自觉的将重要的文件保存好并且备份起来防止丢失。那同样的&#xff0c;我们在使用手机时&#xff0c;也要养成手机备份的好习惯。今天就来…

mysql索引的使用及优化方法_MySQL中索引和优化的用法总结

1、什么是数据库中的索引&#xff1f;索引有什么作用&#xff1f;引入索引的目的是为了加快查询速度。如果数据量很大&#xff0c;大的查询要从硬盘加载数据到内存当中。2、InnoDB中的索引原理是怎么样的&#xff1f;InnoDB是MySQL的默认存储引擎,InnoDB有两种索引&#xff1a;…

苹果屏幕上的小圆点_苹果或明年部署miniLED屏幕 最早用在Macbook上

中关村在线消息&#xff1a;苹果将举行WWDC 2020开发者大会即将召开&#xff0c;昨日&#xff0c;业内人士手机晶片达人透露&#xff1a;“苹果明年即将在Macbook上与iPad导入Mini LED产品&#xff0c;效果非常非常的好。相关供应链都开始动了起来。”苹果明年即将在Macbook上与…

mysql默认字符集和排序_MySQL字符集和排序规则

MySQL在创建数据库是&#xff0c;需要设置数据库的字符集和排序规则&#xff0c;如图所示&#xff1a;我觉得这里有必要解释下字符集和排序规则这两个概念。字符集说到字符集&#xff0c;需要先提下字符、字符集和字符编码这几个词的含义。字符(Character)是各种文字和符号的总…

图形驱动程序和显卡驱动什么区别_以后你的手机也需要单独安装显卡驱动程序了...

在桌面平台制造商通常会定期发布显卡驱动优化和提高性能&#xff0c;对于多数用户来说安装显卡驱动应该是很平常的事。不过在智能手机方面还不需要安装额外的驱动程序&#xff0c;因为制造商通常会通过每年的安卓系统更新来发布新版驱动。有趣的是从明年开始我们的智能手机也要…

有向加权图 最大弱连通分支_开盘引来大涨,当下股市最大的风险是它?

何为昨天的大涨定性&#xff1f;昨天的大涨&#xff0c;上午的加权量能水平达到了2921亿元&#xff0c;一个非常健康的温和放量状态&#xff1b;下午的加权量能水平快速下降到2242亿元的水平&#xff0c;这是略高于五日均量的量能水平&#xff1b;大幅高开&#xff0c;集合竞价…

axure文本框提示文字_Axure教程:一个中继器实现密码验证

本文给大家介绍用一个中继器实现axure登录时账号密码验证效果&#xff0c;一起来看看~实现效果如下图&#xff1a;工具/原料&#xff1a;账号文本框密码文本框登录按钮中继器记录密码的文本标签(隐藏)提示框(隐藏)验证按钮(隐藏)方法/步骤步骤1设置中继器&#xff1a;新增列acc…

深度学习 autoencoder_笔记:李淼博士-基于模仿学习的机器人抓取与操控

说明&#xff1a;本文是Techbeat平台上李淼博士的讲座&#xff1a;“基于模仿学习的机器人抓取与操控”的总结笔记。原视频&#xff1a;TechBeat - 让AI大有可为​www.techbeat.net视频介绍&#xff1a;近四十年来&#xff0c;研究人员对机器人抓取的研究逐渐深入&#xff0c;涉…

linux临时挂载别的文件目录_linux基础05:linux系统目录有哪些?命令行界面如何切换目录?...

我们安装好linux系统后&#xff0c;linux系统也会像windows系统一样&#xff0c;自动生成很多的文件和目录&#xff0c;这些目录都包含了不同的含义。下面&#xff0c;我们就来介绍一下这些目录都代表着什么&#xff1f;以及&#xff0c;在命令行界面&#xff0c;我们如何在不同…

抽象方法可以有方法体_什么方法可以祛斑?祛斑的方法有哪些?

现在是一个看脸的时代&#xff0c;可能不那么准确&#xff0c;但是也说明了人们对于美好脸蛋的追求。完美的脸蛋必定是光滑白皙没有瑕疵的&#xff0c;而有了色斑就会损害整个人的颜值。祛斑的方法有哪些?若是您正深受长斑的烦恼&#xff0c;小编专门寻找了一些简单有效的祛斑…

炫界 (978) -(建工发现应用克隆漏)_除了DMA,这些漏损点检测与漏损区域识别技术你知道么?...

漏损问题在给水管网中是普遍存在且难以避免的。据《2018年城市供水统计年鉴》显示&#xff0c;载入年鉴的各城市在2017年的管网漏损总量超过60亿m3&#xff0c;平均漏损率为14.56%&#xff0c;这与“水十条”明确规定的控漏目标相比仍存有差距。与此同时&#xff0c;居高不下的…

go语言 mysql卡死_一次mysql死锁的排查过程-Go语言中文社区

一次mysql死锁的排查过程一、背景17号晚上要吃饭了&#xff0c;看旁边的妹子和佐哥还在调代码&#xff0c;就问了下什么问题啊&#xff0c;还在弄&#xff0c;妹子说&#xff0c;在测试环境测试给用户并发发送卡券时&#xff0c;出现了死锁&#xff0c;但看代码没有死锁&#x…

怎么格式化电脑_U盘格式化后数据能恢复吗?人人都能学会的恢复方法!

获取专业数据恢复软件&#xff1a;专注硬盘U盘误删文件数据恢复软件免费下载​dl-next.aunbox.cn数据恢复官网&#xff1a;嗨格式数据恢复大师官网 - 专业U盘/电脑/硬盘数据恢复软件_免费下载​huifu.hgs.cnU盘格式化后数据能恢复吗&#xff1f;U盘在我们生活中算是比较常用的数…

java 运算符_详解Java表达式与运算符

课程导言【变量的赋值与计算都离不开表达式&#xff0c;表达式的运算依赖于变量、常量和运算符。本节课讨论Java的表达式的构成、常量的定义、运算符的分类及应用。通过本课的学习你将掌握运用表达式和运算符完成变量赋值、条件判断、数学运算、逻辑运算等功能操作】在讲述课程…

将你一张表的值覆盖_精准度可达亚米级,山东“北斗一张网”向社会免费开放...

齐鲁晚报齐鲁壹点记者张阿凤通讯员苏彬8月21日&#xff0c;山东省北斗卫星导航定位基准站网(以下简称“北斗一张网”)推广应用座谈会在济南举行。“北斗一张网”自2019年8月建成后&#xff0c;现已免费向社会提供实时、动态、高精度的卫星导航定位基础服务&#xff0c;在自然资…

okhttp 工具类_日语学习工具推荐,小白必备!

有很多同学问我&#xff0c;有没有好用的日语学习工具&#xff1f;当然有啦~这些学习工具大概分为辞典类、翻译类、日语知识类等等。今天呢&#xff0c;在自身使用的工具里挑选了下面8个学习工具网站&#xff0c;适合各个学习阶段&#xff0c;从日语初级到精通&#xff0c;它们…

des和aes相比较有哪些特点_栓流气力输送相比较传统的高速气力输送方式而言,有哪些优势?...

南京翔瑞粉体&#xff1a;“气力输送”是指运用物料载体压缩空气&#xff08;或气体&#xff09;&#xff0c;将散装物料从一处输送到另一处的输送系统&#xff0c;与传统的输送机械相比&#xff0c;气力输送系统在输送过程中不易出现沾染粉尘、受潮、污损等现象&#xff0c;并…

32位java虚拟机_微软Java虚拟机-Microsoft VM32位下载V5.0.3805.0安装版-MicrosoftJavaVirtualMachine西西软件下载...

Microsoft VM32位是一款微软Java虚拟机(Microsoft Java Virtual Machine)&#xff0c;为IE浏览器提供Java支持。Microsoft VM for Java 是在由Microsoft开发类别 Servers Shareware 软件。安装在WinNT上之前必须打有 NT4 Service Pack 3 以上。安装检测检查是否已安装 Microsof…

iframe src 传参数_剧本杀测评|本友投稿——蜀山传(非剧透)

点击蓝字关注“我爱剧本杀”以下内容不会剧透请放心阅读本友投稿——《蜀山传》前言&#xff1a;这一次的“本友测评”真的是早早早早早鸟测评了&#xff0c;更加难得的是&#xff0c;这一次是曾经制作发行过《夜来香》的发行团队小本买卖和作者紧张齐聚南宁并亲自带本&#xf…

gnss单频软件接收机应用与编程_GNSS/GPS RTK定位 (手机,无人车定位,无人驾驶,因子图优化)...

Global navigation satellite system (GNSS)是手机或者无人车定位中的关键一个部分。GNSS是当前主要的可以提供绝对定位信息的一种信息来源。无人车的基于地图匹配定位的这一个部分中&#xff0c;GNSS经常用来提供初始化。就目前来看&#xff0c;GNSS的定位方式主要包括单点定位…