bisect模块
bisect 模块包含两个主要函数,bisect 和 insort,两个函数都利用二分查找算法来在有序序列中查找或插入元素。
二分查找算法
二分查找又称折半查找,优点是比较次数少,查找速度快;缺点是要求要查的表是有序表。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。
首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。在子表中进一步查找时,将子表以子表的中间位置分割,再去比较。一直重复分割、比较,直到找到满足条件的记录,或直到子表不存在为止,此时查找不成功。
用bisect()搜索元素位置
bisect(haystack, needle, lo=0, hi=None) 在 haystack里搜索needle的位置,该位置满足的条件是,把 needle 插入这个位置之后,haystack 还能保持升序。也就是在说这个函数返回的位置前面的值,都小于或等于 needle 的值。其中 haystack 必须是一个有序的序列。在haystack 是一个有序的序列的基础上,你可以先用 bisect(haystack, needle) 查找位置 index,再用haystack.insert(index, needle) 来插入新值。 lo=0, hi=None两个参数是搜寻的索引范围,hi的默认参数意思就是整个序列的长度。
eg:
import bisect
import sys
HAYSTACK = [1, 4, 5, 6, 8, 12, 15, 20, 21, 23, 23, 26, 29, 30]
NEEDLES = [0, 1, 2, 5, 8, 10, 22, 23, 29, 30, 31]
ROW_FMT = '{0:2d} @ {1:2d} {2}{0:<2d}'
def demo(bisect_fn):
for needle in reversed(NEEDLES):
position = bisect_fn(HAYSTACK, needle) #用特定的 bisect 函数来计算元素应该出现的位置
offset = position * ' |' #利用该位置来算出需要几个分隔符号
print(ROW_FMT.format(needle, position, offset)) #把元素和其应该出现的位置打印出来
if __name__ == '__main__':
if sys.argv[-1] == 'left': #根据命令上最后一个参数来选用 bisect 函数
bisect_fn = bisect.bisect_left #bisect_fn用来存储方法,不会影响后面()内的列表,bisect.bisect_left 插入元素左侧位置;bisect.bisect_right 插入元素右侧位置,可用来处理插入数值与列表元素相同的情况
else:
bisect_fn = bisect.bisect #bisect.bisect 返回某个数在列表中可以插入的位置,但不会插入该数,如果这个数与列表中的元素相同,则返回元素后面的位置,bisect.bisect默认就是bisect.bisect_right
print('DEMO:', bisect_fn.__name__) #把选定的函数在抬头打印出来
print('haystack ->', ' '.join('%2d' % n for n in HAYSTACK)) #join之前有说过哦
demo(bisect_fn)
输出:
format()函数
在上面的例子中,还用到了format()函数占位,那么format()函数的具体用法是什么呢?(我就喜欢看到哪里学哪里哈,一点一点积累吧)
事实上Format方法有两个种形式,另外一种是三个参数的,主要区别在于它是线程安全的, 但并不多用,所以只对第一个介绍。Format参数是一个格式字符串,用于格式化Args里面的值的。Args是一个变体数组,即它里面可以有多个参数,而且每个参数可以不同。 例如: Format(“my name is %6s”,“wind”); 返回的是:my name is wind 。
占位时的参数格式: { [index “:”] [填充物]["-"] [width][正负号] ["." prec] type },所有的参数都是可选的。
index:在format()传入参数时, 想要获得的值在format()内的对应的序号(序号从0开始), 注意索引不能超出传入的值个数,不然会引起异常。
填充物:在“:”后可输入符号,用来填充设定宽度内无数据的地方。
["-"] :控制内容的对齐方式,< (默认)左对齐、> 右对齐、^ 中间对齐、= (只用于数字)在小数点后进行补齐。
[width]:指定将被格式化的值占的宽度,按照想要输出的宽度输入数字(注意:这里说的宽度不是说我们给的最重要传入的值的宽度,而是我们想要用多长的宽度来展示这个值,就算是这个宽度内有的地方是空的,展示出来也是那些宽度)。
["." prec] :指定精度,若不是设置,默认为精度为6,自动四舍五入,可带符号显示数字正负标志。prec是指要留几位数,若要留4位则在此将该参数设置为4即可。若是精度高度数字本身,其余位置用0补位。
eg:print(’{:+.2f}’.format(NN))
“+”是无论数值正负输出时都显示数值的“+”“-”号;“-”是当数值为负时输出显示“-”符号,但是正数前面就不显示“+”号了,它的效果和不添加“+”“-”号参数的效果是相同的。
type:type 数可选的类型有d,u,f,e,g,n,m,p,s,x,b,c,o
- d :十进制数,表示一个整型值,u 和d一样是整型值,但它是无符号的,而如果它对应的值是负的,则返回时是一个2的32次方减去这个负数的绝对值 。例如:Format(“this is %u”,-2); 返回的是:this is 4294967294
- f :浮点数
- e:科学表示法,对应整型数和浮点数,用’e’表示幂2)。
- g :浮点型,且它会将值中多余的数去掉、
- n:数字。当值为整数时和’d’相同,值为浮点数时和’g’相同。不同的是它会根据区域设置插入数字分隔符。
- m :钱币类型,但关于货币类型有更好的格式化方法,这里只是简单的格式化,另外它只对应于浮点值。
- p :指针类型,返回的值是指针的地址,以十六进制的形式来表示。
- s :字符串类型。
- x :一个整形值,以十六进制的形式返回,9以上的位数用小写字母。
10.X:十六进制数,A 到 F 大写。 - b: 二进制,将数字以2为基数进行输出。
- c:字符。在打印之前将整数转换成对应的Unicode字符串。
- o:八进制。将数字以8为基数进行输出。
reversed()函数
在上面的例子中,用到了reversed()函数,reversed()的作用是什么呢?
reversed ()函数返回一个反转的迭代器,无论输入什么类型的序列,最终都是以列表的形式返回,且列表内元素的排列顺序均与原序列顺序相反。
语法:reversed(seq)
seq – 要转换的序列,可以是 tuple, string, list 或 range。
eg:
# 字符串
seqString = 'Runoob'
print(list(reversed(seqString)))
输出:['b', 'o', 'o', 'n', 'u', 'R']
# 元组
seqTuple = ('R', 'u', 'n', 'o', 'o', 'b')
print(list(reversed(seqTuple)))
输出:['b', 'o', 'o', 'n', 'u', 'R']
# range
seqRange = range(5, 9)
print(list(reversed(seqRange)))
输出:[8, 7, 6, 5]
# 列表
seqList = [1, 2, 4, 3, 5]
print(list(reversed(seqList)))
输出:[5, 3, 4, 2, 1]
用bisect.insort()插入新元素
insort(seq, item) 把变量 item 插入到序列 seq 中,并能保持 seq 的升序顺序。
import bisect
import random
SIZE=7
random.seed(1729) #seed(x)方法改变随机数生成器的种子,若没有设定x数值,每次就生成不一样的随机数,若设定x数值,每次都会生成相同的随机数。此方法影响下面的生成随机数语句,无论运行本程序多少次,每次都会得到相同的随机数输出序列。
my_list = []
for i in range(SIZE):
new_item = random.randrange(SIZE*2) #randrange([start,] stop [,step]) 方法返回指定递增基数集合中的一个随机数,基数默认值为1。start:指定范围内的开始值,包含在范围内。stop:指定范围内的结束值,不包含在范围内。这里只有一个参数,应该是结束值为14,开始值默认为0。
bisect.insort(my_list, new_item) #将随机数插入
print('%2d ->' % new_item, my_list)
输出:
In[2]: runfile('D:/python course/liuchangdePy/bisect——insort.py', wdir='D:/python course/liuchangdePy')
10 -> [10]
0 -> [0, 10]
6 -> [0, 6, 10]
8 -> [0, 6, 8, 10]
7 -> [0, 6, 7, 8, 10]
insort 跟 bisect 一样,有 lo 和 hi 两个可选参数用来控制查找的范围。它也有个变体叫 insort_left,这个变体在背后用的是 bisect_left。
目前所提到的内容都不仅仅是对列表或者元组有效,还可以应用于几乎所有的序列类型上。
呼~~~终于写完了,由于这一部分我自己在学习和理解的时候有一些吃力,感觉可能还有一些小细节没有描述好,接下来会不断地完善,也欢迎大家指出我的错误!
持续更新中,如果存在哪些问题,希望大家能及时指出,我一定会及时修改!