集合,堆和双端队列笔记

本文介绍了Python中的集合、堆、双端队列等数据结构的使用方法,并详细讲解了time、random等常用模块的功能与操作技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、集合

新版本python中,集合由内置类set实现,可直接使用。

>>> set(range(1,10,2))
{1, 3, 5, 7, 9}

集合会忽略重复元素,且元素排列顺序不确定。
pass

2、堆

它是一种优先队列。优先队列让你能够以任意顺序添加对象,并随时(可能是在两次添加对象之间)找出(并删除)最小的元素。相比于列表方法min效率高很多。
实际上,Python没有独立的堆类型,只有一个包含一些堆操作函数的模块。这个模块名为heapq(其中q表示队列),它包含6个函数,前4个与堆操作直接相关。必须使用列表来表示堆对象本身。

函数描述
heappush(heap,x)将x压入堆中
heappop(heap)从堆中弹出最小的元素
heapify(heap)让列表具备堆特征
heapreplace(heap,x)弹出最小的元素,并将x压入堆中
nlargest(n,iter)返回iter中n个最大的元素
nsmallest(n,iter)返回iter中n个最小的元素
#heappush()
>>> from heapq import *
>>> heap = []
>>> for n in range(10):
        heappush(heap,n)

>>> heap    #heappush()不能用于普通列表,只能用于使用堆函数创建的列表。
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]  #因为堆元素排序有规律:位置i处元素总是大于i//2处的元素。这是底层堆运算的基础,称为堆特征。
>>> from random import shuffle
>>> data = list(range(10))
>>> data
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> shuffle(data)
>>> data
[7, 4, 6, 1, 5, 2, 9, 8, 3, 0]
>>> heap = []
>>> for n in data:
        heappush(heap,n)

>>> heap
[0, 1, 2, 4, 3, 6, 9, 8, 7, 5]
>>> heappush(heap,0.5)   #heappush()作用:在堆中添加一个元素。
>>> heap
[0, 0.5, 2, 4, 1, 6, 9, 8, 7, 5, 3]

#heappop(),弹出最小元素(总是位于索引0处),并且确保剩下元素保持堆特征。
>>> heap
[0, 0.5, 2, 4, 1, 6, 9, 8, 7, 5, 3]
>>> heappop(heap)
0
>>> heap
[0.5, 1, 2, 4, 3, 6, 9, 8, 7, 5]
>>> heappop(heap)
0.5
>>> heap
[1, 3, 2, 4, 5, 6, 9, 8, 7]

#heapify()通过执行尽可能少的位移操作将列表变成合法的堆(具备堆特征)。
>>> heap = [1,2,3,4,5,6,7,8,9,0]
>>> heapify(heap)
>>> heap
[0, 1, 3, 4, 2, 6, 7, 8, 9, 5]

#heapreplace()弹出最小元素,再压入一个新元素。
>>> heap 
 [0.5,1,5,3,2,7,9,8,4,6]
>>> heapreplace(heap,10)
0.5
>>> heap
[1,2,5,3,6,7,9,8,4,10]

3、双端队列

在需要按添加元素的顺序进行删除时,双端队列很有用。

>>> from collections import deque
>>> q = deque(range(5))
>>> q
deque([0, 1, 2, 3, 4])
>>> q.append(5)          #可以左添加
>>> q.appendleft(6)      #也可以右添加
>>> q
deque([6, 0, 1, 2, 3, 4, 5])
>>> q.pop()              #可以左删除
5
>>> q.popleft()          #也可以右删除
6
>>> q
deque([0, 1, 2, 3, 4])
>>> q.rotate(3)  #后三个元素移到队首
>>> q
deque([2, 3, 4, 0, 1])
>>> q.rotate(1)   #最后一个元素移到队首
>>> q
deque([1, 2, 3, 4, 0])
>>> q.rotate(2)  #后两个元素移到队首
>>> q
deque([4, 0, 1, 2, 3])

4、模块time

包含用于获取当前时间、操作时间和日期、从字符串中读取日期、将日期格式化为字符串的函数。日期可表示为实数(从“新纪元”1月1日0时起过去的秒数。“新纪元”是一个随平台而异的年份,在UNIX中为1970年),也可表示为包含9位整数的元组。如(2008,1,21,12,2,56,0,21,0)表示2008年1月21日12时2分56秒,这一天是星期一,2008年的第21天(不考虑夏令时)。

