大话数据结构真的是一本好书,有这样系统的学习之后感觉自己零散的知识点回忆都被放入了整齐的盒子中。
4 栈和队列
①栈stack是只允许在尾部(栈顶)进行添加和删除数据元素的线性表(先进后出)。
可应用在Word等的撤销操作。
操作:进栈(push),出栈(pop)。
顺序存储的python代码如下:(用list实现)
#栈的顺序实现
class stack:
def __init__(self):
self.item = []
def push(self,item):
self.item.append(item)
return self.item
def pop(self):
self.item.pop()
return self.item
def lens(self):
return len(self.item)
def top(self):
return self.item[-1]
如果要查找栈中Minum的值,可以使用继承的方法。
注意继承的时候调用继承的类中的方法要加self。
Python代码如下:
class stack_min(stack):
def __init__(self):
stack.__init__(self)
self.mins = stack()
def push(self,item):
stack.push(self,item)
if item <= self.mins.top() or len(self.mins.lens()) == 0:
self.mins.push(item)
def min(self):
return self.mins.top()
def pop(self):
item = stack.pop(self)
if item == self.mins.top():
self.mins.pop()
return item
链式存储:链栈
链栈,头指针指向栈顶即可,栈顶为单链表的头结点。为空就是头指针指向空。
用python实现如下:
class linked_list:
def __init__(self,item):
self.val = item
self.next = None
#链式存储结构
class stack_linked_list:
def __init__(self):
self.top = None #栈顶指针
self.cur = None #游标
def push_stack(self,item):
node = linked_list(item)
self.top = node
node.next = self.cur
self.cur = node
return self.top
def pop_stack(self):
while self.top:
value = self.top.val
self.top = self.top.next
return value
这里删除和插入的操作时间复杂度都是o(1)。
栈的应用:递归
首先介绍最有名的递归程序,斐波那契数列。
#菲波那切数列生成 0,1,1,2,3.......
def f(n):
#寻找base case,和普遍规律
if n == 0:
return 0
if n == 1:
return 1
return f(n-1) + f(n-2)
print(f(3))#n是指的数值的索引位置
说个题外话:斐波那契数列的实现这样递归会很耗时,所以还可以使用其他的方法。在牛客网上搞了好久,真的是really尴尬.....
def f(n):
if n <= 2:
return 1
a,b = 0,1
for i in range(n):
a,b = b,a+b
return a
栈和递归的关系是什么呢?
递归过程退回的顺序是她前行顺序的逆序,在退回过程中要执行某些动作,包括恢复在前行过程中存储的某些数据,这时就需要用到栈。
栈还可以应用到四则运算表达式求值,遇到左括号,就入栈,等遇到右括号,就出栈。
但是有括号还是要解决先加减后乘除的问题,所以rpn 逆波兰表示法诞生。将数学表达式转换成后缀表达式,初始化空栈,遇到数字就入栈,遇到符号就前两个数字出栈进行运算,结果再入栈,以此类推,最终得到结果。但是我们平时的标准四则运算表达式(中缀表达式)是如何转化为后缀表达式的呢?书108-110
②队列(queue)是可以在一头进行添加和另一头进行删除数据元素的线性表(先进先出)
操作系统和客服系统,使用队列。
顺序存储:
#queue by list
class queue:
def __init__(self):
self.item = []
def enqueue(self,item):
return self.item.append(item)
def dequeue(self):
while self.item:
item = self.item[0]
del self.item[0]
return item
return None
队列的入队时间复杂度为o(1),顺序存储时出队时间复杂度为o(n),因为出栈的时候所有元素要向前移动一位,为了节约时间,引出了循环队列。
循环队列是移动队头和队尾的指针,当front和rear指针相等时,队列为空。循环队列也会遇到数据容易溢出等问题,所以引出链式存储的队列。
链式存储:
class linked_list:
def __init__(self,value):
self.val = value
self.next = None
class queue_linked_list:
def __init__(self):
self.top = None
self.tail = None
def enqueue(self,value):
node = linked_list(value)
if self.top == None and self.tail == None:
self.top = self.tail = node
else:
self.tail.next = node
self.tail = node
def dequeue(self):
while self.top:
val = self.top.val
self.top = self.top.next
return val
return None
如果要在队列中实现查找并返回队列最小值,也类似栈,使用继承。
class queue:
def __init__(self):
self.item = []
def enqueue(self,item):
return self.item.append(item)
def dequeue(self):
while self.item:
item = self.item[0]
del self.item[0]
return item
return None
class queue_min(queue):
def __init__(self):
queue.__init__(self)
self.mins = queue()
def mins(self):
return self.mins.dequeue()
def enqueue(self,item):
queue.enqueue(self,item)
if item <= self.mins.item[0] or len(self.mins.item) == 0:
self.mins.enqueue(item)
def dequeue(self):
item = queue.dequeue()
if item == self.mins.item[0]:
self.mins.dequeue()
return item