优先队列如何使用Python实现及海量数据中寻找K大数
优先队列如何使用Python实现及海量数据中寻找K大数
今天是2020.10.01,是个喜庆的日子,中秋和国庆同天贺。祝福祖国越来越好,祝福普天下的家庭幸福美满。今天,主要介绍一下数据结构中的优先队列(PriorityQueue)如何使用Python实现以及优先队列的应用之海量数据中如何寻找K大数。
什么是优先队列(取自百度百科)?
普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。通常采用堆数据结构来实现。通俗一些描述就是,出队的时候,元素按照优先级进行出队。
优先队列不再遵循先入先出的原则,而是分为两种情况:
最大优先队列,无论入队顺序,当前最大的元素优先出队。
最小优先队列,无论入队顺序,当前最小的元素优先出队。
比如有一个最大优先队列,它的最大元素是8,那么虽然元素8并不是队首元素,但出队的时候仍然让元素8首先出队:
要满足以上需求,利用线性数据结构并非不能实现,但是时间复杂度较高,最坏时间复杂度O(n),并不是最理想的方式。其实借助二叉堆可以大大降低时间复杂度。如下介绍。
二叉堆特性
最大堆的堆顶是整个堆中的最大元素
最小堆的堆顶是整个堆中的最小元素
因此,用最大堆来实现最大优先队列,每一次入队操作就是堆的插入操作,每一次出队操作就是删除堆顶节点。如下演示:
借助堆实现优先队列
入队操作(插入元素5):
(1) 首先将元素5插入到树的末尾
(2) 向上调整,找到5合适位置,使得满足大根堆
出队操作(删除根节点):
(1).把原堆顶节点10“出队”
(2).最后一个节点1替换到堆顶位置
(3).节点1下沉,节点9成为新堆顶
代码实现
# coding:utf-8
'''
普通队列:先进先出,插入在队尾,删除在队头
优先队列:优先队列具有最高级先出 (first in, largest out)的行为特征。通常采用堆数据结构来实现。
堆是完全二叉树
'''
class priorityQueue(object):
def __init__(self):
self.queue = []
def put(self,val):
# 向最小堆中插入元素,需要调整,直到满足最小堆的要求
self.queue.append(val)
cur = len(self.queue) - 1
while cur > 0:
parent = (cur - 1) // 2
if self.queue[parent] > self.queue[cur]:
self.queue[parent],self.queue[cur] = self.queue[cur],self.queue[parent]
else:
break
cur = parent
def get(self):
first = self.top()
last = self.queue.pop()
if not self.empty():
self.queue[0] = last
cur = 0
left = 2 * cur + 1
right = 2 * cur + 2
if left >= len(self.queue) or right >= len(self.queue):
break
if self.queue[cur] <= min(self.queue[left],self.queue[right]):
break
if self.queue[left] < self.queue[right]:
self.queue[left],self.queue[cur] = self.queue[cur],self.queue[left]
cur = left
else:
self.queue[right],self.queue[cur] = self.queue[cur],self.queue[right]
cur = right
return first
def find(self,val):
return val in self.queue
def getIndex(self,index):
if index >= len(self.queue):
raise Exception("The index is out of range!")
return self.queue[index]
def top(self):
# 取堆的根元素
if self.empty():
raise Exception("The Queue is Empty!")
return self.queue[0]
def empty(self):
return len(self.queue) == 0
海量数据中寻找K大数
借助python优先队列包来实现优先队列。时间复杂度为nlog(k).
# coding:utf-8
from queue import PriorityQueue
# 适合海量数据的o(nlogk)的方法
def heapFindNk(nums,k):
pq = PriorityQueue()
for num in nums:
pq.put(num)
if pq.qsize() > k:
pq.get()
res = []
while pq.qsize():
res.append(pq.get())
return res
nums = [4,5,1,2,0]
k = 2
print(heapFindNk(nums,k))
参考博客:
https://www.sohu.com/a/256022793_478315
https://baike.baidu.com/item/%E4%BC%98%E5%85%88%E9%98%9F%E5%88%97/9354754?fr=aladdin
优先队列如何使用Python实现及海量数据中寻找K大数相关教程
微服务架构环境下运维如何应对各种挑战
微服务架构环境下,运维如何应对各种挑战? 一. 微服务架构面临的挑战 1 微服务核心价值:3S 2 微服务架构带来的运维挑战 1)单服务流量激增时扩容 2)调用链条变长,调用关系更加复杂 3)微服务拆分导致故障点增多 ▼▼▼▼▼ 1)单服务变更性能影响如何评
如何用终端命令打开一个网址? 简简单单 - 快快乐乐
如何用终端命令打开一个网址? 简简单单 - 快快乐乐 如何用终端命令打开一个网址? 简简单单 - 快快乐乐 JERRY_Z. ~ 2020 / 10 / 1 转载请注明出处!?? 文章目录 如何用终端命令打开一个网址? 简简单单 - 快快乐乐 一、如何才能让终端识别一个命令 二、.exe
如何实现bilibili最新头部景深效果~炫酷
如何实现bilibili最新头部景深效果~炫酷 #如何实现bilibili最新头部景深效果~炫酷 最近烟雨仔注意到 B站 主页导航栏头部有个相当炫酷的交互效果, 类似于摄影里面的 小景深 , 除了聚焦的人物, 其他前景和背景都是模糊状态. 最炫酷的地方在于, 鼠标左右移动, 会
C#-运算符以及运算符的优先级
C#-运算符以及运算符的优先级 C#语言提供了3大类运算符 一元运算符:一个操作数,比如i++ 二元运算符:比如x+y 三元运算符:只有一个:“?:”。 点运算符 指定类型或命名空间的成员,如System.Console.WriteLine(“hello”); 圆括号运算符() (1)制定表
Spark(8) -- Spark的RDD创建
Spark(8) -- Spark的RDD创建 ?如何将数据封装到RDD集合中,主要有两种方式: 并行化本地集合(Driver Program中)和引用加载外部存储系统(如HDFS、Hive、HBase、Kafka、Elasticsearch等)数据集。 官方文档:resilient-distributed-datasets-rdds 1. RDD的创
如何理解 JS 异步编程的,EventLoop、消息队列,什么是宏任务,
如何理解 JS 异步编程的,EventLoop、消息队列,什么是宏任务,什么是微任务? JS 异步编程 JavaScript 语言的执行环境是单线程的,一次只能执行一个任务,多任务需要排队等候,这种模式可能会阻塞代码,导致代码执行效率低下。为了避免这个问题,出现了异步
ROS 学习踩坑笔记3-如何使用VScode IDE (安装+打开工作空间+Cma
ROS 学习踩坑笔记3-如何使用VScode IDE (安装+打开工作空间+Cmake编译+debug)- 持续更新 之前一直使用Roboware对ROS 的工作空间进行编辑,编译和测试,但是用于Roboware已经不再更新,因此近期转换到VScode这个IDE,发现还是很好用的,以下为VScode简略安装
Spring Boot第四弹,一文教你如何无感知切换日志框架?
Spring Boot第四弹,一文教你如何无感知切换日志框架? 前言 Spring Boot 版本 什么是日志门面? 如何做到无感知切换? 如何切换? 引入依赖 指定配置文件 日志如何配置? 总结 首先要感谢一下读者朋友们的支持,你们每一个的赞都是对陈某最大的肯定,陈某也