1.栈
栈是一个数据集合,只能在一端进行插入或删除的操作
特点:后进先出
概念:栈顶/栈底
操作:进栈(push)/出栈(pop)/取栈顶(get_top)
补充
数据结构按逻辑结构分类:
1.线性结构 :数据结构中的元素存在一对一的相互关系
2.树结构:数据结构中的元素存在一对多的相互关系
3.图结构:数据结合中的元素存在多对一的相互关系
列表中的元素在计算机中的存储方式:顺序存储(连续的内存),实际上存储的是元素的地址
数组与列表有两个不同点:
1.数组元素的类型必须相同
2.数组长度固定
1.1代码
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):
return self.stack[-1]
def is_empty(self):
return len(self.stack)==0
'''
括号匹配问题
'''
def brace_math(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
if stack.is_empty():
return True
else:
return False
st=list('(()[][{()[]}])')
print(brace_math(st))
1.2用栈解决迷宫问题
栈–深度优先搜索(回溯法)
思路:
从一个节点开始,任意找下一个能走的点,当找不到能走的点时,退回上一个点寻找是否有其他方向的点。
#使用栈存储当前的路径
#所得路径不一定是最短的
代码
maze=[
[1,1,1,1,1],
[1,0,1,1,1],
[1,0,0,1,1],
[1,1,0,0,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)
]
#这是一个列表,元素是函数表达式,dirs[0](x,y)=(x+1,y)
def maze_path(x1,y1,x2,y2):
stack=[]
stack.append((x1,y1))
while(len(stack)>0):
cur_Node=stack[-1]
if cur_Node[0]==x2 and cur_Node[1]==y2:
#走到终点了
for p in stack:
print(p)
return True
#x,y四个方向:x-1,y-1,x+1,y+1
for dir in dirs:
next_Node=dir(cur_Node[0],cur_Node[1]) #将当前节点依次放进dirs中的四个函数表达式,如果得到的下一个节点可以走(值为0),则进栈,并将其值赋2,结束此次的for循环
#如果下一个节点能走
if maze[next_Node[0]][next_Node[1]]==0:
stack.append(next_Node)
maze[next_Node[0]][next_Node[1]]=2 #2表示已经走过
break
else: #与for对应,表示for循环结束了还是没有任何操作,执行以下语句,开始回退,
# print('next_Node',next_Node)
maze[cur_Node[0]][cur_Node[1]]=2
stack.pop()
else:
print('没有路')
return False
maze_path(1,1,3,3)
2.队列
队列(Queue):是一个数据集合
特点:仅允许在列表的一端进行插入,另一端进行删除
概念:插入动作称为进队或入队,进行插入的一端称为队尾(rear);删除动作称为出队,进行删除的一端称为队头(front)
性质:先进先出
2.1代码
#队列的实现方式--环形队列
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')
#判断队空
def is_empty(self):
return self.rear==self.front
#判断队满
def is_filled(self):
return (self.rear+1)%self.size==self.front
q=Queue(6)
for i in range(5):
q.push(i)
print(q.pop())
print(q.is_filled())
#队列的内置模块
from collections import deque
q=deque() #创建一个空队列
q1=deque([1,2,3,4,5],5) #创建时已队列已有这n个元素,队列长度为5,队满后,在有元素进队时,队首自动出队
q1.append(6)
print(q1)
q.append(1) #队尾进队
q.append(2)
print(q.popleft()) #队首出队
print(q)
'''
#用于双向列表
q.appendleft() #队首进队
q.pop() #队尾出队
'''
2.2队列解决迷宫问题
队列–广度优先搜索
思路:从一个节点开始,寻找–所有–接下来能走的点,继续不断寻找,指到找到出口
使用队列存储当前正在考虑的节点
代码
maze=[
[1,1,1,1,1],
[1,0,1,1,1],
[1,0,0,1,1],
[1,1,0,0,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):
cur_Node=path[-1]
real_path=[]
while cur_Node[2]!=-1:
real_path.append(cur_Node[0:2])
cur_Node=path[cur_Node[2]]
real_path.append(cur_Node[0:2])
real_path.reverse()
for node in real_path:
print(node)
def maze_path(x1,y1,x2,y2):
queue=deque() #创建一个队列,用于
queue.append((x1,y1,-1)) #-1表示x1,y1是自己进来的
path=[] #存放出队的节点
while len(queue)>0: #只要队不空,进行以下语句
cur_Node=queue.popleft() #队首出队,并将队首的值赋给cur_Node
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])
if maze[next_Node[0]][next_Node[1]]==0:
queue.append((next_Node[0],next_Node[1],len(path)-1)) #后续节点进队,记录那个节点带他来的
maze[next_Node[0]][next_Node[1]]=2
else:
print('没有路')
return False
maze_path(1,1,3,3)