1. 理解算法前提
1.1 理解递归
递归:recursion
简单来说就是引用(或者调用)自身的意思。用递归实现的功能都可以用循环实现,但是有些时候递归函数更易读
# 通过循环实现幂函数
def power(x, n):
result = 1
for i in range(n):
result *= x
return result
# 通过递归实现幂函数
def power(x, n):
if n == 0:
return 1
else:
# 注意此时调用power函数时的输入:x, n-1
# 如果是输入: x, n 该函数将会陷入无限循环, 直到运行崩溃
return x * power(x, n-1)
递归函数一定要以一个最小可能性问题结束,上述代码中的最小可能性问题就是:n == 0
1.2 Python生成器
关键字:yield
任何包含yield语句的函数称为生成器
生成器的行为和普通函数有很大的区别,它不像return那样返回值,而是每次产生多个值。每次产生一个值(使用yield语句),函数就会被冻结:即函数停在那点等待被重新唤醒。函数被重新唤醒后就从停止的那点开始执行。
# 定义一个递归生成器
# 问题描述:按从左到右的顺序取出序列中的每个元素,不论该序列内部嵌套了多少层序列
# 此处忽略输入为字符串的序列,我们测试的时候用列表
def flatten(nested):
try:
for sublist in nested:
for element in flatten(sublist):
yield element
except:
yield nested
# 调用该生成器
list(flatten([[[1],2],3,4,[5,[6,7]],8]))
# 测试一下返回的到底是啥
g = flatten([[[1],2],3,4,[5,[6,7]],8])
print(g)
while(True):
try:
print(next(g))
except:
break
通过上述演示,我们可以看到生成器调用结束后返回了一个生成器对象,通过next函数可以逐个获取生成器内的每个返回值
如果上述递归生成器改成普通函数,则需要一个额外的序列去存储每次生成的element
2. 八皇后算法
2.1 八皇后问题描述
在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法
2.2 算法核心
2.2.1 检测冲突
def conflict(state, nextX):
'''检测冲突, 逻辑如下
state = (y1, y2, y3, ...)
第一个皇后的位置: (0,y1)
第二个皇后的位置: (1,y2)
第三个皇后的位置: (2,y3)
依此类推
nextX 是下一个皇后的位置的x坐标, 从0开始
'''
# nextY 是下一个皇后的位置的y坐标, 从0开始, 于是: nextY = len(state)
nextY = len(state)
# 循环已知的皇后
for i in range(nextY):
# state[i] 是前面的皇后的位置的x坐标, i=0表示第一个皇后, i=1表示第二个皇后, 依次类推
# 下一个皇后和前面任意一个皇后的位置的x坐标不能相同(同列), x坐标距离和y坐标距离不能相等(同斜线)
if abs(nextX - state[i]) in (0, nextY - i):
return True
return False
2.2.2 基于Python生成器求解
def queens(num=8, state=()):
# 从第一列判断到第num-1列
for pos in range(num):
# 不冲突
if not conflict(state, pos):
# 已经是最后一个皇后了
if len(state) == num-1:
# 返回此皇后的位置
yield (pos,)
else:
# 递归获取下一个皇后的位置, 输入为:下一行列数, 前面皇后的位置信息
for result in queens(num, state + (pos,)):
# 返回此皇后的位置 + 后面几个皇后的位置, 因为是递归, 所以是此皇后的放前面
yield (pos,) + result
2.2.3 输出结果并图形化输出摆法
def prettyprint(solution):
def line(pos, length=len(solution)):
print((' - ' * pos) + ' x ' + (' - ' * (length - pos - 1)))
print(solution)
for pos in solution:
line(pos)
# 输出摆法
print(len(list(queens(4))))
# 优化输出结果
for solution in queens(4):
prettyprint(solution)
Congratulations
恭喜你学习到了第一个用Python实现的经典回溯算法——八皇后问题,更多进阶内容请继续关注,感兴趣记得订阅哦!!!