队列概念
队列 Queue是一个数据集合,仅允许在列表一端插入,另一端进行删除
进行插入的一端称为队尾(rear),插入动作称为进队或入队
进行删除的一端称为队头(front),删除动作称为出队
队列的性质:先进先出(First in,First out)
队列能不能用列表实现呢?
比较删除一个元素,列表操作的时间复杂度是O(n),这并不是我们所希望的
那如果维护两个指针,一个指向队头,一个指向队尾,当出队删除元素时,我们只要移动队头指针就可以了,那是不是就解决了上面的问题了,似乎是解决了,但是又引出另外一个问题,就删除元素的空间是还在的,这样会很浪费空间的,那怎么充分利用这空间呢,或者说,怎么在进队时,使得进队的元素指向这些空间进行充分利用呢?
为了解决上面问题,就引出了环形队列
环形队列
环形队列满足下面条件:
- 队头(front)和队尾(rear)相等时,队列为空
- rear + 1 = front,队满,为了区分队空,留了一小块空间
- 实现环形队列使用取余模型
- 队首指针前进1:front = (front + 1) % MaxSize
- 队尾指针前进1:rear = (rear + 1) % MaxSize
- 队空:rear == front
- 队满: (rear + 1) % MaxSize == front
class Queue: def __init__(self, size=100): self.queue = [0 for _ in range(size)] self.size = size self.rear = 0 #队尾指针 self.front = 0 #队首指针 def push(self, element): if not self.is_filled: self.rear = (self.rear + 1) % self.size self.queue[self.rear] = element else: raise IndexError("Queue is filled.") def pop(self): if not self.is_empty: self.front = (self.front + 1) % self.size return self.queue[self.front] else: raise IndexError("Queue is empty.") @property def is_empty(self): return self.rear == self.front @property def is_filled(self): return (self.rear + 1) % self.size == self.front
Python队列内置模块
- 双向队列: from collections import deque(一般构造数据结构用这个,保证线程安全,用import queue)
- 创建队列:queue = deque()
- 进队:append()
- 出队:popleft()
- 双向队列队首进队:appendleft()
- 双向队列队尾出队:pop()
其中deque,第一参数是指定初始队列值,而第二参数则是指定队列的长度,不过它在队满的情况下,会自动出队之前的值,利用这个特性我们可以实现linux命令tail取后几行操作
from collections import deque def tail(n): with open('test.txt', 'r') as f: q = deque(f, n) return q for line in tail(5): print(line, end="")
利用队列实现广度优先走迷宫
from collections import deque maze = [ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 0, 0, 0, 1, 0, 1], [1, 0, 0, 1, 0, 0, 0, 1, 0, 1], [1, 0, 0, 0, 0, 1, 1, 0, 0, 1], [1, 0, 1, 1, 1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 1, 0, 0, 0, 0, 1], [1, 0, 1, 0, 0, 0, 1, 0, 0, 1], [1, 0, 1, 1, 1, 0, 1, 1, 0, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ] dirs = [ lambda x, y: (x + 1, y), lambda x, y: (x - 1, y), lambda x, y: (x, y - 1), lambda x, y: (x, y + 1) ] def print_r(path): curNode = path[-1] realpath = [] while curNode[2] == -1: realpath.append(curNode[0:2]) curNode = path[curNode[2]] realpath.append(curNode[0:2]) # 起点 realpath.reverse() for node in realpath: print(node) def maze_path_queue(x1, y1, x2, y2): queue = deque() queue.append((x1, y1, -1)) path = [] while len(queue) > 0: curNode = queue.pop() path.append(curNode) if curNode[0] == x2 and curNode[1] == y2: # 终点 print_r(path) return True for dir in dirs: nextNode = dir(curNode[0], curNode[1]) if maze[nextNode[0]][nextNode[1]] == 0: queue.append((nextNode[0], nextNode[1], len(path) - 1)) # 后续节点进队,记录哪个节点带他来的 maze[nextNode[0]][nextNode[1]] = 2 # 标记为已经走过 else: print("没有路") return False maze_path_queue(1, 1, 8, 8)