zoukankan      html  css  js  c++  java
  • 数据结构之栈与队列

    一 栈的简介

    栈是一个数据集合,可以理解为只能在一段进行插入或删除操作的列表
    栈的特点:后进先出
    栈的概念:栈顶,栈底
    栈的操作:

    • 进栈(压栈):push
    • 出栈:pop
    • 取栈顶:gettop

    使用一般的列表结构可实现栈

    • 进栈: li.append
    • 出栈: li.pop
    • 取栈顶: li[-1]

    Python代码实现栈:

    class stack:
    
        def __init__(self):
            self.stack = []
    
        def push(self, element):
            self.stack.append(element)
    
        def pop(self):
            return self.stack.pop()
    
        def get_top(self):
            if len(self.stack) > 0:
                return self.stack[-1]
            else:
                return None
    
        def is_empty(self):
            return len(self.stack) == 0
    
    sta = stack()
    sta.stack = [1, 2]
    sta.push(5)
    print(sta.pop())
    print(sta.pop())
    print(sta.pop())
    print(sta.is_empty())

     二 栈的应用示例 —— 括号匹配问题

    括号匹配问题: 给一个字符串,其中包括小括号,中括号,大括号,求该字符串中的括号是否匹配
    例如:

    • ()()[]{} 匹配
    • ([{()}]) 匹配
    • []( 不匹配
    • [(]) 不匹配
    def brace_match(s):
        match = {'}': '{', ']': '[', ')': '('}
        stack = Stack()
        for ch in s:
            if ch in {'(', '[', '{'}:
                stack.push(ch)
            else:
                if stack.is_empty():
                    return False
                elif stack.get_top() == match[ch]:
                    stack.pop()
                else:  # stack.get_top() != match[ch]
                    return False
    
        return '匹配成功'
    
    
    print(brace_match(["{", "(", ")", "}"]))

    三 队列的简介

    • 队列是一个数据集合,仅允许在列表的一端进行插入,另一端进行删除,
    • 进行插入的一端称为队尾(rear),插入动作称之为进队或入队
    • 进行删除的一端称之为对头(front),删除动作称为出队
    • 队列的性质:先进先出

    双向队列:对列的两端都允许进行进队和出队操作

    队列的实现

    队列能否简单用列表实现?为什么?

    • 初步设想:列表+两个下标指针
    • 创建一个列表和两个变量,front变量指向队首,rear变量指向队尾。初始时,front和rear都为0。
    • 进队操作:元素写到li[rear]的位置,rear自增1。
    • 出队操作:返回li[front]的元素,front自减1。

    队列的实现原理-----环形对列

     

    环形队列:当队尾指针front == Maxsize + 1时,再前进一个位置就自动到0。

    • 实现方式:求余数运算
    • 队首指针前进1:front = (front + 1) % MaxSize
    • 队尾指针前进1:rear = (rear + 1) % MaxSize
    • 队空条件:rear == front

    队列实现代码

    class Queue:
        def __init__(self, size=100):
            self.queue = [0 for _ in range(size)]
            self.rear = 0  # 队尾指针
            self.front = 0  # 队首指针
            self.size = size
    
        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")
    
        # 判断队列是否是空的
        def is_empty(self):
            return self.rear == self.front
    
        # 判断队满
        def is_filled(self):
            return (self.rear+1) % self.size == self.front
    
    q = Queue(5)
    for i in range(4):
        q.push(i)
    
    print(q.is_filled())
    print(q.pop())
    q.push(5)
    print(q.pop())
    print(q.pop())
    print(q.pop())
    print(q.pop())

    对列的内置模块

    from collections import deque
    queue = deque()#创建队列
    queue.append('first')
    queue.append('second')
    queue.append('third')
    print(queue.popleft())
    print(queue.popleft())
    print(queue.popleft())#出队,,先进先出
    print([i for i in queue])  #查看队列里的元素
    
    queue.appendleft('one')#双向队列队首进队
    queue.appendleft('two')#双向队列队首进队
    queue.appendleft('five')#双向队列队首进队
    print(queue.pop())
    print(queue.pop())#双向队列从队尾出队
    print([i for i in queue])
    
    
    
    #单向队列
    from queue import Queue
    q = Queue()
    q.put('a')
    q.put('b')
    q.put('c')
    print(q.get())  #a

    四 栈和队列的应用----- 迷宫问题

    给一个二维列表, 表示迷宫(0表示通道,1表示围墙)。给出算法,求一条走出迷宫的路径

    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]
    ]

    1  栈实现回溯法(深度优先)

    思路:从一个节点开始,任意找下一个能走的点,当找不到能走的点时,退回上一个点寻找是否有其他方向的点
    使用栈存储当前路径

    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]
    ]
    
    # 四个方向坐标 上x-1,y; 下x+1,y;  左:x, y-1; 右 x,y+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 maze_path(x1, y1, x2, y2):
        stack = []
        stack.append((x1, y1))
        while (len(stack) > 0):
            curNode = stack[-1]  # 当前位置
            if curNode[0] == x2 and curNode[1] == y2:
                # 走到终点了:
                for p in stack:
                    print(p)
                return True
            # 四个方向坐标 上x-1,y; 下x+1,y;  左:x, y-1; 右 x,y+1
            for dir in dirs:
                nextNode = dir(curNode[0], curNode[1])  # 下一个节点
                # 如果下一个节点能走
                if maze[nextNode[0]][nextNode[1]] == 0:
                    stack.append(nextNode)
                    maze[nextNode[0]][nextNode[1]] = 2  # 2表示这个玩位置已经走过
                    break
            else:
                maze[nextNode[0]][nextNode[1]] = 2
                stack.pop()
        else:
            print('没有出路')
            return False
    
    
    maze_path(1, 1, 8, 8)

     2  队列实现广度搜索

    思路:

    • 从一个节点开始,寻找所有接下来能继续走的点,继续不断寻找,直到找到出口
    • 使用队列存储当前正在考虑的节点

    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)
    ]
    
    from collections import deque
    
    
    def print_r(path):
        real_path = []     # 出去的路径
        i = len(path) - 1  # 最后一个节点
        print(path)
        print(i)
        while i >= 0:      # 判断最后一个节点的标记是否为-1,如果是-1说明是起始点,如果不是-1就继续查找
            real_path.append(path[i][0:2])   # 拿到并添加节点x,y坐标信息
            i = path[i][2]                   # 这里i[2]是当前节点的前一步节点的标识:path的下标,因此path[i[2]]拿到前一节点
        real_path.reverse()                  # 将列表倒序,将前面生成的从后往前的列表变为从前往后
        for node in real_path:
            print(node)
    
    
    def maze_path_queue(x1, y1, x2, y2):
        queue = deque()
        path = []
        queue.append((x1, y1, -1))
        while len(queue) > 0:  # 当队列不空时循环
            cur_node = queue.popleft()  # 当前节点
            path.append(cur_node)
            if cur_node[0] == x2 and cur_node[1] == y2:
                # 到达终点
                print_r(path)
                return True
            for dir in dirs:
                next_node = dir(cur_node[0], cur_node[1])  # curNode[0],curNode[1]分别是当前节点x、y
                if maze[next_node[0]][next_node[1]] == 0:  # 如果有路可走
                    queue.append((next_node[0], next_node[1], len(path) - 1))  # 后续节点进队,标记谁让它来的:path最后一个元素的下标
                    maze[next_node[0]][next_node[1]] = 2  # 设置为2,标记为已经走过
    
        return False
    
    
    maze_path_queue(1, 1, 8, 8)
  • 相关阅读:
    竞赛备考建议
    谷山丰的一生
    从首个IMO季军谈起 作者 : 付云皓
    孔庆东:单刀赴高考
    LaTeX 技巧 802:国内期刊 CCT 模板编译经验
    数学书籍推荐
    翻译
    printf中用法详解
    黎活明给程序员的忠告【转】
    log4j2配置文件log4j2.xml详解(转载)
  • 原文地址:https://www.cnblogs.com/harryblog/p/10722305.html
Copyright © 2011-2022 走看看