简介
这一讲,我们介绍一种简单的数据结构------栈。栈这种数据结构,就像整齐堆在一起的盘子,你需要用的时候,就从最上面取走一个。当你洗碗餐具,就把洗好的新盘子放在原先盘子的上面。你能拿到的总是最上面的一个盘子,最下面的盘子总是被最后取出。抽象的说,就是 first in last out(先进去的元素,最后出来)。
栈出栈、入栈、查看栈顶元素,由于只操作单个元素,时间复杂度为 O(1)。
由于 python 的 list 数据结构十分强大,所以使用 list 的内置操作,我们很轻松地就实现了栈这种数据结构。栈作为一种受限的线性表,我们只能操作栈尾部的元素。push
函数用于向栈尾部添加一个元素,pop
函数用于删除栈尾的一个元素。但需要注意的是,我们需要判断栈是否为空,如果为空,我们不能进行删除元素的操作;还要判断栈是否已满,如果已满的话,我们不能进行添加元素的操作。top
函数返回栈尾部的一个元素,size
函数返回栈的大小。
class StackArray(object):
def __init__(self, length):
# length 栈被限制的大小
self.item = []
self.length = length
def push(self, value):
if self.is_full():
raise Exception('栈已满')
else:
self.item.append(value)
def pop(self):
if self.is_empty():
raise Exception('栈为空')
self.item.pop()
def top(self):
if self.is_empty():
raise Exception('栈为空')
return self.item[-1]
def is_empty(self):
return len(self.item) == 0
def is_full(self):
if len(self.item) >= self.length:
return True
def size(self):
return len(self.item)
接下来,我们介绍使用栈模拟浏览器进退功能的简单案例。
linux 系统下实现效果图:
浏览器进退功能是指,我连续开了a,b,c,d四个页面。退:是指从页面 d 返回页面 c ;进:是指返回页面 c 后再前进到页面 d。通过两个线性栈,就可以保存前进与后退所有的元素。但是,如果我退到页面 b 之后,我又新开了页面 e,我就无法通过页面 e 返回到页面 c,d。
第一节curses 库的安装与使用讲了curses
库安装与使用,这里我就简单介绍一下:
# 屏幕不显示用户输入的字符
curses.noecho()
# 使用 curses 首先需要初始化
stdscr = curses.initscr()
# stdscr.getchar() 返回的是
# 输入的单个字符的 ascii 码值
# 假如输入'p',返回 112
stdscr.getch()
# 清除屏幕
stdscr.clear()
# 打印字符
stdscr.addstr('You win')
那么如何用 python 实现呢?
我们需要建立两个线性栈,一个主栈用来保存当前的页面和之前的几个页面,一个副栈用来保存当前页面之后的几个页面。
当进行后退操作时,副栈获取主栈最上面的元素,主栈删除这个元素,从而后退到前一个页面。
当进行前进操作时,主栈获取副栈最上面的元素,副栈删除这个元素,从而前进到下一个页面。
当新的页面被创建,显然新页面前面不存在其他页面,这是我们要清空副栈。即下面的代码:
while not temp_stack.is_empty():
temp_stack.pop()
当主栈中只有一个元素时,显然浏览器已经后退到第一个页面,不能再后退了;当副栈没有元素时,显然浏览器已经前进到最后一个页面了,不能再前进了。用代码限制为:
length = stack.size()
if length > 1:
temp_stack.push(stack.top())
stack.pop()
以下为全部代码:
注:stack 为主栈,temp_stack 为副栈
在命令行执行: python + 文件名 即可运行
import curses
from curses import wrapper
from datetime import datetime
stdscr = curses.initscr()
count = 1
class StackBrowser(object):
def __init__(self, length=200):
self.item = []
self.length = length
def push(self, value):
if self.is_full():
return None
else:
self.item.append(value)
def pop(self):
if self.is_empty():
return None
self.item.pop()
def top(self):
if self.is_empty():
return None
return self.item[-1]
def is_empty(self):
return len(self.item) == 0
def is_full(self):
if len(self.item) >= self.length:
return True
def size(self):
return len(self.item)
def show_stack(self):
print(self.item)
def print_board(stdscr):
# stdscr.clear()
# 清除屏幕
for i in range(4):
stdscr.addstr('-' * 22 + '\n')
for j in range(4):
stdscr.addstr('|')
if board[i, j]:
stdscr.addstr('{:^4d}'.format(board[i, j]))
else:
stdscr.addstr(' '.format())
stdscr.addstr('|')
stdscr.addstr('\n')
stdscr.addstr('-' * 22 + '\n')
def print_browser(stdscr, order, stack, temp_stack):
global count
# datetime.now() 获取当前时间和日期
# strftime 将日期格式化输出 年-月-日 时:分:秒
now = '网页创建时间:{}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S \n'))
stdscr.clear()
# 退出程序
if order == ord('q'):
exit()
# 新建页面
elif order == ord('n'):
count += 1
stack.push(now)
while not temp_stack.is_empty():
temp_stack.pop()
# 后退功能
elif order == ord('b'):
length = stack.size()
if length > 1:
temp_stack.push(stack.top())
stack.pop()
# 前进功能
elif order == ord('f'):
length = temp_stack.size()
if length >= 1:
stack.push(temp_stack.top())
temp_stack.pop()
# 打印功能
if stack.top():
stack_size = stack.size()
sum_size = stack.size() + temp_stack.size()
stdscr.addstr(stack.top())
stdscr.addstr('共创建了 {} 个页面 \n'.format(count))
stdscr.addstr('当前页面:第 {} 页 \n'.format(stack_size))
stdscr.addstr('共 {} 页 \n'.format(sum_size))
def main(stdscr):
global count
# 不显示输入
curses.noecho()
# 创建 stack 类
# stack 为主栈
# temp_stack 为副栈
stack = StackBrowser()
temp_stack = StackBrowser()
# 获取当前时间
now = '网页创建时间:{}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S \n'))
# 栈保存网页创建时间
stack.push(now)
stack_size = stack.size()
sum_size = stack.size() + temp_stack.size()
stdscr.addstr(stack.top())
stdscr.addstr('共创建了 {} 个页面 \n'.format(count))
stdscr.addstr('当前页面:第 {} 页 \n'.format(stack_size))
stdscr.addstr('共 {} 页 \n'.format(sum_size))
while 1:
order = stdscr.getch()
print_browser(stdscr=stdscr, order=order, stack=stack, temp_stack=temp_stack)
if __name__ == '__main__':
wrapper(main)