栈与队列
一、栈
-
特性:
-
先进后出
- 从栈顶向栈底添加元素,从栈顶取元素
-
-
栈的操作
- Stack() :创建一个新的空栈
- push(item) :添加一个新的元素item到栈顶
- pop() :弹出栈顶元素
- peek() :返回栈顶元素
- is_empty(): 判断栈是否为空
- size(): 返回栈的元素个数
-
栈的实现
class Stack: """栈""" def __init__(self): self.items = [] def is_empty(self): """判断是否为空""" return self.items == [] def push(self, item): """添加元素""" self.items.append(item) def pop(self): """弹出元素""" return self.items.pop() def peek(self): """返回栈顶元素""" return self.items[len(self.items)-1] def size(self): """返回栈的大小""" return len(self.items) if __name__ == "__main__": stack = Stack() stack.push("hello") stack.push("world")print (stack.size()) print (stack.peek()) print (stack.pop())
二、队列
-
特性:
- 先进先出
- 只允许从队尾插入元素,从队头取元素
-
操作:
- Queue() :创建一个空的队列
- enqueue(item) :往队列中添加一个item元素
- dequeue() :从队列头部删除一个元素
- is_empty() :判断一个队列是否为空
- size() :返回队列的大小
-
队列实现:
class Queue: '''队列''' def __init__(self): self.items = [] def enqueue(self,item): '''入队列''' self.items.insert(0,item) def dequeue(self): '''出队列''' return self.items.pop() def is_empty(self): '''判空''' return self.items == [] def size(self): '''大小''' return len(self.items) if __name__ == "__main__": q = Queue() q.enqueue("hello") q.enqueue("world") print(q.size()) print(q.dequeue())
-
案例
- 烫手的山芋:
- 6个孩子围成一个圈,排列顺序由自己指定。第一个孩子手里有一个烫手的山芋,需要在计时器计时开始1秒后传递给下一个孩子,以此类推。规则是:计时器每计时7秒时,就会淘汰手里有山芋的孩子,该游戏直到剩下最后一个孩子结束,该孩子获胜。请用队列实现该游戏策略,排在第几个孩子最终获胜。
- 分析:
- 队列特性:先进先出,并且只能从队尾插入数据,从队头取数据。
- 第1秒时,山芋在第1个孩子手里,第2秒时在第2个孩子手里,以此类推,第7秒时,该轮游戏中山芋被传递了6次
- 可以将手里有山芋的孩子始终放在队头位置:每传递一次,队头孩子出队列,然后再入队列,每轮结束时,队头孩子出队列
- 代码实现:
# coding:utf-8 class Queue: '''队列''' def __init__(self): self.items = [] def enqueue(self,item): '''入队列''' self.items.insert(0,item) def dequeue(self): '''出队列''' return self.items.pop() def is_empty(self): '''判空''' return self.items == [] def size(self): '''大小''' return len(self.items) def shanyu_game(): '''烫手的山芋游戏''' kids = [1,2,3,4,5,6] #1-6分别表示一开始对应位置上的孩子 q = Queue() for kid in kids: q.enqueue(kid) while q.size() > 1: for i in range(6): kid = q.dequeue() #出队列 q.enqueue(kid) #入队列 q.dequeue() print('第%s个孩子获胜'%q.dequeue()) if __name__ == "__main__": shanyu_game()
运行结果:第5个孩子获胜
- 烫手的山芋:
三、双端队列
-
特性
- 是一种具有队列和栈的性质的数据结构。
- 可以在队列任意一端入队和出队。
-
操作
- Deque() :创建一个空的双端队列
- add_front(item) :从队头加入一个item元素
- add_rear(item) :从队尾加入一个item元素
- remove_front() :从队头删除一个item元素
- remove_rear(): 从队尾删除一个item元素
- is_empty(): 判断双端队列是否为空
- size(): 返回队列的大小
-
实现
class Deque: '''双端队列''' def __init__(self): self.items = [] def add_front(self,item): '''队头插入元素''' self.items.insert(0,item) def add_rear(self,item): '''队尾插入元素''' self.items.append(item) def remove_front(self): '''队头删除元素''' return self.items.pop(0) def remove_rear(self): '''队尾删除元素''' return self.items.pop() def size(self): '''返回队列大小''' return len(self.items) if __name__ == '__main__': d = Deque() d.add_front('a') d.add_front('b') d.add_rear('c') d.add_rear('d') print(d.remove_front()) print(d.remove_rear()) print(d.size())
-
案例
- 回文检查:判断字符串首尾字符是否相同,例如madam,toot
- 代码实现:
# coding:utf-8 class Deque: '''双端队列''' def __init__(self): self.items = [] def add_front(self,item): '''队头插入元素''' self.items.insert(0,item) def add_rear(self,item): '''队尾插入元素''' self.items.append(item) def remove_front(self): '''队头删除元素''' return self.items.pop(0) def remove_rear(self): '''队尾删除元素''' return self.items.pop() def size(self): '''返回队列大小''' return len(self.items) def palindrome_checker(item): '''回文检查器''' d = Deque() for i in item: d.add_rear(i) while d.size() > 1: start = d.remove_front() end = d.remove_rear() #判断首位字符是否相等,不相等即返回False if start != end: return False return True if __name__ == '__main__': print(palindrome_checker('hello')) print(palindrome_checker('abbccbba')) print(palindrome_checker('abcdcba'))
四、使用栈实现队列
-
分析:
- 使用栈实现队列,即实现先进先出的特性
- 可以采用两个栈来实现
- 栈A提供入队列功能
- 栈B提供出队列功能
- 若栈B为空,则先将栈A中的数据依次弹出,放入栈B,再弹出栈B的最后一个数据
- 若栈B不为空,则直接弹出栈B的最后一个数据
-
代码实现:
# coding:utf-8 class Stack: """栈""" def __init__(self): self.items = [] def is_empty(self): """判断是否为空""" return self.items == [] def push(self, item): """添加元素""" self.items.append(item) def pop(self): """弹出元素""" return self.items.pop() def peek(self): """返回栈顶元素""" return self.items[len(self.items)-1] def size(self): """返回栈的大小""" return len(self.items) class MyQueue: '''栈实现队列''' def __init__(self): self.A = Stack() self.B = Stack() def push(self,item): '''入队列''' self.A.push(item) def pop(self): '''出队列''' if self.B.is_empty(): while not self.A.is_empty(): self.B.push(self.A.pop()) return self.B.pop() if __name__ == '__main__': q = MyQueue() q.push('a') q.push('b') q.push('c') print(q.pop()) print(q.pop()) print(q.pop())
五、使用队列实现栈
-
分析
- 使用队列实现栈,即实现先入后出的特性
- 可以采用两个队列来实现
- 队列A负责入栈操作
- 出栈操作时,队列A中仅保留队尾一个数据,其余数据全部入队列B,然后队列A和队列B互换,取出队列B中的一个数据
-
代码实现
class Queue: '''队列''' def __init__(self): self.items = [] def enqueue(self,item): '''入队列''' self.items.insert(0,item) def dequeue(self): '''出队列''' return self.items.pop() def is_empty(self): '''判空''' return self.items == [] def size(self): '''大小''' return len(self.items) class MyStack: '''队列实现的栈''' def __init__(self): self.A = Queue() self.B = Queue() def push(self,item): '''入栈''' self.A.enqueue(item) def pop(self): '''出栈''' while self.A.size() > 1: self.B.enqueue(self.A.dequeue()) self.A,self.B = self.B,self.A return self.B.dequeue() if __name__ == '__main__': stack = MyStack() stack.push(1) stack.push(2) stack.push(3) print(stack.pop()) stack.push(4) print(stack.pop()) print(stack.pop()) print(stack.pop())