栈是一种重要的线性结构。栈是线性表的一种具体的形式。
栈的官方定义:栈是一个后进先出的线性表,它要求只在表尾进行删除和插入操作。
表尾称为栈的栈顶(top),表底部称为栈的栈底(bottom),栈的插入操作(push)叫压栈或入栈,栈的删除操作(pop)叫做出栈,也叫作弹栈。

栈并不是python的内建类型,程序员可以使用列表结构来实现栈的功能。j
栈的实现:
class Stack: def __init__(self): self.stack=[] def isEmpty(self): """ 栈的清空 :return: """ self.stack.clear() return self.stack def push(self,item): """ 栈的压入 :param item: :return: """ self.stack.append(item) def pop(self): """ 出栈 :return: """ if self.isEmpty(): raise IndexError('pop from empty stack') return self.stack.pop() def peek(self): """ 返回栈顶数据 :return: """ return self.stack[-1] def size(self): """ 返回当前栈的大小 :return: """ return len(self.stack) a=Stack() a.push(5) a.push(6) a.push(7) print(a.peek()) print(a.size())
结果
7 3
栈的应用:
1.维护web游览器所访问过的链接的历史记录。
2. 括号 匹配问题:给一个字符串,字符串中有小括号,中括号大括号,求该字符串中的括号是否匹配,实例‘({[]})’
解题思路: 做一个空栈,把字符串中的左括号先push栈中,右括号匹配左括号,如果匹配上就出栈,直到栈和字符串中没有括号为止,即为成功匹配
##'([{}])' def kuohao(s): stack=[] for i in s: if i in ['(','[','{']: stack.append(i) elif i==')': if len(stack)>0 and stack[-1]=='(': #匹配上则出栈 stack.pop() else: return False elif i == ']': if len(stack) > 0 and stack[-1] == '[': stack.pop() else: return False elif i == '}': if len(stack) > 0 and stack[-1] == '{': stack.pop() else: return False if len(stack)==0: #最后查看栈中还有没有左括号,没有即为完全匹配 return True else: return False
3.十进制转2进制
def tentotwo(num): stack=[] stack2=[] while num >0 : set=num %2 #区余数 num=num//2 stack.append(set) while len(stack)>0: stack2.append(stack.pop()) #倒着push到stack2中 return stack2 print(tentotwo(100))
结果:
[1, 1, 0, 0, 1, 0, 0]
4. Flask中的上下文管理中把请求上下文对象和应用上下文对象放到local对象中,就是应用了栈
队列(queue)
队列(queue):是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出的线性表
队列既可以用链表实现,也可以用数组来实现。
栈一般我们用顺序表来实现,而队列我们常用链表来实现,简称为链队列。
队列不能用列表来实现,当队首删除的时候所有的元素都要移动一个位置。时间复杂操作为o(n)。
在python中提供队列功能的模块叫:
from collections import deque
链表队列实现:
我们定义如下的链表来实现队列数据结构:

定义一个头节点,左边指向队列的开头,右边指向队列的末尾,这样就可以保证我们插入一个元素和取出一个元素都是O(1)的操作,使用这种链表实现stack也是非常的方便。实现代码如下:
class Node: """ 节点类 """ def __init__(self,item): self.item=item self.next=None class Head: """ 头节点类 """ def __init__(self): self.right=None self.left=None class LinkQueue: """ 链表队列类 """ def __init__(self): self.head=Head() self.size=0 def add(self,item): """ 队列添加函数 :param item: :return: """ newNode=Node(item) if self.head.right: #如果head节点的右边不为空,说明队列中已经有值了。取出head节点右边指向的那个节点 temp=self.head.right#取出当前队列的最后一个节点 self.head.right=newNode#把head节点的right指向新节点 temp.next=newNode #把当前队列的最后一个节点的next指向新节点 self.size+=1 else: self.head.left=newNode self.head.right=newNode self.size += 1 def pop(self): """ 队列删除函数 :return: """ if self.head.right: if self.head.right==self.head.left:#说名只有一个节点 tep=self.head.left self.head.left=self.head.right=None self.size=0 return tep.item else: t1=self.head.left #把要删除的值先取出来 self.head.left=t1.next #把head。left连接上第二个节点 self.size-=1 return t1.item else: raise LookupError('列表为空') def peek(self): """ #查询队列的第一个值 :return: """ if self.head.left: return self.head.left.item else: raise LookupError('列表为空') def size(self): """ 查询队列的元素个数 :return: """ return self.size q=LinkQueue() q.add(5) q.add(6) q.add(7) # print(q.pop()) # print(q.pop()) print(q.size)
循环队列实现
队列不能用列表来实现,当队首删除的时候所有的元素都要移动一个位置。时间复杂操作为o(n)。
我们可不可以这样当删除操作队首元素时,只是队首位置向后移动了一个,其他位置不变,这样不就解决了,所有元素都要移动一个位置的问题吗? 但是,我们会发现,队列的实际空间变小了一个,这就是队列的假溢出。
怎么解决这个问题呢?
解决的办法是,如果队列满了,就从队列的头开始也就是头尾相接的循环,就用到了循环队列
我们定义一个头节点,有front 变量指向第一个节点,rear变量指向最后一个节点,当pop操作时front变量指向下一个节点,其他节点不动,当add操作时,rail变量指向新添加的节点,知道队列没有空余空间为止。

也就是在add和pop操作中front和rail变量的索引不断加1,但是如何让rail和front操作队列最大的索引呢即溢出,我们可以采取取模的方式,rail的值就等于(rail+1)//队列容量 ,front=(front+1)%队列容量,
这样rail和front永远不会溢出。
浙公网安备 33010602011771号