1.python数据结构性能分析
我们用到了timeit模块中的Timer类,测试一段python代码的执行速度。
Timer类有3个参数:
- stmt:接受测试的代码块语句
- setup:运行代码块所需的设置
- timeit函数:表示为Timer.timeit(number=10000),代表执行10000次该程序的平均耗时
from timeit import Timer
def addItem():
alist = [ ]
for i in range(1000):
alist += [i]
return alist
if __name__ == '__main__':
# Timer类需要的参数,‘from __main__ import addItem’代表从主函数中插入addItem函数的设置
t1 = Timer(stmt='addItem()',setup='from __main__ import addItem')
time = t1.timeit(1000)
print(time)
# pycharm执行结果:
# 0.11482795300071302
2.栈stack
栈和栈内元素好比乒乓球筒,遵循先进后出原则。
2.1 栈的应用
浏览器的后退与前进按钮
本质上就是把网页网址放入到一个栈中,第一个查看的网页存放在栈尾,点击返回按钮后,按照相反的顺序浏览刚才的页面。
2.2 栈的工作流程
class Stack(): # 创建一个空栈,无需参数
# __init__ 是初始化方法,用来初始化实例后的对象stack,这样写self.items属性就可以作为一个变量
def __init__(self):
self.items = [ ]
# 用于将一个新元素添加到栈顶
def push(self,item):
self.items.append(item)
# 从栈中删除顶部项,无需传参,删除顶项
def pop(self):
return self.items.pop()
# 判断栈是否为空,返回bool值
def isEmpty(self):
return self.items == [ ]
# 返回栈中的item属性,返回整数
def size(self):
return len(self.items)
# 从栈返回顶部项
def peek(self):
return
alist = [1,2,3,4,5]
stack = Stack()
# 从alist中拿元素放入栈中
for item in alist:
stack.push(item)
print(stack.size())
for i in range(len(alist)):
print(stack.pop())
3.队列
队列就好比是一个高速公路隧道,特点是先进先出
2.1 队列的应用
应用场景
比如公司的打印机,各部门的打印需求都在一个队列中,第一个进入任务是先完成。
2.2 队列的工作流程
# 创建一个空的队列
class Queue():
def __init__(self):
self.items = [ ]
# 将新项添加到队尾
def enqueue(self,item):
self.items.insert(0,item)
# 从队首移除项,队列被修改
def dequeue(self):
return self.items.pop()
# 查看队列是否为空
def isEmpty(self):
return self.items == [ ]
# 查看队列中的项数
def size(self):
return len(self.items)
alist = [1,2,3,4,5]
q = Queue()
for item in alist:
q.enqueue(item)
for i in range(len(alist)):
print(q.dequeue())
2.3 案例:烫手的山芋
"""
烫手山芋游戏介绍:
6个孩子围城一个圈,排列顺序孩子们自己指定。第一个孩子手里有一个烫手的山芋,需要在计时器计时1秒后将山芋传递给下一个孩子,依次类推。规则是,在计时器每计时7秒时,手里有山芋的孩子退出游戏。该游戏直到剩下一个孩子时结束,最后剩下的孩子获胜。请使用队列实现该游戏策略,排在第几个位置最终会获胜。
思路分析:
队列中有6个元素
一轮游戏是7秒.山芋被传递了几次(6)
"""
q = Queue()
# 一共有6个孩子,就是队列中的6个元素
kids = ['A', 'B', 'C', 'D', 'E', 'F']
# 往队列中添加6个元素,孩子进入队列
for kid in kids:
q.enqueue(kid)
# 游戏开始:
# 只要队列中有超过1个孩子,就要进入新一轮游戏
while q.size() > 1:
# 一轮游戏,按照队列中元素个数进行循环,(并不是循环1圈就删掉一个人)
# 因为队列只能删除队首,无法随意位置删除,所以这个for循环实现了一个“模拟传递山芋的过程,并在传递后调整队列顺序,始终使拿山芋的人位于队首”。
for i in range(len(kids)):
kid = q.dequeue() # dequeue(),队首移除,不需要参数并返回item
q.enqueue(kid) # 循环1圈,游戏未结束,队尾添加
print(q.size()) # 每轮队列元素-1,打印队列长度
print("这一轮退出游戏的是:",q.dequeue())
print("最终胜出者:",q.dequeue())
2.4 如何使用两个队列实现一个栈
分析:
栈的特性是先入后出(12345 -> 54321),队列的特性是先入先出
q1 = Queue()
q2 = Queue()
alist = [1,2,3,4,5]
for item in alist:
q1.enqueue(item) # q1 = [1,2,3,4,5]
while q1.size() > 0:
for i in range(q1.size()-1): # 循环4次,因为循环4次之后,q1=[5],直接dequeue取出就可以了,再走循环有点多余。
# 从q1队首移除项并用item接收,加入q2队列队尾 从队首删,从队尾加。 q1 = [2,3,4,5] q2 = [1,]
item = q1.dequeue() # item = 1, item = 2, item = 3, item = 4, q1 = [5,]
q2.enqueue(item) # q2 [1,]
print(q1.dequeue()) # 此时5就取出来了,栈第一个取出来的元素就应该是5,没错
q1,q2 = q2,q1 # 此时q2已经变成了原q1的格式,所以进行变量替换就可以继续加入循环,直至循环结束,输出54321
2.5 双端队列
同同列相比,有两个头部和尾部。可以在双端进行数据的插入和删除,提供了单数据结构中栈和队列的特性。
双端队列的应用:
回文检查。回文是一个字符串,读取首尾相同的字符,例如,radar toot madam。
"""
Deque() 创建一个空的新 deque。它不需要参数,并返回空的 deque。
addFront(item) 将一个新项添加到 deque 的首部。它需要 item 参数 并不返回任何内容。
addRear(item) 将一个新项添加到 deque 的尾部。它需要 item 参数并不返回任何内容。
removeFront() 从 deque 中删除首项。它不需要参数并返回 item。deque 被修改。
removeRear() 从 deque 中删除尾项。它不需要参数并返回 item。deque 被修改。
isEmpty() 测试 deque 是否为空。它不需要参数,并返回布尔值。
size() 返回 deque 中的项数。它不需要参数,并返回一个整数。
"""