python基础(9)--递归、二叉算法、多维数组、正则表达式
1.递归
在函数内部,可以调其他函数,如果一个函数在内部调用它本身,这个函数就是递归函数。递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于裂解
递归算法解决问题的特点:
1)递归是在过程或函数里调用自身
2)在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口
3)递归算法解题通常显得很简洁,但递归算法解题的运行效率较低,所以一般不提倡用递归算法设计程序
4)在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序
递归算法所体现的“重复”一般有三个要求:
1)每次调用在规模上都有所缩小(通常是减半)
2)相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入)
3)在问题的规模极小时必须用直接给出解答而不再进行递归调用,因为每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束
例:
def func(num):
if num / 2 > 0:
num -= 1
print(num)
num = func(num)
print('quit')
return num func(10)
二叉算法---具体实例可以通过递归实现二分查找
def binary_search(data_list, find_num):
mid_pos = int(len(data_list) / 2) #计算需要查找数据长度的一半
mid_val = data_list[mid_pos] #获取中间位置的那个值
print(data_list) #查看每次剩余筛选的数据列表
if len(data_list) > 0: #当列表长度大于0时,则一直查找
if mid_val > find_num: #如果中间的数比实际要查找的数大,那么这个数肯定在左边
print("%s should be in left of [%s]" % (find_num, mid_val))
binary_search(data_list[:mid_pos], find_num)
elif mid_val < find_num: #如果中间的数比实际查找的数小,那么这个数肯定在右边
print("%s should be in right of [%s]" % (find_num, mid_val))
binary_search(data_list[mid_pos:], find_num)
else:
print("Find %s" % find_num) else: #否则就没有这个数
print("cannot find [%s] in data_list" % find_num) if __name__ == '__main__':
primes = [1, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
binary_search(primes, 1) #在列表里面查找1 '''
执行结果
[1, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
1 should be in left of [41]
[1, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
1 should be in left of [17]
[1, 3, 5, 7, 11, 13]
1 should be in left of [7]
[1, 3, 5]
1 should be in left of [3]
[1]
Find 1
'''
多维数组交叉(多维数组旋转90度)
array = [[col for col in range(4)] for row in range(4)] #初始化一个4*4数组 for row in array: #旋转前先看看数组长啥样
print(row) for i, row in enumerate(array):
for index in range(i, len(row)):
tmp = array[index][i] #将每一列数据在每一次遍历前,临时存储
array[index][i] = array[i][index] #将每一次遍历的值,赋值给交叉的列
print(tmp, array[i][index])
array[i][index] = tmp #将之前保存的交叉列的值,赋值给交叉行的对应值
for r in array: #打印每次交换后的值
print(r) '''
[0, 1, 2, 3]
[0, 1, 2, 3]
[0, 1, 2, 3]
[0, 1, 2, 3]
0 0
0 1
0 2
0 3
[0, 0, 0, 0]
[1, 1, 2, 3]
[2, 1, 2, 3]
[3, 1, 2, 3]
1 1
1 2
1 3
[0, 0, 0, 0]
[1, 1, 1, 1]
[2, 2, 2, 3]
[3, 3, 2, 3]
2 2
2 3
[0, 0, 0, 0]
[1, 1, 1, 1]
[2, 2, 2, 2]
[3, 3, 3, 3]
3 3
[0, 0, 0, 0]
[1, 1, 1, 1]
[2, 2, 2, 2]
[3, 3, 3, 3]
'''
正则表达式
字符串是编程时涉及到最多的一种数据结果,对字符串进行操作的需求几乎无处不在,比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦,而且代码难以服用
正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串,在文本处理方面功能非常强大,也经常用作爬虫,来爬取特地内容,Python本身不支持正则,但是通过导入re模块,Python也能用正则表达式,下面就来讲一下python正则表达式的用法
Python支持的正则表达式元字符和语法
语法 | 说明 | 表达式实例 | 完整匹配的字符串 |
字符 | |||
一般字符 | 匹配自己 | abc | abc |
. | 匹配任意字符“\n”除外 DOTALL模式中(re.DOTALL)也能匹配换行符 |
a.b | abc或abc或a1c等 |
[...] | 字符集[abc]表示a或b或c,也可以-表示一个范围如[a-d]表示a或b或c或d | a[bc]c | abc或adc |
[^...] | 非字符集,也就是非[]里的之外的字符 | a[^bc]c | adc或aec等 |
预定义字符集(也可以系在字符集[...]中) | |||
\d | 数字:[0-9] | a\dc | a1c等 |
\D | 非数字:[^0-9]或[^\d] | a\Dc | abc等 |
\s | 空白字符:[<空格>\t\n\f\v] | a\sc | a b等 |
\S | 非空白字符:[^s] | a\Sc | abc等 |
\w | 字母数字(单词字符)[a-zA-Z0-9] | a\wc | abc或a1c等 |
\W | 非字母数字(非单词字符)[^\w] | a\Wc | a.c或a_c等 |
数量词(用在字符或(...)分组之后) | |||
* | 匹配0个或多个前面的表达式。(注意包括0次) | abc* | ab或abcc等 |
+ | 匹配1个或多个前面的表达式。 | abc+ | abc或abcc等 |
? | 匹配0个或1个前面的表达式。(注意包括0次) | abc? | ab或abc |
{m} | 匹配m个前面表达式(非贪婪) | abc{2} | abcc |
{m,} | 匹配至少m个前面表达式(m至无限次) | abc{2,} | abcc或abccc等 |
{m,n} | 匹配m至n个前面的表达式 | abc{1,2} | abc或abcc |
边界匹配(不消耗待匹配字符中的字符) | |||
^ | 匹配字符串开头,在多行模式中匹配每一行的开头 | ^abc | abc或abcd等 |
$ | 匹配字符串结尾,在多行模式中匹配每一行的结尾 | abc$ | abc或123abc等 |
\A | 仅匹配字符串开头 | \Aabc | abc或abcd等 |
\Z | 仅匹配字符串结尾 | abc\Z | abc或123abc等 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 | ||
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 | ||
逻辑、分组 | |||
| | 或左右表达式任意一个(短路)如果|没有在()中表示整个正则表达式(注意有括号和没括号的区别) | abc|def ab(c|d)ef |
abc或def abcef或abdef |
(...) | 分组,可以用来引用,也可以括号内的被当做一组进行数量匹配后接数量词 | (abc){2}a | abcabca |
(?P<name>...) | 分组别名,给分组起个名字,方便后面调用 | ||
\<number> | 引用编号为<number>的分组匹配到的字符串(注意是配到的字符串不是分组表达式本身) | (\d)abc\1 | 1ab1或5ab5等 |
(?=name) | 引用别名为name的分组匹配到的字符串(注意是配到的字符串不是分组表达式本身) | (?P<id>\d)abc(?P=id) | 1ab1或5ab5等 |
import re #将正则表达式编译成Pattern对象
pattern = re.compile(r'hello') #使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None
match = pattern.match('hello world!') if match:
#使用Match获得分组信息
print(match.group()) #执行结果hello
还可以直接使用re模块的方法的时候直接传递正则表达式参数来完成
match = re.match('hello', 'hello world')
print(match.group()
re模块常用方法
1)findall(获取字符串中所有的匹配字符串)
import re
l = re.findall('\d', '4k3sadsd8,9') #\d代表数字,将匹配带的元素放到一个列表里
print(l) #['4', '3', '8', '9'] print(re.findall('\w', 'de..,_2')) #['d', 'e', '_', '2']匹配字母数字下划线 print(re.findall('^dk', 'dkwej,ds34,')) #以dk开头的['dk'] print(re.findall('^dk', 'des,423')) #[] print(re.findall('d{3,5}', 'sddddd')) #取前面一个字符d的3到5次 print(re.findall('s{2}', 'ssaesssfgss')) #匹配前一个字符s两次['ss', 'ss', 'ss'] print(re.findall('a*x', 'aaaaaax')) #['aaaaaax']匹配前面一个字符0次或多次,贪婪匹配 print(re.findall('\d*', 'swe32452')) #['', '', '', '32452', ''] print(re.findall('a+c', 'aaaccc')) #['aaac']匹配前面一个字符的一次或多次,贪婪匹配 print(re.findall('a?c', 'aaaccc')) #['ac', 'c', 'c']匹配前面一个字符的0次或1次 print(re.findall('a[.]s', 'adfff afs')) #.在[]里面失去意义,所以为[] print(re.findall('[a-z]', 'we3.j4_re')) #['w', 'e', 'j', 'r', 'e'] print(re.findall('[^a-z]', 'we3.j4_re')) #['3', '.', '4', '_']取反 print(re.findall('ax$', 'dsadax')) #以ax结尾['ax'] print(re.findall('a(\d+)b', 'a42323b')) #['42323'] print(re.findall('a(\d+?)b', 'a42323b'))#['42323']前后均有限定条件,则非贪婪模式,失效 print(re.findall('a(\d+)', 'a23b')) #['23'] print(re.findall('a(\d+?)', 'a23b'))#['2']加上?变成非贪婪模式
findall高级用法: ?:
默认取分组()内的信息,但是想让分组外的匹配信息也渠道,就要用?:
import re
l = re.findall("www.(baidu|laonanhai).com", "asd www.baidu.commwww.laonanhai.com")
print(l) #['baidu', 'laonanhai']默认取括号内的信息 l = re.findall("www.(?:baidu|laonanhai).com", "asd www.baidu.commwww.laonanhai.com")
print(l) #['www.baidu.com', 'www.laonanhai.com']
finditer(): 迭代查找
import re
p = re.compile('\d+')
iterator = p.finditer('12 drumm44ers drumming, 11 ... 10 ...')
for match in iterator:
print(match.group())
print(match.span()) '''
执行结果
12
(0, 2)
44
(8, 10)
11
(24, 26)
10
(31, 33)
'''
2)match(pattern, string, flag=0)
·正则表达式
·要匹配的字符串
·标志位,用于控制正则表达式的匹配方式
注意:这个方法并不是完全匹配。当pattern结束时若string还有剩余字符,仍然视为成功。想要完全匹配,可以在表达式末尾加上边界匹配符'$'。
返回值:如果匹配成功返回match对象,否则返回None
Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息
方法:
1.group([group1, ...]):
获得一个或多个分组截获的字符串,指定多个参数时将以元组形式返回,group1可以使用编号也可以使用别名,编号0代表整个匹配的子串,不填写参数时,返回group(0),没有截获字符串的返回None,截获了多次的返回最后一次的子串
2.group([default]):
以元组形式返回全部分组截获的字符串,相当于调用group(1,2,...last),default表示没有截获字符串的组以这个代替,默认为None
3.groupdict([default]):
返回以有别名的组的别名为键、以该组截获的子串为值得字典,没有别名的组不包含在内,default含义同上
4.start([group]):
返回以指定的组截获的子串string中的其实索引(子串第一个字符的索引),group默认值为0
5.end([group])
返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1),group默认值为0
6.span([group]):
返回(start(group),end(group))
7.expand(template):
将匹配到的分组带入template中然后返回,template中可以使用\id或g<id>、\g<name>引用分组,但不能使用编号0,\id与\g<id>是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'',只能使用\g<1>0。
3)search(pattern,string,flag=0)
根据模型去字符串中匹配指定内容,匹配单个,只匹配一次,可以结合split将匹配到内容分割、拼接,然后再次循环查找,因为findall尽管可以找到所以,但是在处理分组()时候分组外的内容匹配不到,findall返回的是列表
可以通过一个实例来看下match跟search的区别
import re
s = 'hello world'
print(re.match('ello', s)) #输出None print(re.search('ello', s)) #<_sre.SRE_Match object; span=(1, 5), match='ello'> '''
可以看到match只匹配开头,search则可以从中间匹配,只要有就能匹配到
'''
4)group和groups
group(0) 显示全部
group(1) 显示第一个分组()
group(2) 显示第二个分组()
如果没有分组或超出分组个数就会报错
5)split(pattern, string, maxsplit=0, flags=0)
按照匹配子串将字符串进行分割,返回分割的列表,maxsplit用于指定最大分割次数,不指定将全部分割。
import re
s = 'one1two2three3four4'
print(re.split('\d+', s)) #['one', 'two', 'three', 'four', '']
6)re.compile(strPattern[, flag]): compile 编译方法
如果一个匹配规则,以后要使用偶次,就可以先将其编译,以后就不用每次都在去写匹配规则
这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象。第二个参数flag是匹配模式,取值可以使用按位或运算符'|',表示同时生效,比如re.l | re.M
可以把正则表达式编译成一个正则表达式对象。可以把那些经常使用的正则表达式编译成正则表达式对象,可以提高一定的效率,下面是一个正则表达式对象的例子
import re
text = "JGood is a handsome boy, he is cool, clever, and so on..."
regx = re.compile('w*oo\w')
print(regx.findall(text)) #查找所有包含'oo'的单词['ood', 'ool']
7)sub(pattern, repl, string, count=0, flag=0)
用于替换匹配的字符串,pattern内必须为正则表达式,不能是正则比倒是search或findall查找到的赋值变量
比如我的计算器处理括号的方法,用正则search匹配到后,不能直接将变量输入sub的pattern,因为不起做哟用
sub(repl, string[, count]) | re.sub(pattern, repl, string[, count]):
使用repl替换string中每一个匹配的子串后返回替换后的字符串
当repl是一个字符串时,可以使用\id或g<id>、\g<name>引用分组,但不能使用编号0
当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)
import re
print(re.subn('\d', 'ZZ', '34*,5sdfs,4hsdf')) #('ZZZZ*,ZZsdfs,ZZhsdf', 4)
#subn方法,返回总共替换的次数
实例:假设有一个四则元素表达式'--(1.1+1+1-(-1)-(1+1+(1+1+2.2)))+-----111+--++--3-+++++++---+---1+4+4/2+(1+3)*4.1+(2-1.1)*2/2*3',遵循奇数个负号等于正否则为负的原则进行替换,我们可以这样
import re
s = '--(1.1+1+1-(-1)-(1+1+(1+1+2.2)))+-----111+--++--3-+++++++---+---1+4+4/2+(1+3)*4.1+(2-1.1)*2/2*3'
def replace_sign(expression):
def re_sign(m):
if m:
if m.group().count('-') % 2 == 1:
return '-'
else:
return '+'
else:
return '' expression = re.sub('[\+\-]{2,}', re_sign, expression)
return expression s = replace_sign(s)
print(s) #+(1.1+1+1-(-1)-(1+1+(1+1+2.2)))-111+3-1+4+4/2+(1+3)*4.1+(2-1.1)*2/2*3
正则补充 match search示例
import re
print(re.match('www', "www.baidu.com")) # 打印匹配结果
print(re.match('www', "www.baidu.com").group()) # 打印匹配到的结果
print(re.match('www', "www.baidu.com").end()) # 打印匹配到的结束位置,不包含该索引字符
print(re.match('www', "www.baidu.comw").endpos) # 打印最后一个字符串位置
print(re.match('www', "www.baidu.com").groupdict())
print(re.match('www', "www.baidu.com").groups())
print(re.match('www', "www.baidu.com").lastindex)
print(re.match('www', "www.wwwbaidu.com").pos) # 打印匹配索引
print(re.match('www', "www.baidu.com").re) # 打印编译(解析公式)
print(re.match('ww', "www.baidu.com").span()) # 打印匹配分片的位置
print(re.match('www', "www.baidu.com").start()) # 打印匹配开始索引
print(re.match('www', "www.baidu.com").string) # 打印被匹配字符串 print(re.search("www", "www.www.com"))
print(re.search("www", "qq.www.com"))
print(re.search("www", "www.www.com").string)
print(re.search("www", "www.www.com").start())
print(re.search("www", "qq.www.com").start())
print(re.search("www", "qq.www.com").span()) # 返回匹配到的索引位置
print(re.search("www", "www.www.com").span())
print(re.search("www", "qq.www.com").group())
print(re.search("www", "qq.www.com").groups())
print(re.search("www", "qq.www.com")) # search 与match,
# search 从头匹配,只要找到则停止匹配,如果有多个被匹配,只返回最先匹配到的位置字符
# match 从头匹配,开头位置匹配不到就不继续匹配
正则分组匹配模式 ()
a = "123abc456"
print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).group()) # 模式()分组匹配
print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(0)) # 显示第0组,也就是所有分组
print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(1)) # 显示第一组分组
print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(2))
print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).groups()) # 返回元组形式的分组匹配
匹配中文
re.findall("[\u4e00-\u9fa5]+", string)
contactInfo = 'Oldboy School, Beijing Changping Shahe: 010-8343245'
match = re.search('(?P<last>\w+\s+\w+),(?P<first>\s+\w+\s+\w+\s+\w+): (?P<phone>\S+)', contactInfo)
print(match.group("last")) # 打印自定义标签内容
print(match.group('first'))
print(match.group("phone")) '''
Oldboy School
Beijing Changping Shahe
010-8343245
'''
python基础(9)--递归、二叉算法、多维数组、正则表达式的更多相关文章
- LeetCode刷题191130 --基础知识篇 二叉搜索树
休息了两天,状态恢复了一下,补充点基础知识. 二叉搜索树 搜索树数据结构支持许多动态集合操作,包括Search,minimum,maximum,predecessor(前驱),successor(后继 ...
- 十四. Python基础(14)--递归
十四. Python基础(14)--递归 1 ● 递归(recursion) 概念: recursive functions-functions that call themselves either ...
- Python 基础 面向对象之二 三大特性
Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...
- python基础篇(二)
PYTHON基础篇(二) if:else,缩进 A:if的基础格式和缩进 B:循环判断 C:range()函数和len()函数 D:break,contiue和pass语句 for,while循环 函 ...
- python基础扩展(二)
python基础扩展(二) 常用操作 1.startswith(以什么开始) endswith(y)什么结束 s='taiWanw39dd' print(s.startswith('t')) #意思是 ...
- php 数据集转换树、递归重组节点信息多维数组(转)
一.将数据集转换成树 /** * 将返回的数据集转换成树 * @param array $list 数据集 * @param string $pk 主键 * @param string $pid 父节 ...
- 用Python实现数据结构之二叉搜索树
二叉搜索树 二叉搜索树是一种特殊的二叉树,它的特点是: 对于任意一个节点p,存储在p的左子树的中的所有节点中的值都小于p中的值 对于任意一个节点p,存储在p的右子树的中的所有节点中的值都大于p中的值 ...
- python基础知识(二)
以下内容,作为python基础知识的补充,主要涉及基础数据类型的创建及特性,以及新数据类型Bytes类型的引入介绍
- Python基础学习总结(二)
2.列表简介 Python有内置的一种数据类型列表:list. list是一种有序的集合. 列表由一系列按特定顺序排列的元素组合.用方括号 [ ] 来表示. list里面的元素的数据类型可以不同,比如 ...
随机推荐
- PID控制算法的C语言实现五 积分分离的PID控制算法C语言实现
在普通PID控制中,引入积分环节的目的主要是为了消除静差,提高控制精度.但在过程的启动.结束或大幅度增减设定时,短时间内系统输出有很大的偏差,会造成PID运算的积分积累,致使控制量超过执行机构可能允许 ...
- html中的事件属性
Window 事件属性 针对 window 对象触发的事件(应用到 <body> 标签): 属性 值 描述 onafterprint script 文档打印之后运行的脚本. onbefor ...
- Codeforces 932.F Escape Through Leaf
F. Escape Through Leaf time limit per test 3 seconds memory limit per test 256 megabytes input stand ...
- BNU-2017.7.4排位赛2总结
链接:https://www.bnuoj.com/v3/contest_show.php?cid=9147#info A题 sort之后交换首尾两个数. B题 for一遍,如果每个数都在对应位置了,输 ...
- php数组定义
$arr = array( ,), //是’0' ,不是[‘0’] ,), ,), ,), ); $arr = [ '0' => array(2,3), //是’0' ,不是[‘0’] '1' ...
- Mac(Linux)上安装memcached步骤
Mac上安装memcached类似于在Linux平台上安装memcached. 主要需要做两块: 一.安装libevent库: 二.安装memcached; 一.安装libevent库 libeven ...
- 前端PHP入门-029-文件操作-掌握级别
人生只有三天,活在昨天的人迷惑:活在明天的人等待:活在今天的人最踏实.你永远无法预测意外和明天哪个来得更早,所以,我们能做的,就是尽最大的努力过好今天.请记住:今天永远是昨天死去的人所期待的明天. f ...
- 高可用rabbitmq集群服务部署步骤
消息队列是非常基础的关键服务,为保证公司队列服务的高可用及负载均衡,现通过如下方式实现: RabbitMQ Cluster + Queue HA + Haproxy + Keepalived 3台ra ...
- "Access restriction: The type BASE64Encoder is not accessible due to restrict"问题解决
问题如题: Eclipse中有一种叫做存取限制的机制,来防止你错误使用那些非共享的API.通常来说,Eclipse做的是对的,因为两点,我们不想要使用非共享API的,而且Eclipse知道什么是共享的 ...
- 如何在Lunix云服务器上安装Mysql进行远程连接
说说这个服务器上安装mysql真是一个大坑啊 ! 我也不知道自己怎么心血来潮就买一个百度云服务器,然后就想着吧自己做的一些小项目都跑上去.嘿嘿...其实就是想显摆下,写点小应用给不是编程的朋友们使用 ...