1. heapq堆排序算法

堆(heap)是一个树形数据结构,其中子节点与父节点有一种有序关系。二叉堆(binary heap)可以使用一个有组织的列表或数组表示,其中元素N的子元素位于2*N+1和2*N+2(索引从0开始)。这种布局允许原地重新组织堆,从而不必再添加或删除元素时重新分配大量内存。

最大堆(max-heap)确保父节点大于或等于其两个子节点。最小堆(min-heap)要求父节点小于或等于其子节点。Python的heapq模块实现了一个最小堆。

1.1 创建堆

创建堆有两种基本方式:heappush()和heapify()。

import heapq
import math
from io import StringIO data = [19, 9, 4, 10, 11] def show_tree(tree, total_width=36, fill=' '):
"""Pretty-print a tree."""
output = StringIO()
last_row = -1
for i, n in enumerate(tree):
if i:
row = int(math.floor(math.log(i + 1, 2)))
else:
row = 0
if row != last_row:
output.write('\n')
columns = 2 ** row
col_width = int(math.floor(total_width / columns))
output.write(str(n).center(col_width, fill))
last_row = row
print(output.getvalue())
print('-' * total_width)
print() heap = []
print('random :', data)
print() for n in data:
print('add {:>3}:'.format(n))
heapq.heappush(heap, n)
show_tree(heap)

使用heappush(),从数据源增加新元素时会保持元素的堆排序顺序。

如果数据已经在内存中,那么使用heapify()原地重新组织列表中的元素会更高效。

import heapq
import math
from io import StringIO data = [19, 9, 4, 10, 11] def show_tree(tree, total_width=36, fill=' '):
"""Pretty-print a tree."""
output = StringIO()
last_row = -1
for i, n in enumerate(tree):
if i:
row = int(math.floor(math.log(i + 1, 2)))
else:
row = 0
if row != last_row:
output.write('\n')
columns = 2 ** row
col_width = int(math.floor(total_width / columns))
output.write(str(n).center(col_width, fill))
last_row = row
print(output.getvalue())
print('-' * total_width)
print() print('random :', data)
heapq.heapify(data)
print('heapified :')
show_tree(data)

如果按堆顺序一次一个元素地构建列表,那么结果与构建一个无序列表再调用heapify()是一样的。

1.2 访问堆内容

一旦堆已经被正确组织,则可以使用heappop()删除有最小值的元素。

import heapq
import math
from io import StringIO data = [19, 9, 4, 10, 11] def show_tree(tree, total_width=36, fill=' '):
"""Pretty-print a tree."""
output = StringIO()
last_row = -1
for i, n in enumerate(tree):
if i:
row = int(math.floor(math.log(i + 1, 2)))
else:
row = 0
if row != last_row:
output.write('\n')
columns = 2 ** row
col_width = int(math.floor(total_width / columns))
output.write(str(n).center(col_width, fill))
last_row = row
print(output.getvalue())
print('-' * total_width)
print() print('random :', data)
heapq.heapify(data)
print('heapified :')
show_tree(data)
print() for i in range(2):
smallest = heapq.heappop(data)
print('pop {:>3}:'.format(smallest))
show_tree(data)

这个例子是由标准库文档改写的,其中使用heapify()和heappop()对一个数字队列进行排序。

如果希望在一个操作中删除现有元素并替换为新值,则可以使用heapreplace()。

import heapq
import math
from io import StringIO data = [19, 9, 4, 10, 11] def show_tree(tree, total_width=36, fill=' '):
"""Pretty-print a tree."""
output = StringIO()
last_row = -1
for i, n in enumerate(tree):
if i:
row = int(math.floor(math.log(i + 1, 2)))
else:
row = 0
if row != last_row:
output.write('\n')
columns = 2 ** row
col_width = int(math.floor(total_width / columns))
output.write(str(n).center(col_width, fill))
last_row = row
print(output.getvalue())
print('-' * total_width)
print() heapq.heapify(data)
print('start:')
show_tree(data) for n in [0, 13]:
smallest = heapq.heapreplace(data, n)
print('replace {:>2} with {:>2}:'.format(smallest, n))
show_tree(data)

通过原地替换元素,就这样可以维持一个固定大小的堆,如按优先级排序的作业队列。

1.3 堆的数据极值

heapq还包括两个检查可迭代对象(iterable)的函数,可以查找其中包含的最大或最小值的范围。

import heapq
import math
from io import StringIO data = [19, 9, 4, 10, 11] def show_tree(tree, total_width=36, fill=' '):
"""Pretty-print a tree."""
output = StringIO()
last_row = -1
for i, n in enumerate(tree):
if i:
row = int(math.floor(math.log(i + 1, 2)))
else:
row = 0
if row != last_row:
output.write('\n')
columns = 2 ** row
col_width = int(math.floor(total_width / columns))
output.write(str(n).center(col_width, fill))
last_row = row
print(output.getvalue())
print('-' * total_width)
print() print('all :', data)
print('3 largest :', heapq.nlargest(3, data))
print('from sort :', list(reversed(sorted(data)[-3:])))
print('3 smallest:', heapq.nsmallest(3, data))
print('from sort :', sorted(data)[:3])

只有当n值(n>1)相对小时使用nlargest()和nsmallest()才算高效,不过有些情况下这两个函数会很方便。

1.4 高效合并有序序列

对于小数据集,将多个有序序列合并到一个新序列很容易。

list(sorted(itertools.chain(*data)))

