一 栈的简介

 

 

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

  • 进栈(压栈):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)

 

posted on 2019-04-17 11:18  cs_1993  阅读(224)  评论(0编辑  收藏  举报