Python中日期元素的字段

索引字段
0如2018
11~12
21~31
30~23
40~59
50~61(闰年)
6星期0~6(0为星期一)
7儒略日1~366
8夏令时0、1或-1

夏令时数字是一个布尔值(True或False),但如果使用-1,那么mktime [ 将时间元组转换为时间戳(从新纪元开始后的秒数) 的函数] 可能得到正确的值。

模块time中一些重要的函数

函数描述
asctime([tuple])将时间元组转换为字符串
localtime([secs])centered
mktime(tuple)are neat
sleep(secs)休眠(什么都不做) secs秒
striptime(string[,format])将字符串转换为时间元组
time()当前时间(从新纪元开始后的秒数,以UTC为准)
>>> import time
>>> time.asctime()
'Mon Aug 13 22:58:12 2018'
>>> time.localtime()
>>> time.struct_time(tm_year=2018, tm_mon=8, tm_mday=13, tm_hour=22, tm_min=58, tm_sec=38, tm_wday=0, tm_yday=225, tm_isdst=0)
>>> time.strptime('Mon Aug 13 22:58:12 2018')
time.struct_time(tm_year=2018, tm_mon=8, tm_mday=13, tm_hour=22, tm_min=58, tm_sec=12, tm_wday=0, tm_yday=225, tm_isdst=-1)

5、模块random

包含生成伪随机数的函数,有助于编写模拟程序或生成随机输出的程序。请注意,虽然这些函数生成的数字好像是完全随机的,但它们背后的系统是可预测的。如果要求真正的随机(如用于加密或实现与安全相关的功能),应考虑使用模块os中的函数urandom。模块random中的函数SystemRandom类基于的功能与urandom类似,可提供接近于真正随机的数据。
模块random的一些重要的函数

函数描述
random()返回一个0~1(含)的随机实数
getrandbits(n)以长实数方式返回n个随机的二进制位
uniform(a,b)返回一个a~b(含)的随机实数
randrange([start],stop,[step])从range(start,stop,step)中随机地选择一个数
choice(seq)从序列seq中随机地选择一个元素
shuffle(seq[,random])就地打乱序列seq
sample(seq,n)从序列seq中随机地选择n个值不同的元素
>>> import random
>>> random.random()
0.08968567002141803
>>> random.random()
0.8316540189763981
>>> random.getrandbits(12)
2532
>>> random.getrandbits(4)
12
>>> random.uniform(1,2)
1.4238137189490196
>>> random.uniform(3,4)
3.3753276314879472
>>> random.choice([1,23,4,5,6])
6
>>> random.choice([1,2,3,4,5,6,78])
5
>>> a = [1,2,3,4,5,6,7,8,9]
>>> random.shuffle(a)
>>> a
[6, 2, 1, 9, 4, 8, 7, 5, 3]
>>> random.sample(a,3)
[1, 8, 9]
>>> random.sample(a,5)
[1, 9, 4, 2, 5]

6、shelve和json

模块shelve用于文件存储(简单的存储方案)。其中的函数open()是将一个文件名作为参数,返回一个Shelf对象,以存储数据。可以像普通字典那样错做它(只是键必须是字符串),操作完毕(并将所做的修改存盘)时,可调用方法open。
shelve.open返回的对象并非普通映射。

>>> import shelve
>>> s = shelve.open('test.dat')
>>> s['x'] = ['a','b','c']
>>> s['x'].append('d')
>>> s['x']
['a', 'b', 'c']

>>> temp = s['x']
>>> temp.append('d')
>>> s['x'] = temp
>>> s['x']
['a', 'b', 'c', 'd']

pass

7、模块re

模块re提供了对正则表达式的支持。正则表达式是可匹配文字片段的模式。最简单的正则表达式为字符串,与它们自己匹配。换而言之,正则表达式 ‘ python ’ 与字符串 ‘ python ’ 匹配。可使用这种匹配行为来完成如下工作:在文本中查找模式,将特定的模式替换为计算得到的值,以及将文本分隔成片段。

