数据结构-队列

队列概念

  队列 Queue是一个数据集合,仅允许在列表一端插入,另一端进行删除

  进行插入的一端称为队尾(rear),插入动作称为进队或入队

  进行删除的一端称为队头(front),删除动作称为出队

  队列的性质:先进先出(First in,First out)

 

  队列能不能用列表实现呢?

  比较删除一个元素,列表操作的时间复杂度是O(n),这并不是我们所希望的

  那如果维护两个指针,一个指向队头,一个指向队尾,当出队删除元素时,我们只要移动队头指针就可以了,那是不是就解决了上面的问题了,似乎是解决了,但是又引出另外一个问题,就删除元素的空间是还在的,这样会很浪费空间的,那怎么充分利用这空间呢,或者说,怎么在进队时,使得进队的元素指向这些空间进行充分利用呢?

  为了解决上面问题,就引出了环形队列

 

环形队列

  环形队列满足下面条件:

  • 队头(front)和队尾(rear)相等时,队列为空
  • rear + 1 = front,队满,为了区分队空,留了一小块空间
  • 实现环形队列使用取余模型
  1. 队首指针前进1:front = (front + 1) % MaxSize
  2. 队尾指针前进1:rear = (rear + 1) % MaxSize
  3. 队空:rear == front
  4. 队满:  (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)

 

posted @ 2019-01-28 09:43  财经知识狂魔  阅读(276)  评论(0编辑  收藏  举报