对于较大的数据集,这个技术可能会占用大量内存。merge()不是对整个合并后的序列排序,而是使用一个堆一次一个元素地生成一个新序列,利用固定大小的内存确定下一个元素。

import heapq
import random random.seed(2016) data = []
for i in range(4):
new_data = list(random.sample(range(1, 101), 5))
new_data.sort()
data.append(new_data) for i, d in enumerate(data):
print('{}: {}'.format(i, d)) print('\nMerged:')
for i in heapq.merge(*data):
print(i, end=' ')
print()

由于merge()的实现使用了一个堆,所以它会根据所合并的序列个数消耗内存,而不是根据这些序列中的元素个数。

Python3标准库:heapq堆排序算法的更多相关文章

  1. Python3 标准库

    Python3标准库 更详尽:http://blog.csdn.net/jurbo/article/details/52334345 文本 string:通用字符串操作 re:正则表达式操作 diff ...

  2. 8.Python3标准库--数据持久存储与交换

    ''' 持久存储数据以便长期使用包括两个方面:在对象的内存中表示和存储格式之间来回转换数据,以及处理转换后数据的存储区. 标准库包含很多模块可以处理不同情况下的这两个方面 有两个模块可以将对象转换为一 ...

  3. python023 Python3 标准库概览

    Python3 标准库概览 操作系统接口 os模块提供了不少与操作系统相关联的函数. >>> import os >>> os.getcwd() # 返回当前的工作 ...

  4. python3标准库总结

    Python3标准库 操作系统接口 os模块提供了不少与操作系统相关联的函数. ? 1 2 3 4 5 6 >>> import os >>> os.getcwd( ...

  5. 7.Python3标准库--文件系统

    ''' Python的标准库中包含大量工具,可以处理文件系统中的文件,构造和解析文件名,还可以检查文件内容. 处理文件的第一步是要确定处理的文件的名字.Python将文件名表示为简单的字符串,另外还提 ...

  6. 1.Python3标准库--前戏

    Python有一个很大的优势便是在于其拥有丰富的第三方库,可以解决很多很多问题.其实Python的标准库也是非常丰富的,今后我将介绍一下Python的标准库. 这个教程使用的书籍就叫做<Pyth ...

  7. 比较两个文件的异同Python3 标准库difflib 实现

    比较两个文件的异同Python3 标准库difflib 实现 对于要比较两个文件特别是配置文件的差异,这种需求很常见,如果用眼睛看,真是眼睛疼. 可以使用linux命令行工具diff a_file b ...

  8. 3.Python3标准库--数据结构

    (一)enum:枚举类型 import enum ''' enum模块定义了一个提供迭代和比较功能的枚举类型.可以用这个为值创建明确定义的符号,而不是使用字面量整数或字符串 ''' 1.创建枚举 im ...

  9. 读书分享全网学习资源大合集,推荐Python3标准库等五本书「02」

    0.前言 在此之前,我已经为准备学习python的小白同学们准备了轻量级但超无敌的python开发利器之visio studio code使用入门系列.详见 1.PYTHON开发利器之VS Code使 ...

随机推荐

  1. C# list中ConvertAll的使用

    static double TakeSquareRoot(int x) { //return Math.Sqrt(x); ; } static void Main(string[] args) { L ...

  2. 使用GoldenGate完成MySQL到MySQL的同步

    (一)基础环境配置   源库 目标库 操作系统版本 CentOS Linux release 7.4 CentOS Linux release 7.4 IP地址 192.168.10.11 192.1 ...

  3. 暑假第一周总结(在centos虚拟机上安装jdk以及hadoop并对hadoop进行配置)

    本周主要就是对虚拟机进行安装并在上边安装jdk以及hadoop并对其进行配置. 在看林子雨老师的教程时,下载了老师所给的全套的下载软件,在安装时发现老师所给的VirtualBox安装后无法正常启动,尝 ...

  4. Codeforces_807

    A. 严格按照题目给的两个条件来. #include<bits/stdc++.h> using namespace std; ],b[]; int main() { ios::sync_w ...

  5. WeChall_Training: Get Sourced (Training)

    The solution is hidden in this page Use View Sourcecode to get it 解题: 网页源码,最后一行 <!-- You are look ...

  6. JS中map与forEach的区别

    很多同学可能对于map与forEach的区别不是太了解,今天我们介绍一下JS中的map与forEach方法, 我对map的理解是,这个方法对一个数组arr1中的每一个元素进行遍历(传递给一个数组,参数 ...

  7. Head First设计模式分析学习

    永不放弃的毅力,和对欲望的控制. 注意:要能够理解相类似的设计模式之间的区别和不同.可以把类比列举出来,加深记忆. 是否加入Spring容器中的标准是是否要用到Spring框架的方法或者功能特性,如事 ...

  8. 《C# 爬虫 破境之道》:第二境 爬虫应用 — 第五节:小总结带来的优化与重构

    在上一节中,我们完成了一个简单的采集示例.本节呢,我们先来小结一下,这个示例可能存在的问题: 没有做异常处理 没有做反爬应对策略 没有做重试机制 没有做并发限制 …… 呃,看似平静的表面下还是隐藏着不 ...

  9. Hanoi塔问题——递归

    /////////////Hanoi塔问题///////#include<iostream>using namespace std;void hanoi(int i,char A,char ...

  10. CentOS 7 GNOME桌面系统 网络配置

    问题概述:在学习Linux系统的过程中,在WORKSTATION 14 PRO上安装了CentOS 7 Linux虚拟机,安装过程一切正常,但在应用过程中无法连接网络: 具体问题:1. 通过 ip a ...