二十二 常见模块2(正则表达式及容器)

22.1 正则表达式及re模块

正则表达式(Regular Expression)用于描述一种字符串匹配模式(Pattern),它可以用于检查一个字符串是否含有某个子串,也可用于从字符串提取匹配的子串,或者对字符串中匹配的子串执行替换操作。

22.1.1 创建正则表达式

创建正则表达式的过程就是描述需要匹配字符串的过程,是一个模板,凡是符合此模板的字符串将被提取出来,所以创建正则表达式的过程就是创建一个特殊的字符串。

  1. 匹配符
    下表列出了创建正则表达式可以使用的合法字符。
匹配字符 解释
x 字符x(x可代表任意合法的字符
\uhhhh 十六进制值0xhhhh所代表的Unicode字符
\t 制表符(’\u0009’
\n 新行(换行)符(‘\u000A’)
\r 回车符(‘\u000D’)
\f 换页符(‘\u000C’)
\a 报警(bell)符(‘\u0007’)
\e Escape符(‘\u001B’)
\cx x对应的控制符。例如,\cM匹配Ctrl+M。x值必须为AZ或az之一
$ 匹配一行的结尾。匹配$本身,使用$
^ 匹配一行的开头。本身使用^
\A 只匹配字符串的开头
\Z 只匹配字符串的结尾,仅用于最后的结束符
. 匹配除换行符\n之外的任意单个字符,在使用re.S或s.DOTALL旗标后,可匹配换行符
\d 预定义字符,digit 默认匹配0~9的所有数字
\D 预定义字符,匹配非数字
\s 预定义字符,sapce 匹配所有空白字符,包括空格、制表符、回车符、换页符、换行符等
\S 预定义字符,匹配所有非空白符
\b 单词的边界,但只能匹配单词前后的空白
\B 非单词边界,只能匹配不在单词前后的空白
\w 预定义字符,word 匹配所有单词字符,包括0~9,26个字母和下划线
\W 预定义字符,所有非单词字符
了解了上面的匹配字符,我们就可以创建简单的正则表达式了。
r'\u0041\\' # 匹配A\
r'\u0061\t' #匹配a<制表符>
r'\?\[' #匹配?[

上面的正则表达式只是匹配单个字符,一旦我们需要匹配多个字符,不管字符是什么,只要部分字符匹配就可以,创建这样的正则表达式就要使用到通配符,可以匹配多个字符的特殊字符,他们被称为“预定义字符”。

r'c\wt'   # 匹配cat、cbt。。。;c0t,c1t...;c_t
r'\d\d\d-\d\d  # 匹配000-00格式,0可替换为0-9任意数字
  1. 功能符

正则表达式中的特殊字符(与匹配字符组合使用,具有特殊功能含义的字符):

特殊字符 解释
( ) 标记子表达式(也就是组)的开始位置与结束位置
[ ] 确定中括号表达式的开始与结束位置
{ } 标记前面子表达式的出现频率
* 指定前面子表达式可以出现0次或多次,等同于{0,}
+ 指定前面表达式可以出现一次或多次,等同于{1,}
指定前面子表达式可出现0次或1次,等同于{0,1}
| 指定两项之间任选一项
\ 转义字符或指定八进制、十六进制字符,前面的特殊字符如果想匹配本身,前面都要加\

下面具体讲解上表功能符的含义:

  • 【】表达式-定义匹配范围
    在一些特殊的情况下,例如只想匹配部分英文字符或中文字符,上面的预设定义字符就无能为力了,此时就需要使用方括号表达式。
方括号表达式 解释
枚举 例如[abc],表示a,b,c其中任意一个字符
范围 例如[a-f],可以与枚举结合,例如[a-cx-z]代表ac,xz范围内字符
^求否 [^abc] 除abc之外的任意字符;[^a-f]不是a~f范围内的任意字符

方括号表达式几乎可以匹配任意字符,例如,若需要匹配所有中文字符,就可以利用[\u0041-\u0056]的形式。

  • ()表达式-定义子表达式
    正则表达式支持圆括号表达式,用于将多个表达式组成一个子表达式,在圆括号中可以使用或运算符(|)。
子表达式用法 解释 示例
(exp) 匹配exp表达式并捕获成一个自动命名(\1,\2,…)的组,后面通过’\1’引用第一个捕获组所匹配的实际内容 r’Windows(95|98|NT|2000)[\w]+\1’ 说明:(95|98|NT|2000)为\1组,[\w ]匹配任意字符及空格;后面\1子表达式匹配到的字符串,例如在Windows 95 published in 95 中匹配,第一次匹配到了95,后面的\1代表95,其他在字符98,NT等都不行
(?Pexp),(?P=name) 捕获exp表达式,并使用name命名,后面通过(?P=name)引用前面捕获到的实际字符串 r’<(?P\w+)>\w+</(?P=tag)>可以匹配到<字符串1>任意字符<字符串1>注意<>内字符必须相同才能匹配到
(?:exp) 匹配exp,但不捕获,因此后面不能引用,即不能使用’\1’,但是可以正常匹配到字符串
(?<=exp) 表达式exp出现在匹配字符串的左侧,即捕获exp(不包括exp右侧的内容) re.search(r’(?<=<、h1>).+',‘help!<\h1><、div></、div></、h1>!technology’)可以匹配到’<、div></、div></、h1>!technology’>
(?=exp) 表达式exp出现在匹配字符串的右侧,即捕获exp(不包括exp左侧的内容) re.search(r’.+(?=</、h1>)','help!<、h1><、div></、div></、h1>!technology’)可以匹配到help!<、h1><、div></、div>
(?<!exp) (?<=exp)的逆向表达,exp模式不出现在匹配内容的左侧
(?!exp) (?=exp)的逆向表达,exp模式不出现在匹配内容的右侧
(?#comment) 注释组,?#后面的内容是注释,不影响表达式
(?aiLmaux) 旗标组,为整个正则表达式添加内旗标,可指定多个(旗标后续会讲解)
(?imsx:exp) 只对当前组起作用的旗标,只影响后面()内的子表达式,在已有旗标的情况下,使用(?-imsx)去除旗标 re.search(r’(?i:[a-z0-9_]){3,}@csdn.com’,‘Python@cadn.com’)匹配Python@cadn.com
(?-imsx:exp) 在已有旗标的情况下,使用(?-imsx)去除旗标 re.search(r’(?-i:[a-z0-9])',‘Abcd’,re.I)
匹配到’b’,旗标re.I指定不区分大小写,但是使用-i后,子表达式区分了大小写
  • {}表达式-定义出现频率
频率限定用法 解释 示例
* 等价 {0,} 前面子表达式可出现0~N次 r’zo*'可匹配:z、zo、zoo等
+等价{1,} 前面子表达式出现1~N次 r’zo+'匹配:zo、zoo、zooo等
? 等价{0,1} 前面子表达式出现0~1次 r’zo?'匹配:z、zo
{n,m}非负整数,n<=m 前面子表达式出现n~m次 r’fo{1,3}d’匹配:fod、food、foood
{n,} 子表达式至少出现n次 r’fo{2,}d’匹配:food、foood等
{,m} 子表达式至多出现m次 r’fo{3,}d’匹配:fd、fod、food、foood
{n} 子表达式只能出现n次 r’fo{2}d’匹配:food
  • 贪婪模式及勉强模式
    所谓贪婪模式,就是正则表达式尽可能多匹配字符,Python默认使用贪婪模式。例如:
re.search(r'.+\.','https://editor.csdn.net/')
输出:
<re.Match object; span=(0, 20), match='https://editor.csdn.'>
# 已最后面一个.作为结束标识

与贪婪模式相反,勉强模式尽可能少的匹配字符,使用?表示。例如:

re.search(r'.+?\.','https://editor.csdn.net/')
输出:
<re.Match object; span=(0, 15), match='https://editor.'>
# 已第一个.作为结束标识

22.1.2 re模块

>>> import re
>>> re.__all__
['match', 'fullmatch', 'search', 'sub', 'subn', 'split', 'findall', 'finditer', 'compile','purge', 'template', 'escape', 'error', 'Pattern', 'Match', 'A', 'I', 'L', 'M', 'S', 'X', 'U', 'ASCII', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL', 'VERBOSE', 'UNICODE']
>>>

20.1.2.1 旗标

Python支持的正则表达式旗标,实际上是re模块中的属性AILMSXU,旗标主要用于控制整个正则表达式需要遵循的规则及可以使用的匹配符。

旗标 解释
re.A或re.ASCII或(?a:exp) 控制\w,\W,\b,\B,\d,\D,\s,\S只匹配ASCII码
re.I或re.IGNORECASE或(?i:exp) 匹配不区分大小写
re.L或re.LOCALE或(?L:exp) 只对bytes模式起作用,根据当前区域设置,匹配时不区分大小写
re.M或re.MULTILINE或(?m) 多行模式旗标,可以匹配到^,$
re.S或re.DOTALL或(?s) 让点(.)可以匹配包括换行符在内的所有字符
re.U或re.UNICODE 控制\w,\W,\b,\B,\d,\D,\s,\S能匹配所有Unicode码
re.X或re.VERBOSE或(?x) 允许分行书写正则表达式

20.1.2.2 re模块函数

  1. re.compile(pattern,flags=0)
    将正则表达式字符串编译成_sre.SRE_Pattern对象(内存中的对象),可以缓存并复用正则表达式字符串。
    pattern:正则表达式
    flags:旗标
    _sre.SRE_Pattern对象包含了re模块中绝大部分函数对应的方法。
pa = re.compile(r'(?<=<(?P<tag>h1)>).+(?=</(?P=tag)>)')
>>> [e for e in dir(pa) if not e.startswith('_')]
['findall', 'finditer', 'flags', 'fullmatch', 'groupindex', 'groups', 'match', 'pattern',
'scanner', 'search', 'split', 'sub', 'subn']
import re
# 被匹配字符串定义
test = 'abc<h1>  xyz</h1>def'
# 编译的到正则表达式对象
pa = re.compile(r'(?<=<?P<tag>h1)>)[\w ]+(?=</(?P=tag)>)')
# _sre.SRE_Pattern对象的match方法,match方法从开头位置匹配,因此需要指定开始位置,才能匹配到,本例从位置7开始。
pa.match(test,7) #输出<re.Match object; span=(7, 12), match=' xyz '>
pa.match(test)  #匹配为空
# 指定开始位置与结束位置
pa.match(test,7,10)  #匹配空
pa.match(test,7,len(test))  #输出<re.Match object; span=(7, 12), match=' xyz '>
# 使用match().span()方法,
pa.match(test,7).span()    #输出 (7, 12)
# 使用全匹配fullmatch()方法
pa.fullmatch(test,7,16)
  1. match()与search()
    match()尝试从字符串开始位置匹配正则表达式,如果从开始位置匹配不成功,match()返回None。
    search()扫描整个字符串,并返回第一处匹配对象。
re.match(pattern,string,flags=0)
re.search(pattern,string,flags=0)
pattern:正则表达式
string:被匹配字符串
flags:匹配旗标
返回_sre.SRE_Match对象。

re模块中的match函数不能指定起始及结束位置,但是_sre.SRE_Pattern对象可以。

这两个函数只返回第一处匹配对象,返回的是_sre.SRE_Match对象。
该对象包含以下方法与属性:

  • match.group([group1,…]):获取该对象中指定组所匹配的字符串
  • match.__fetitem–(g):match.group(g)的简写方法,可以是用match[g]替代match.group(g)
  • match.groups(default=None):返回match对象中所有组所匹配的字符串组成的元组
  • match.groupdict(default=None):返回match对象中所有组所匹配的字符串组成的字典,前提条件是已经使用(?Ppattern)为改组指定了名字。
  • match.start([group]):获取该匹配对象中指定组所匹配的字符串的开始位置
  • match.end([group]):获取该匹配对象中指定组所匹配的字符串的结束位置
  • match.span([group]):获取该匹配对象中指定组所匹配的字符串的开始和结束位置
    组的概念对应前面讲过的(子表达式),组在正则表达式中很常见,例如下面的程序示例:
import re
# 注意第二组+号前面的转义字符,不能漏掉
m = re.search(r'(Python).+(C\+\+)',r'Python.C++是很好的语言,C++也是')
print(m.group(0))
>>> m.group(0)
'Python是很好的语言,C++'
>>> m[0]   #此方法与上面相同
'Python是很好的语言,C++'
>>> m[1]
'Python'
>>> m.span(0)
(0, 16)
>>> m.groups()
('Python', 'C++')

下面几个是_sre.SRE_Match()对象的几个属性:

  • match.pos:返回正则表达式传给search(),match()方法的pos参数
  • match.endpos:返回正则表达式传给search(),match()方法的endpos参数
  • match.lastgroup:返回最后一个匹配的捕获组的整数索引。
  • match.re:返回正则表达式
  • match.string:返回被匹配字符串
  1. findall()与finditer()
re.findall(pattern,string,flags=0)

findall()扫描整个字符串,并返回字符串中所有匹配的子串子串组成的–列表

re.finditer(pattern,string,flags=0)

finditer()扫面整个字符串,并返回字符串中所有匹配的子串子串组成的–迭代器–,迭代器的元素是_sre.SRE_Match对象。

两个函数功能类似,只是返回值不同,

  1. fullmatch()
re.fullmatch(pattern,string,flags=0)

fullmatch()函数要求整个字符串能匹配pattern,如果匹配则返回_sre.SRE_Match对象,否则返回None

  1. re.sub()
re.sub(pattern,repl,string,count=0,flags=0)
repl-替换字符或函数
count-控制最多替换多少次,如果指定默认0,表示全部替换

re.sub()函数将所有匹配的对象替换为repl。

import re
test = '2022-7-16'
print(re.sub(r'-','/',test)  #2022/7/16
print(re.sub(r'-','/',test,1)   #2022/7-16

repl也可以是函数形式,例如下面的示例:

# 定义替换函数
def fun(matched):#传入的matched就是匹配对象,通过该对象的group()方法可以获取被匹配的字符value = "学习”+(matched.group('lang'))+"语言"return value
s = 'Python很好,C也很好'
#使用re.A旗标,只匹配ASCII码
print(re.sub(r'(?P<lang>\w+)',s,fun,flags=re.A))
# 学习Python语言很好,学习C语言也很好
  1. re.split()
re.split(pattern,string,maxsplit=0,flags=0)
maxsplit-最多分割次数

re.split()函数的作用是使用pattern对string进行分割,返回分割得到的多个子串组成的数组。

  1. re.purge() :清楚正则表达式缓存
  2. re.escape()
    对模式中除ASCII字符、数值、下划线之外的其他字符进行转义。
re.escape(string)
import re
print(re.escape(r'Python-C-C++都是很好的语言_1'))
# Python\-C\-C\+\+都是很好的语言_1

22.2 容器

绝大部门编程元会提供4种主流的数据结构:list,set,dict(dictionary或map),deque。

22.2.1 复杂容器结构

22.2.1.1 set与frozenset

前面我们已经讲解了set,现在我们来回顾以下set的特点:

  • 不记录元素添加顺序
  • 不允许重复

set集合是可变容器,即可以改变set内元素,而frozenset是不可变的。

>>> [e for e in dir(set) if not e.startswith('_')]
['add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection',
'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove',
'symmetric_difference', 'symmetric_difference_update', 'union', 'update']

方法名称已经暗示了方法的功能,此处不在细诉,只是给出示例:

#使用{}构建set集合
>>> c = {'唐僧'}
>>> c.add('孙悟空')
>>> c.add(6)
>>> print(c)
{'孙悟空', '唐僧', 6}
>>> c.remove(6)
>>> print(c)
{'孙悟空', '唐僧'}
>>> print('c中是否包含孙悟空:',("孙悟空" in c))
c中是否包含孙悟空: True
>>> languages = set()
>>> languages.add('Java')
>>> print("判断languages是否是c的子集:",languages.issubset(c))
判断languages是否是c的子集: False
>>> print("判断是否是父集合:",c.issuperset(languages))
判断是否是父集合: False
>>> result1 = c-languages
>>> print(result1)
{'孙悟空', '唐僧'}
>>> #difference()方法的功能也是’-‘
>>> result2 = c.difference(languages)
>>> print(result2)
{'孙悟空', '唐僧'}
>>> c.clear()
>>> d = {'Java','C','Python','C'}
>>> #计算交集
>>> inter1 = d&languages
>>> print(inter1)
{'Java'}
>>> #intersection()方法与&完全相同
>>> inter2 = d.intersection(languages)
>>> print(inter2)
{'Java'}
>>> # intersection_update()方法计算交集的同时,改变集合
>>> d.intersection_update(languages)
>>> print(d)
{'Java'}
>>> #使用range()函数创建集合
>>> e = set(range(3,7))
>>> print(e)
{3, 4, 5, 6}
>>> #异或计算
>>> f = set(range(5))
>>> xor = e^f
>>> print(xor)
{0, 1, 2, 5, 6}
>>> #并集计算
>>> un = e.union(f)
>>> print(un)
{0, 1, 2, 3, 4, 5, 6}
>>> #计算并集,并更新
>>> e.update(f)
>>> print(e)
{0, 1, 2, 3, 4, 5, 6}

frozenset是set的不可变版本,因此set集合中所有能改变集合本身的方法(如:add、remove、discard、xxx_update等)frozenset都不支持。

[e for e in dir(frozenset) if not e.startswith('_')]
['copy', 'difference', 'intersection', 'isdisjoint', 'issubset', 'issuperset',
'symmetric_difference', 'union']

22.2.1.2 双端队列(deque)

在‘数据结构’课程中最常出现的数据结构有:栈、队列、双端队列。

  • 栈:一种特殊的线性表,只允许一端进行插入、删除操作,可操作端被称为栈顶(top),另一端为栈底(bottom)。它就像一个瓶子,只能从瓶口取放东西。放入元素被称为‘入栈’(push),取东西称为“出栈”(pop),是一种后入先出(LIFO)的结构。
  • 队列:与栈类似,只不过队列是两端开口,就像一个只允许单人通过的长廊,一端出口(front),一端入口(rear),先进去的人(元素)可以先通过,是先进先出(FIFO)结构。
  • 双端队列(deque):也是一种线性结构,有双端,与队列不同的是双端都可以进出。

22.2.2 collections包

22.2.2.1 deque

deque位于collection包下。

>>> from collections import deque
>>> [e for e in dir(deque) if not e.startswith('_')]
['append', 'appendleft', 'clear', 'copy', 'count', 'extend', 'extendleft', 'index',
'insert', 'maxlen', 'pop', 'popleft', 'remove', 'reverse', 'rotate']

可以看到deque的方法都是有两个,正是体现了双端结构,左边(left)相当于队列头(front),右边(right)相当于队尾(rear)。

  • append()和appendleft():队列右边或左边插入元素。
  • pop()和popleft():右侧或左侧弹出元素。
  • extend()和extendleft():右侧或左侧添加多个元素
  • clear() :清空队列
  • insert():在指定位置插入元素。
    只是用单侧的方法操作双端队列,双端队列就变成栈,一端添加元素,一端弹出,双端队列就变成了队列。
  • rotate():将队列的队尾元素移动到对头,使之首尾相连。
from collections import deque
q = deque(range(5))
print('q中的元素:',q)    #q中的元素:deque([0,1,2,3,4])
q.rotary()
print('q中的元素:',q)     #q中的元素:deque([4,0,1,2,3])
q.rotary()
print('q中的元素:',q)     #q中的元素:deque([3,4,0,1,2])

22.2.2.2 ChainMap对象

collections包下的ChainMap是一个工具类。
ChainMap将多个dict’链‘成一个大的dict,方便取用。但是ChainMap并未真正合并他们,因此各个不同的dict可以有相同的key,此时前面的dict中的key具有更高的优先使用级。

22.2.2.3 Counter对象

collections包下的counter是一个很有用的工具类。
用于自动统计容器中各元素出现的次数。
Counter的本质是一个特殊的dict,它的key是其所包含的元素,而它的value则记录了该key出现的次数。
程序可以通过任何可迭代对象参数来创建Counter对象,也可以以dict为参数来构建Counter对象,还能通过关键字参数来构建Counter对象。

from collections import Counter
c1 = Counter()
>>> c2 = Counter('python')
>>> print(c2)
Counter({'p': 1, 'y': 1, 't': 1, 'h': 1, 'o': 1, 'n': 1})
>>> c3 = Counter({'red':4,'blue':2})
>>> print(c3)
Counter({'red': 4, 'blue': 2})

事实上Counter对象继承了dict类,因此它玩侵权可以调用dict所支持的方法,此外,Counter对象还提供了如下三个常用方法:

  • elements():该方法返回该Counter中所包含的全部元素组成的迭代器
  • most_common([n]):该方法返回Counter中出现最大多的n各元素
  • subtract([iterable-or-mapping]):该方法计算counter的减法,其实就是计算减去之后各元素出现的次数。
    此外,还支持两个Counter对象之间的加、减、交、并、求正、求负操作。
  • 加:将两个Counter对象中各key出现的次数相加,且只保留出现次数为正的元素
  • 减:将两个Counter对象中各key出现的次数相减,且只保留出现次数为正的元素
  • 交:取两个Counter对象中都出现的key且各key对应的次数的最小数
  • 并:取两个Counter对象中key对应的次数的最大数
  • 求正:只保留Counter中出现次数为0或正的键值对
  • 求负:只保留Counter中出现次数为负的键值对,并将次数改为正数
>>> from collections import Counter
>>> c = Counter(Python=4,C=1,Java=3,JS=-2)
>>> print(sum(c.values()))
6
>>> print(list(c))
['Python', 'C', 'Java', 'JS']
>>> print(dict(c))
{'Python': 4, 'C': 1, 'Java': 3, 'JS': -2}
>>> print(c.items())
dict_items([('Python', 4), ('C', 1), ('Java', 3), ('JS', -2)])
>>> c2 = Counter(c.items())
>>> print(c2)
Counter({('Python', 4): 1, ('C', 1): 1, ('Java', 3): 1, ('JS', -2): 1})
>>> c3 = dict(c.items())
>>> c4 = Counter(c3)
>>> print(c4)
Counter({'Python': 4, 'Java': 3, 'C': 1, 'JS': -2})
>>> # 获取c4中最少出现的d三个元素
>>> print(c4.most_common()[:-4:-1])
[('JS', -2), ('C', 1), ('Java', 3)]
>>> #清空
>>> c4.clear()
>>> c.clear()
>>> c = Counter(a=3,b=1,c=-1)
>>> d = Counter(a=1,b=-2,d=3)
>>> print(c+d)
Counter({'a': 4, 'd': 3})

22.2.2.4 defaultdict对象

collections中的default对象是dict的子类,支持dict的功能,区别在于:如果程序试图根据不存在的key来访问dict,会引发KeyError异常,而default则可以提供一个default_factory属性,该属性所指定的函数负责为不存在的key生成value。

22.2.2.5namedtuple工厂函数

namedtuple()是一个工厂函数,使用该函数可以创建一个tuple类的子类,该子类可以为tuple的每个元素指定字段名,这样程序就可以根据字段名来访问namedtuple的各元素了,当然,如果有需要,程序依然可以根据索引来访问namedtuple。

namedtuple(typename,field_name,*,verbose=False,rename=False,module=None)
typename:指定所创建的tuple子类的类名,相当于用户定义了一个新类
field_names:该参数是一个字符串序列,如['x','y']或'x y';'x,y'
rename:如果该参数为Ture,那么无效的字段名将被自动替换为位置名,例如['abc','def','ghi','abc']将被替换为['abc','_1','ghi',;'_3'],这是因为def是关键字,abc命名重复
verbose:如果该参数为Ture,那么当该子类被创建之后,该类定义就会被立即打印出来。
module:如果设置了该参数,那么该类将位于该模块下,因此该自定义类的module属性将被设为该参数值

22.2.2.6 OrderedDict

OrderedDict也是dict的子类,它可以“维护”添加ket-value对的顺序。先添加的在前,后添加的在后,由于OrderedDict有顺序限制,因此即使两个对象的键值对相同,只要顺序不同,他们依然是不相等的。

  • popitem(last=True):默认弹出最后的key-value对,如果last=False,则弹出最先的键值对
  • move_to_end(key,last=Ture):默认将指定的key-value移动到最右(最后加入),如果last=False,则移动到最左(最先加入)

22.2.3 堆操作及heapq包

Python提供了关于堆的操作,先来了解一下堆的概念:
假设有n个数据元素的序列:k(0),k(1),…k(n-1),将此序列排列成完全二叉树,就是第一层有一个元素,然后每个元素发散出两个树枝(延申出两个元素),以此类推。结构如下图:

  • 小顶堆(小根堆)
    满足k(i)<=k(2i+2)且k(i)<=k(2i+2)(其中i=0,2,4,…,(n-1)/2),即完全二叉树的每个树顶元素小于等于分支。
  • 大顶堆(大根堆)
    满足k(i)>=k(2i+2)且k(i)>=k(2i+2)(其中i=0,2,4,…,(n-1)/2),即完全二叉树的每个树顶元素大于等于分支。

Python提供的是基于小顶堆的操作,当使用heapq包中的一些函数操作列表时,列表就表现出“堆”的行为。

>>> import heapq
>>> heapq.__all__
['heappush', 'heappop', 'heapify', 'heapreplace', 'merge', 'nlargest', 'nsmallest',
'heappushpop']
  • heappush(heap,item):将item元素加入堆
  • heappop(heap):将堆中最小元素弹出,即弹出堆顶
  • heaoify(heap):将堆属性应用到列表上
  • heapreplace(heap,x):将队中最小元素弹出,并将元素x入堆
  • merge(*iterables,key=None,reverse=False):将多个有序的堆合并成一个大的有序堆,然后在输出
  • heappushpop(heap,item):将item入堆,然后弹出并返回队中最小元素
  • nlargest(n,iterable,key=None):返回堆中最大的n个元素。
  • namallest(n,iterable,key=None):返回堆中最小的n个元素
>>> import heapq
>>> heapq.__all__
['heappush', 'heappop', 'heapify', 'heapreplace', 'merge', 'nlargest', 'nsmallest', 'heappushpop']
>>> from heapq import *
>>> my_data = list(range(10))
>>> my_data.append(0.5)
>>> print('my_data的元素:',my_data)
my_data的元素: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0.5]
>>> heapify(my_data)
>>> print('应用堆之后my_data的元素:',my_data)
应用堆之后my_data的元素: [0, 0.5, 2, 3, 1, 5, 6, 7, 8, 9, 4]
>>> heappush(my_data,7.2)
>>> print('添加7.2之后my_data的元素:',my_data)
添加7.2之后my_data的元素: [0, 0.5, 2, 3, 1, 5, 6, 7, 8, 9, 4, 7.2]
>>> my_data.append(8.3)
>>> print(my_data)
[0, 0.5, 2, 3, 1, 5, 6, 7, 8, 9, 4, 7.2, 8.3]
>>> my_data.append(0.3)  #依然可以使用append方法
>>> print(my_data)      #但是输出已经不是最小堆排序
[0, 0.5, 2, 3, 1, 5, 6, 7, 8, 9, 4, 7.2, 8.3, 0.3]
>>> print(heappop(my_data))  #可以弹出序列中的最小值
0

heapq包的主要功能是构建小顶堆,然后获取最大最小的n个值。

Python入门(二十二)- 常见模块2(正则表达式及容器)相关推荐

  1. 多态(Python入门三十二)

    面向对象的三大特征之一(多态) - 多态是面向对象的三大特征之一        多态从字面上理解是多种形态        狗(狼狗.藏獒.哈士奇.古牧 ...)        一个对象可以以不同的形态 ...

  2. Python入门(二十一)- 常见模块

    二十一.常见模块 上一章介绍了Python模块的相关知识,在实际开发中,Python的很多功能都已经有了成熟的第三方实现,一般不需要开发者"重复造轮子",当开发者需要完成某种功能时 ...

  3. Reflex WMS入门系列二十二:物料库存报表

    Reflex WMS入门系列二十二:物料库存报表 在Reflex WMS系统上,我们可以通过物料号查询它的HD列表,或者IPG列表.通过在其HD/IPG信息得知其库存数据.当然还可以通过如下方式直接获 ...

  4. Splinter入门(十二)Executing javascript(执行JavaScript)

    Splinter入门(十二)Executing javascript(执行JavaScript)   Splinter支持调用JavaScript脚本,例如: <!DOCTYPE html> ...

  5. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验二十:SDRAM模块③ — 页读写 α...

    实验二十:SDRAM模块③ - 页读写 α 完成单字读写与多字读写以后,接下来我们要实验页读写.丑话当前,实验二十的页读写只是实验性质的东西,其中不存在任何实用价值,笔者希望读者可以把它当成页读写的热 ...

  6. Oracle入门(十二)之SQL的DDL

    一.数据类型 Character 数据类型 Number 数据类型 Date 数据类型 Raw 和 Long Raw 数据类型 LOB 数据类型 注:Oracle数据类型详解 二.表 (1)创建表 c ...

  7. python二级第十二套答案

    python二级第十二套答案 46.考生文件夹下存在三个Python源文件,分别对应三个问题,请按照文件内说明修改代码,实现以下功能: 法定节假日是根据各国.各名族的风俗习惯或纪念要求,由国家法律统一 ...

  8. GUI的演化和python编程——Python学习笔记之二十二

    GUI的演化和python编程--Python学习笔记之二十二 写完了有关长寿的两篇博文,本该去完成哥德尔那个命题六的.对计算机图形界面的好奇,让我把注意力暂时离开那个高度抽象难读的哥德尔,给转到计算 ...

  9. Python遥感图像处理应用篇(二十二):Python+GDAL 批量等距离裁剪影像-续

    之前写过一篇按照指定行列号数量来进行影像等距离裁剪的博客,链接如下: Python遥感图像处理应用篇(二十二):Python+GDAL 批量等距离裁剪影像_空中旋转篮球的博客-CSDN博客_pytho ...

最新文章

  1. 极客新闻——08、高效团队善用的3个敏捷方法
  2. 对象存储与块存储、文件存储等对比
  3. Linux Centos7 下安装Mysql - 8.0.15
  4. Windows——完全控制面板(上帝模式)
  5. 【结论】游戏(jzoj 5536)
  6. pcie1 4 速度_太阳系行星们谁转得最快?八大行星自转速度排行榜,地球排第五...
  7. 《vue+vant 文本超出两行部分省略号显示》
  8. java告警系统设计_告警系统的设计
  9. presto 设置mysql连接,Apache Presto配置设置
  10. NodeJS仿WebApi路由
  11. Spark DataFrame入门详解
  12. R与Python手牵手:数据探索性分析案例展示
  13. 鸿蒙移植mate10,鸿蒙系统+麒麟1020再升一个台阶,华为Mate30黯然神伤无奈下跌
  14. WinForm和WPF的区别
  15. 网格员试题计算机,网格员考试 计算机基础知识试题库完整.doc
  16. android没有adm_这可能是安卓平台上最好的下载器:ADM
  17. 人工神经网络算法的应用,神经网络算法应用案例
  18. oracle 查询数据的结果集导出
  19. 原神私服 grasscutter搭建及食用教程 v3.3
  20. myeclipse下使用maven搭建SSM(spring、springmvc、mybatis)框架

热门文章

  1. jstree Api 中文翻译文档
  2. 计算机浏览页面,计算机默认网页浏览器怎么设置
  3. 铨顺宏RFID:车辆运输管理途中怎么监控?RFID智能称重系统有用吗
  4. 扑克牌面试问题:从牌顶拿出一张牌放到桌子上,再从牌顶拿一张牌放在手上牌的底部,重复第一步、第二步的操作
  5. Cocos Creator游戏引擎可以支持鼠标吗_Cocos Creator入门实战:桌球小游戏
  6. html之制作banner按钮
  7. 用Python获取公众号阅读数、点赞数。
  8. lqc_帐号控制—NIS服务器
  9. 长期不能落地的区块链突破口在这里
  10. IOS 屏幕适配(一)理论篇