通配符

正则表达式可与多个字符串匹配,可使用特殊字符串来创建这种正则表达式。例如,句点与处换行符外的其他字符都匹配,因此正则表达式 ’ .ython ’ 与字符串 ’ python ’ 和 ‘jython’ 都匹配,还与 ’ qython ’ , ’ +ython ’ 和 ’ ython ‘(空格) 匹配,但不与 ’ cpython ’ 和’ython’匹配,因为点句只与一个字符匹配,不与零或一个以上字符匹配。
句点与除换行符外的任何字符都匹配,因此被称为通配符

对特殊字符进行转义

普通字符只与自己匹配,但特殊字符的情况完全不同。例如,假设要匹配字符串 ‘python.org’,直接使用会与’pythonzorg’匹配。要让特殊字符的行为与普通字符一样,要对其进行转义:前面加上反斜杠\。为表示模块re要求的单个反斜杠,需要在字符串前加两个反斜杠,让解释器对其进行转义。

字符集

匹配任何字符很有用,但有时需要更细致地控制。为此,可用方括号将一个子串括起,创建一个所谓的字符集。这样的字符集与其包含的字符都匹配,如’[pg]ython’与’python’和’jython’都匹配。此外,还可以设置范围,如’[a-z]’与a~z的任何字母都匹配。还可以组合多个访问,方法是依次列出它们,如’[a-zA-Z0-9]’与大写字母、小写字母和数字都匹配。但注意,字符集只能匹配一个字符
要指定排除字符集,可以在开头添加^,如’[^abc]’与处a、b和c外的其他字符都匹配。

二选一和子模式

需要以不同的方式处理每个字符时,字符集很好,但如果只想匹配字符串’python’和’perl’,使用字符集或通配符无法指定这样的模式,必须使用表示二选一的特殊字符|。所需的模式为’python|perl’。
如果不想二选一运算符作用于整个模式,只作用模式的一部分,可以将这部分(子模式)放在圆括号内,即’p(ython|erl)’。注意,单个字符也可称为子模式

可选模式和重复模式

通过在子模式后面加上问号,可将其指定为可选的,即可包含可不包含。如下:

r'(http://)?(www\.)?python|.org'

只与’http://www.python.org‘、’http://python.org‘、’www.python.org’和’python.org’匹配。其中,为了减少所需的反斜杠数量,使用了原始字符串r。
另外,问号表示可选的子模式可出现一次或者不出现,还有其他几个运算符可用于子模式的重复多次。(pattern)*表示pattern可重复0、1或多次。(pattern)+表示pattern可重复1或多次。(pattern){m,n}表示模式可重复m~n次。

字符串的开头和末尾

pass

8、模块re的内容

模块re中一些重要的函数

函数描述
compile(pattern[,flags])根据包含正则表达式的字符串创建模式对象
search(pattern,string[,flags])在字符串中查找模式
match(pattern,string[,flags])在字符串开头匹配模式
split(pattern,string[,maxsplit=0])根据模式来分隔字符串
findall(pattern,string)返回一个列表,其中包含字符串中所有与模式匹配的子串
sub(pat,repl,string[,count=0])将字符串中与模式pat匹配的子串都替换为repl
escape(string)对字符串中所有的正则表达式特殊字符都进行转义
>>> import re
>>> some_text = 'alpha,beta,,,,gamma    delta'

#search()函数
>>> re.search('[,]+',some_text)
<re.Match object; span=(5, 6), match=','>
>>> re.search('[l]+',some_text)
<re.Match object; span=(1, 2), match='l'>

#match()函数
>>> re.match('[a]+',some_text)   #查找第一个与指定正则表达式匹配的子串
<re.Match object; span=(0, 1), match='a'>
>>> re.match('[l]+',some_text)  #re.search()如果找到指定子串,有就返回MatchObject(结果为真),否则返回None(假)
>>>
#split()函数
>>> re.split('[, ]+',some_text)
['alpha', 'beta', 'gamma', 'delta']
>>> re.split('[, ]+',some_text,maxsplit=2)
['alpha', 'beta', 'gamma    delta']
>>> re.split('[,]+',some_text,maxsplit=1)
['alpha', 'beta,,,,gamma    delta']

