数据结构
程序=数据结构+算法
数据结构就是设计数据以何种方式组织并存储在计算机中。列表、集合与字典等都是一种数据结构。
小Tips:列表中的元素是怎样存储的,操作的时间复杂度是多少?
Python将数存放在一个内存单元中,在列表中的元素指向那个内存单元。所以列表中的元素在内存单元中可能在一起,也可能不在一起。
[].insert()和[].remove()的时间复杂度为o(n)
[].append()和[].pop()的时间复杂度为o(1)
栈
栈(Stack)是一个数据集合,可以理解为只能在一端进行插入或删除操作的列表。
栈的特点:后进先出
栈的基本操作:
- 进栈(压栈):push
- 出栈:pop
- 取栈顶(看看栈顶是谁):gettop
Python中实现栈:
进栈函数:append
出栈函数:pop
查看栈顶函数:li[-1]
小Tips:
递归出错的原因是:爆栈
示例:给一个字符串,其中包含小括号、中括号、大括号,求该字符串中的括号是否匹配。
思路:检查字符串是否包含"{","[","("如果包含则将其入栈,遇到"}","]",")"时检查当前栈顶,相同则将其出栈,否则返回False
1 def check_kuohao(str):
2 stack = []
3 for i in str:
4 if i in {'{','[','('}:
5 stack.append(i)
6 elif i == '}':
7 if len(stack) > 0 and stack[-1] == '{':
8 stack.pop()
9 else:
10 return False
11 elif i == ']':
12 if len(stack) > 0 and stack[-1] == '[':
13 stack.pop()
14 else:
15 return False
16 elif i == ')':
17 if len(stack) > 0 and stack[-1] == '(':
18 stack.pop()
19 else:
20 return False
21
22 if len(stack) == 0:
23 return True
24 else:
25 return False
26
27 print(check_kuohao('([)]'))
View Code
示例:迷宫问题(深度优先,一条路走到黑)
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]
]
def mazepath(x1,y1,x2,y2):
dirs = [
# lambda 参数1,参数2:(返回值格式)
lambda x, y: (x + 1, y), # 向下走一格
lambda x, y: (x - 1, y), # 向上走一格
lambda x, y: (x, y - 1), # 向左走一格
lambda x, y: (x, y + 1) # 向右走一格
]
stack = [] # 初始化一个栈
stack.append((x1,y1)) # 将起始坐标推入栈中
while len(stack) > 0:
curNode = stack[-1] # 查看栈顶元素
if curNode[0] == x2 and curNode[1] == y2: # 到达终点
for i in stack:
print(i)
return True
else:
for d in dirs:
nextNode = d(curNode[0],curNode[1]) # 将()中的元素做相应的操作,还没推入栈中
if maze[nextNode[0]][nextNode[1]] == 0: # 这条路可以走
stack.append(nextNode) # 将这个新位置入栈
maze[nextNode[0]][nextNode[1]] = -1 # 将新位置标记为已经走过,防止死循环
break
else: # 当前位置上下左右都不能走,后退一步
stack.pop()
return False # 栈为空,无路可走
print(mazepath(1,1,8,8))
队列
队列(Queue)是一个数据集合,仅允许在列表的一端进行插入,另一端进行删除。
进行插入的一端称为队尾(rear),插入动作称为进队或入队,进行删除的一端称为队头(front),删除动作称为出队
队列的性质:先进先出
双向队列:队列的两端都允许进行进队和出队操作。
队列的实现原理:
初步设想:列表+两个下标指针
创建一个列表和两个变量,front变量指向队首,rear变量指向队尾。初始时,front和rear都为0。
进队操作:元素写到li[rear]的位置,rear自增1。
出队操作:返回li[front]的元素,front自减1。
这样队列会不够用,所以我可以把它的首尾连接起来。
环形队列:
实现方式:求余数运算
队首指针前进1:front = (front + 1) % MaxSize
队尾指针前进1:rear = (rear + 1) % MaxSize
队空条件:rear == front
队满条件:(rear + 1) % MaxSize == front
Python实现队列:
from collections import deque # 双向队列
创建队列:queue = deque(li)
进队:append
出队:popleft
双向队列队首进队:appendleft
双向队列队尾进队:pop
示例:迷宫问题(广度优先)
思路:从一个节点开始,寻找所有下面能继续走的点。继续寻找,直到找到出口。
1 from collections import deque
2
3 mg = [
4 [1,1,1,1,1,1,1,1,1,1],
5 [1,0,0,1,0,0,0,1,0,1],
6 [1,0,0,1,0,0,0,1,0,1],
7 [1,0,0,0,0,1,1,0,0,1],
8 [1,0,1,1,1,0,0,0,0,1],
9 [1,0,0,0,1,0,0,0,0,1],
10 [1,0,1,0,0,0,1,0,0,1],
11 [1,0,1,1,1,0,1,1,0,1],
12 [1,1,0,0,0,0,0,1,0,1],
13 [1,1,1,1,1,1,1,1,1,1]
14 ]
15
16 dirs = [lambda x, y: (x + 1, y),
17 lambda x, y: (x - 1, y),
18 lambda x, y: (x, y - 1),
19 lambda x, y: (x, y + 1)]
20
21 def print_p(path):
22 curNode = path[-1]
23 realpath = []
24 print('迷宫路径为:')
25 while curNode[2] != -1:
26 realpath.append(curNode[0:2])
27 curNode = path[curNode[2]]
28 realpath.append(curNode[0:2])
29 realpath.reverse()
30 print(realpath)
31
32 def mgpath(x1, y1, x2, y2):
33 queue = deque()
34 path = []
35 queue.append((x1, y1, -1))
36 while len(queue) > 0:
37 curNode = queue.popleft()
38 path.append(curNode)
39 if curNode[0] == x2 and curNode[1] == y2:
40 #到达终点
41 print_p(path)
42 return True
43 for dir in dirs:
44 nextNode = dir(curNode[0], curNode[1])
45 if mg[nextNode[0]][nextNode[1]] == 0: # 找到下一个方块
46 queue.append((*nextNode, len(path) - 1))
47 mg[nextNode[0]][nextNode[1]] = -1 # 标记为已经走过
48 return False
49
50
51 mgpath(1,1,8,8)
View Code
链表
链表中每一个元素都是一个对象,每个对象称为一个节点,包含有数据域key和指向下一个节点的指针next。通过各个节点之间的相互连接,最终串联成一个链表。
定义节点:
class Node(object):
def __init__(self, item):
self.item = item # 当前节点的值
self.next = None # 下一节点的值
a = Node(1)
b = Node(2)
c = Node(3)
a.next = b
b.next = c
链表节点的插入和删除
插入:
p.next = curNode.next
curNode.next = p
删除:
p = curNode.next
curNode.next = curNode.next.next
del p
建立链表:
头插法
def createLinkListF(li):
l = Node()
for num in li:
s = Node(num)
s.next = l.next
l.next = s
return l
尾插法
def createLinkListR(li):
l = Node()
r = l #r指向尾节点
for num in li:
s = Node(num)
r.next = s
r = s
双链表
双链表中每个节点有两个指针:一个指向后面节点、一个指向前面节点。
节点定义:
class Node(object):
def __init__(self, item=None):
self.item = item
self.next = None
self.prior = None
插入和删除
插入:
p.next = curNode.next
curNode.next.prior = p
p.prior = curNode
curNode.next = p
删除:
p = curNode.next
curNode.next = p.next
p.next.prior = curNode
del p
建立双链表
def createLinkListR(li):
l = Node()
r = l
for num in li:
s = Node(num)
r.next = s
s.prior = r
r = s
return l, r