百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Python中heapq与优先队列「详细」

toyiye 2024-06-21 12:02 12 浏览 0 评论

今天的文章来介绍Python当中一个蛮有用的库——heapq


heapq的全写是heap queue,是堆队列的意思。这里的堆和队列都是数据结构,在后序的文章当中我们会详细介绍,今天只介绍heapq的用法,如果不了解heap和queue原理的同学可以忽略,我们并不会深入太多,会在之后的文章里详细阐述。


在介绍用法之前,我们需要先知道优先队列的定义。队列大家应该都不陌生,也是非常基础简单的数据结构。我们可以想象成队列里的所有元素排成一排,新的元素只能从队尾加入队列,元素要出队列只能通过队首,不能中途从队列当中退出


而优先队列呢,是给队列当中的元素每一个都设置了优先级,使得队伍当中的元素会自动按照优先级排序,优先级高的排在前面。


也就是说Python当中的heapq就是一个维护优先队列的library,我们通过调用它可以轻松实现优先队列的功能。


最大或最小的K个元素


我们来看一个实际的问题,假设我们当下有N个杂乱无章的元素,但是我们只关心其中最大的K个或者是最小的K个元素。我们想从整个数组当中将这部分抽取出来,应该怎么办呢?


这个问题在实际当中非常常见,随便就可以举出例子来。比如用户输入了搜索词,我们根据用户的搜索词找到了大量的内容。我们想要根据算法筛选出用户最有可能点击的文本来,机器学习的模型可以给每一个文本一个预测的分数。


之后,我们就需要选出分数最大的K个结果。这种类似的场景还有很多,利用heapq库里的nlargest和nsmallest接口可以非常方便地做到这点。


我们一起来看一个例子:



heapq的nlargest和nsmallest接受两个参数,第一个参数是K,也就是返回的元素的数量,第二个参数是传入的数组,heapq返回的正是传入的数组当中的前K大或者是前K小。


这里有一个问题,如果我们数组当中的元素是一个对象呢?应该怎么办?


其实也很简单,有了解过Python自定义关键词排序的同学应该知道,和排序一样,我们可以通过匿名函数实现。


匿名函数


我们都知道,在Python当中通过def可以定义一个函数。通过def定义的函数都有函数名,所以称为有名函数。除了有名函数之外,Python还支持匿名函数。顾名思义,就是没有函数名的函数。也就是说它其他方面都和普通函数一样,只不过没有名字而已。


初学者可能会纳闷,函数没有名字应该怎么调用呢


会有这个疑惑很正常,这是因为习惯了面向过程的编程,对面向对象理解不够深入导致的。在许多高级语言当中,一切皆对象,一个类,一个函数,一个int都是对象。既然函数也是对象,那么函数自然也可以用来传递,不仅可以用来传递,还可以用来返回。这是函数式编程的概念了,我们这里不多做深入。


当然,普通函数也一样可以传递,起到的效果一样。只不过在编程当中,有些函数我们只会使用一次,没必要再单独定义一个函数,使用匿名函数会非常方便。


举个例子,比方说我有一个这样的函数:



这个operate函数它接受两个参数,第一个参数是变量x,第二个参数是一个函数。它会在函数内部调用func,返回func调用的结果。我现在要做这样一件事情,我希望根据x这个整数对4取余的余数来判断应该用什么样的func。如果对4的余数为0,我希望求一次方,如果余数是2,我希望求平方,以此类推。如果按照正常的方法,我们需要实现4个方法,然后依次传递。


这当然是可以的,不过非常麻烦,如果使用匿名函数,就可以大大简化代码量:



在上面的代码当中,我们通过lambda关键字定义了匿名函数,避免了定义四种函数用来传递的情况。当然,这个问题还有更简单的写法,可以只用一个函数解决。


我们来看lambda定义匿名函数的语法,首先是lambda关键字,表示我们当下定义的是一个匿名函数。之后跟的是这个匿名函数的参数,我们只用到一个变量x,所以只需要写一个x。如果我们需要用到多个参数,通过逗号分隔,当然也可以不用参数。写完参数之后,我们用冒号分开,冒号后面写的是返回的结果。


我们也可以把匿名函数赋值给一个变量,之后我们就可以和调用普通函数一样来调用了:



自定义排序


回到之前的内容,如果我们想要heapq排序的是一个对象。那么heapq并不知道应该依据对象当中的哪个参数来作为排序的衡量标准,所以这个时候,需要我们自己定义一个获取关键字的函数,传递给heapq,这样才可以完成排序。


比如说,我们现在有一批电脑,我们希望heapq能够根据电脑的价格排序:



在调用nlargest和nsmallest的时候,我们额外传递了一个参数key,我们传入的是一个匿名函数,它返回的结果是这个对象的price,也就是说我们希望heapq根据对象的price来进行排序。


优先队列


heapq除了可以返回最大最小的K个数之外,还实现了优先队列的接口。我们可以直接调用heapq.heapify方法,输入一个数组,返回的结果是根据这个数组生成的堆(等价于优先队列)。


当然我们也可以从零开始,直接通过调用heapq的push和pop来维护这个堆。接下来,我们就通过heapq来自己动手实现一个优先队列,代码非常的简单,我想大家应该可以瞬间学会


首先是实现优先队列的部分:



其次我们来实际看一下运用的情况:



到这里,关于heapq的应用方面就算是介绍完了,但是还没有真正的结束。


我们需要分析一下heapq当中操作的复杂度,关于堆的部分我们暂时跳过,我们先来看nlargest和nsmallest。我在github当中找到了这个库的源码,在方法的注释上,作者写下了这个方法的复杂度,和排序之后取前K个开销五五开



我们都知道排序的复杂度的期望是 O(nlogn) ,如果你了解堆的话,会知道堆一次插入元素的复杂度是

O(logn)。如果我们限定堆的长度是K,我们插入n次之后也只能保留K个元素。每次插入的复杂度是

O(logK) ,一共插入n次,所以整体的复杂度是 O(nlogK)。


如果K小一些,可能开销会比排序稍小,但是程度有限。那么有没有什么办法可以不用排序并且尽可能快地筛选出前K大或者是前K小的元素呢?


我这里先卖个关子,我们之后的文章当中再来讲解。


今天的文章就到这里,如果觉得有所收获,请顺手点个关注或者转发吧,你的举手之劳对我很重要。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码