#findall()函数
text = '"Hm...Err--are you sure?" he said, sounding insecure.'
re.findall(pat,text)
['are ', 'you ', 'he ', 'sounding ']
pat = '[a-zA-Z]+'
re.findall(pat,text)
['Hm', 'Err', 'are', 'you', 'sure', 'he', 'said', 'sounding', 'insecure']
pat = '[.?\-",]+'
re.findall(pat,text)
['"', '...', '--', '?"', ',', '.']

#sub()函数
pat = '{name}'
text = 'Dear {name}'
re.sub(pat,'Mr. Gumby',text)
'Dear Mr. Gumby'

\d可以匹配一个数字,\w可以匹配一个字母或者数字,如’00\d’可以匹配007,008,不能匹配00A。\s为空格,\s+至少一个空位。
要更精准的匹配,可以使用范围[ ],如[0-9a-zA-Z_]可以匹配一个数字或者字母或者一个_。若[pattern]+就是匹配至少一个,[pattern]*可以匹配任意个,[pattern]{n,m}可以匹配n~m个。^表示行的开头,^\d表示必须以数字开头。

\d 表 示 行 的 结 束 , \d $表示以数字结尾。

re.escape是一个工具函数,用于对字符串中所有可能被视为正则表达式运算符的字符进行转义。
使用这个函数的情况有:字符串很长,其中包含大量特殊字符,而你不想输入大量的反斜杠;你从用户那里获取了一个字符串(例如通过input),想将其用于正则表达式中。


>>> re.escape('http://www.python.com')
'http://www\\.python\\.com'
>>> re.escape('Hello, world!')
'Hello,\\ world!'

匹配对象和编组
在模块re中,查找与模式匹配的子串的函数都在找到时返回MatchObject对象。这种对象包含与模式匹配的子串,还包含模式的哪部分与子串的哪部分匹配的信息。这些子串部分称为编组
编组就是放在圆括号内的子模式,它们是根据左边的括号数编号的,其中编组0指的是整个模式。举例如下:
’ There (was a (wee) (cooper) ) who (lived in Eyfe) ’
包含如下编组:
0 There was a wee cooper who lived in Eyfe
1 was a wee cooper
2 wee
3 cooper
4 lived in Eyfe
re匹配对象的重要方法

方法描述
group([group1,…])获取与给定子模式(编组)匹配的子串
start([group])返回与给定编组匹配的子串的起始位置
end([group])返回与给定编组匹配的子串的终止位置(与切片一样,不包含终止位置)
span([group])返回与给定编组匹配的子串的起始和终止位置
>>> m = re.match(r'www\.(jav.)(.*)\..{3}','www.javapythonc++.com')
>>> m.group(0)   #编组0(整个字符串)
'www.javapythonc++.com'
>>> m.group(1)   #编组1,与格式(jav.)匹配
'java'
>>> m.group(2)   #编组2,与格式(.*)匹配
'pythonc++'
>>> m.start(1)   #编组1起始位置
4
>>> m.start(2)    #编组2起始位置
8
>>> m.end(1)      #编组1终止位置
8
>>> m.span(1)     #编组1跨度
(4, 8)

替换中的组号和函数
pass

贪婪和非贪婪模式
正则匹配默认是贪婪匹配,及匹配尽可能多的字符。

>>> re.match(r'^(\d+)(0*)$','102300').groups()
('102300', '')
>>> re.match(r'^(\d+?)(0*)$','102300').groups()
('1023', '00')
>>> emphasis_pattern = r'\*(.+)\*'
>>> re.sub(emphasis_pattern,r'<em>\1</em>','*This* is *it*!')
'<em>This* is *it</em>!'
>>> emphasis_pattern = r'\*(.+?)\*'
>>> re.sub(emphasis_pattern,r'<em>\1</em>','*This* is *it*!')
'<em>This</em> is <em>it</em>!'
>>> emphasis_pattern = r'\*\*(.+?)\*\*'
>>> re.sub(emphasis_pattern,r'<em>\1</em>','**This** is **it**!')
'<em>This</em> is <em>it</em>!'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值