• 06.队列、python标准库中的双端队列、迷宫问题


    class QueueUnderflow(ValueError):
        """队列为空"""
        pass
    
    
    class SQueue:
        def __init__(self, init_len=5):
            self._len = init_len  # 存储区长度
            self._elems = [0] * init_len  # 元素存储
            self._head = 0  # 表头元素下标
            self._num = 0  # 元素个数
    
        def is_empty(self):
            return self._num == 0
    
        def peek(self):
            """查看队头元素"""
            if self._num == 0:
                raise QueueUnderflow
            return self._elems[self._head]
    
        def dequeue(self):
            """出队"""
            if self._num == 0:
                raise QueueUnderflow
            e = self._elems[self._head]
            self._head = (self._head + 1) % self._len
            self._num -= 1
            return e
    
        def enqueue(self, e):
            """入队"""
            if self._head == self._len - 1:
                self._extend()
            self._elems[(self._head + self._num) % self._len] = e
            self._num += 1
    
        def _extend(self):
            """扩容操作"""
            old_len = self._len
            self._len *= 2
            new_elems = [0] * self._len
            for i in range(old_len):
                new_elems[i] = self._elems[(self._head + i) % old_len]
            self._elems, self._head = new_elems, 0
    
        def print(self):
            """打印从队头开始"""
            end = self._head + self._num
            print("list:", self._elems[self._head:end])

    python的deque类:

    import collections
    # deque双端队列,支持元素的两端插入和删除,采用一种双链表技术实现
    d = collections.deque()
    d.append(1)
    d.append(2)
    d.appendleft(0)
    print(d)  # deque([0, 1, 2])

    迷宫的递归求解:

    def make(maze, pos):
        """标记maze为已走过"""
        maze[pos[0]][pos[1]] = 2
    
    
    def passable(maze, pos):
        """检查maze位置是否可行"""
        return maze[pos[0]][pos[1]] == 0
    
    
    def find_path(maze, pos, end):
        dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # 东,南,西,北
        make(maze, pos)
        if pos == end:
            print(pos, end=' ')
            return True
        for i in range(4):
            nextp = [pos[0] + dirs[i][0], pos[1] + dirs[i][1]]
            if passable(maze, nextp):
                if find_path(maze, nextp, end):
                    print(pos, end=' ') 
                    return True
        return False
    
    
    def mazes():
        """初始化迷宫"""
        map = []
        for i in range(8):
            map.append([])
            for j in range(7):
                if i == 0 or i == 7 or j == 0 or j == 6:
                    map[i].append(1)
                else:
                    map[i].append(0)
        return map
    
    
    def showMap(map):
        """打印迷宫"""
        row, col = len(map), len(map[0])
        for i in range(row):
            for j in range(col):
                print(map[i][j], end='	')
            print()
        print()
    
    
    if __name__ == '__main__':
        mmap1 = mazes()
        showMap(mmap1)
        print(find_path(mmap1, [1, 1], [6, 5]))
        showMap(mmap1)
    """
    1    1    1    1    1    1    1
    1    0    0    0    0    0    1
    1    0    0    0    0    0    1
    1    0    0    0    0    0    1
    1    0    0    0    0    0    1
    1    0    0    0    0    0    1
    1    0    0    0    0    0    1
    1    1    1    1    1    1    1
    
    [6, 5] [5, 5] [4, 5] [3, 5] [2, 5] [1, 5] [1, 4] [1, 3] [1, 2] [1, 1] True
    1    1    1    1    1    1    1
    1    2    2    2    2    2    1
    1    0    0    0    0    2    1
    1    0    0    0    0    2    1
    1    0    0    0    0    2    1
    1    0    0    0    0    2    1
    1    0    0    0    0    2    1
    1    1    1    1    1    1    1
    """

    基于栈的回溯解决迷宫问题:

    def maze_solver(maze, start, end):
        """基于栈的回溯解决迷宫问题
        算法框架:
        入口start相关信息(位置和尚未探索方向)入栈;
        while 栈不空:
            弹出栈顶元素作为当前位置继续搜索
            while  当前位置存在未走过的方向:
                求出下一探测位置nextp
                if nextp 是出口:
                    输出路径并结束
                if nextp 未走过:
                    将当前位置和nextp顺序入栈并退出内层循环
    
        """
        dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # 东,南,西,北
        if start == end:
            print(start)
            return
        st = SStack()
        make(maze, start)  # 标记走过
        # 4个方向分别编码为0,1,2,3,表示dirs的下标
        st.push((start, 0))  # 入口和方向0入栈
        while not st.is_empty():
            pos, nxt = st.pop()
            for i in range(nxt, 4):
                nextp = [pos[0] + dirs[i][0], pos[1] + dirs[i][1]]  # 算出下一位置
                if nextp == end:  # 到达出口
                    print(nextp, end=' ')  # 终点位置
                    print(pos, end=' ')  # 当前位置
                    st.print()  # 经过的位置
                    return
                if passable(maze, nextp):  # 位置可行
                    st.push((pos, i + 1))  # 当前位置,与下一方向入栈,因为现在走的是i,如果回退就应走i+1了
                    make(maze, nextp)
                    st.push((nextp, 0))  # 新位置入栈,方向都是从0开始
                    break  # 退出内层循环,下层讲以新栈顶为当前位置继续
        print("no path found.")
    
    if __name__ == '__main__':
        mmap1 = mazes()
        showMap(mmap1)
        print(maze_solver(mmap1, [1, 1], [6, 5]))
    
    """
    1    1    1    1    1    1    1    
    1    0    0    0    0    0    1    
    1    0    0    0    0    0    1    
    1    0    0    0    0    0    1    
    1    0    0    0    0    0    1    
    1    0    0    0    0    0    1    
    1    0    0    0    0    0    1    
    1    1    1    1    1    1    1    
    
    [6, 5] [5, 5] [([4, 5], 2), ([3, 5], 2), ([2, 5], 2), ([1, 5], 2), ([1, 4], 1), ([1, 3], 1), ([1, 2], 1), ([1, 1], 1)]
    None
    1    1    1    1    1    1    1    
    1    2    2    2    2    2    1    
    1    0    0    0    0    2    1    
    1    0    0    0    0    2    1    
    1    0    0    0    0    2    1    
    1    0    0    0    0    2    1    
    1    0    0    0    0    0    1    
    1    1    1    1    1    1    1    
    """

    基于队列的迷宫求解算法:

    def maze_solver_queue(maze, start, end):
        """基于队列的迷宫求解算法:
        基本框架:
        将start标记为已到达
        start入队
        while 队列里还有未充分探查的位置:
            取出一个位置pos
            检查pos的相邻位置
                遇到end结束
                未探查的都mark并入队
        队列空,探索失败
        """
        dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # 东,南,西,北
        if start == end:
            print(start)
            return
        qu = SQueue()
        make(maze, start)
        qu.enqueue(start)
        while not qu.is_empty():
            pos = qu.dequeue()
            for i in range(4):
                nextp = [pos[0] + dirs[i][0], pos[1] + dirs[i][1]]  # 算出下一位置
                if passable(maze, nextp):
                    if nextp == end:
                        print("path find")
                        return
                    make(maze, nextp)
                    qu.enqueue(nextp)
        print("No path.")
    
    if __name__ == '__main__':
        mmap1 = mazes()
        showMap(mmap1)
        print(maze_solver_queue(mmap1, [1, 1], [6, 5]))
        showMap(mmap1)
    
    
    """
    1    1    1    1    1    1    1    
    1    0    0    0    0    0    1    
    1    0    0    0    0    0    1    
    1    0    0    0    0    0    1    
    1    0    0    0    0    0    1    
    1    0    0    0    0    0    1    
    1    0    0    0    0    0    1    
    1    1    1    1    1    1    1    
    
    path find
    None
    1    1    1    1    1    1    1    
    1    2    2    2    2    2    1    
    1    2    2    2    2    2    1    
    1    2    2    2    2    2    1    
    1    2    2    2    2    2    1    
    1    2    2    2    2    2    1    
    1    2    2    2    2    0    1    
    1    1    1    1    1    1    1    
    """

    从打印结果看,基于栈的搜索如果顺利,可能只探查不多的位置就找到出口,是一条路径;

    基于队列的搜索是一种步步为营的搜索,只有在检查完所有与入口同样距离位置之后才更多前进一步

    根据搜索过程的特点:把基于栈的搜索称为深度优先搜索,

    基于队列的搜索称为宽度优先搜索

  • 相关阅读:
    Linux查看当前系统的发行版信息
    用 CentOS 7 打造合适的科研环境
    消息队列的使用场景
    RabbitMQ几种Exchange 模式
    JMS规范概览
    消息队列的学习
    springMVC参数传递实例
    java8时间处理实例
    windows电脑常用必备软件
    http后台json解析实例
  • 原文地址:https://www.cnblogs.com/fly-book/p/11720129.html
Copyright © 2020-2023  润新知