看书看到迭代器和生成器了,一般的使用是没什么问题的,不过很多时候并不能用的很习惯

书中例举了经典的八皇后问题,作为一个程序员怎么能够放过做题的机会呢,于是乎先自己来一遍,于是有了下面这个ugly的代码

def table(m, lst):
'''绘制m列的棋盘,每行有个皇后旗子'''
head = '┌' + '─┬' * (m-1) + '─┐'
row = lambda x: '│' + ' │' * x + '╳│' + ' │' * (m - x - 1)
trow = '├' + '─┼' * (m-1) + '─┤'
tail = '└' + '─┴' * (m-1) + '─┘'
print(head)
for i, n in zip(range(len(lst)), lst):
print (row(n))
print (trow) if i < len(lst) - 1 else print (tail)
queens = [0]*8
def rightqueen(lst, m):
'''判断lst的所有皇后是否与下一行的m位置皇后干涉,不干涉则返回True'''
for i, n in zip(range(len(lst)), lst):
if(n == m or len(lst) - i == m - n or len(lst) - i == n - m):
return False
return True
def calqueen(lst, n):
'''求解第n个皇后与之前的皇后不干涉
如果第n行成功则求解n+1行,否则求解n-1行且复位n行'''
for i in range(lst[n], 8):
if rightqueen(lst[:n], i):
lst[n] = i
calqueen.count += 1
print(calqueen.count)
table(8, lst[:n+1])
if n < 7: calqueen(lst, n+1)
break
else:
#如果遍历8个之后仍然没有解则重新求解上一行
lst[n] = 0
lst[n-1] += 1
print('求解上一行')
calqueen(lst, n-1)
calqueen.count = 0
calqueen(queens, 0)

前面那个table函数只是用来绘制棋盘的,写完后感觉Python确实是很简洁的语言,当然可以更简洁,现在我的代码风格还保留很强的C语言风格,这个转变估计还需要一段时间

说他ugly倒并不是因为他没有使用迭代器,主要的问题在于函数的两个分支都使用了迭代,只有达到第八层时才会结束迭代,这个代码迭代次数要达到100多次,这样多的迭代其内存占用以及运行效率都是不太好的

因此改进版的代码应该是在失败的时候返回运行结果以便减少迭代次数,调整后的代码如下:

def table(m, lst):
'''绘制m列的棋盘,每行有个皇后旗子'''
head = '┌' + '─┬' * (m-1) + '─┐'
row = lambda x: '│' + ' │' * x + '╳│' + ' │' * (m - x - 1)
trow = '├' + '─┼' * (m-1) + '─┤'
tail = '└' + '─┴' * (m-1) + '─┘'
print(head)
for i, n in zip(range(len(lst)), lst):
print (row(n))
print (trow) if i < len(lst) - 1 else print (tail)
queens = [0]*8
def rightqueen(lst, m):
'''判断lst的所有皇后是否与下一行的m位置皇后干涉,不干涉则返回True'''
for i, n in zip(range(len(lst)), lst):
if(n == m or len(lst) - i == m - n or len(lst) - i == n - m):
return False
return True
def calqueen(lst, n):
'''求解第n个皇后与之前的皇后不干涉
如果第n行成功则求解n+1行,否则求解n-1行且复位n行'''
for i in range(8):
if rightqueen(lst[:n], i):
lst[n] = i
calqueen.count += 1
print(calqueen.count)
table(8, lst[:n+1])
if n < 7:
if not calqueen(lst, n+1): continue
return True
else:
#如果遍历8个之后仍然没有解则重新求解上一行
print('求解上一行')
calqueen.count -= 1
return False
calqueen.count = 0
calqueen(queens, 0)

减少了迭代次数后至少程序是比较合理的了,不过在看过使用生成器,迭代器的代码之后还是觉得我对Python以及迭代器编程的感觉太少了,为了增强感觉,合上书按照自己的理解又盲写了一遍,当然代码跟书上的不太一致了,但思想差不多

def table(m, lst):
'''绘制m列的棋盘,每行有个皇后旗子'''
head = '┌' + '─┬' * (m-1) + '─┐'
row = lambda x: '│' + ' │' * x + '╳│' + ' │' * (m - x - 1)
trow = '├' + '─┼' * (m-1) + '─┤'
tail = '└' + '─┴' * (m-1) + '─┘'
print(head)
for i, n in zip(range(len(lst)), lst):
print (row(n))
print (trow) if i < len(lst) - 1 else print (tail)
def rightqueen(lst, m):
'''判断lst的所有皇后是否与下一行的m位置皇后干涉,不干涉则返回True'''
for i, n in zip(range(len(lst)), lst):
if(n - m in (0, len(lst) - i, i - len(lst))):
return False
return True
def calqueen(lst, n):
'''求解第n个皇后与之前的皇后不干涉
只在第八层提交数据,其余每一层都是把本层的所有可能和后面的所有可能相加'''
for i in range(8):
calqueen.total += 1
if rightqueen(lst, i):
calqueen.count += 1
if n == 7:
calqueen.number += 1
print(calqueen.number, calqueen.count, calqueen.total)
yield lst + [i]
else:
for l in calqueen(lst + [i], n + 1):
yield l
calqueen.total = 0
calqueen.count = 0
calqueen.number = 0
for l in calqueen([], 0):
table(8, l)

事实上两个函数的核心代码只有13行,使用in和元组来替代3个条件判断,用迭代器替代对函数返回值的判断,因为如果迭代器为空,则上层调用函数遍历就会失败,自动解决了我原来算法的问题

而且这个程序能够遍历出92个八皇后的解法,虽然我之前的代码改改应该也能实现,但是不会有这么精简

因为生成器的存在,使得迭代器在使用时非常的方便,后期在处理一些需要循环层进迭代的方法时也应该优先考虑生成器,迭代器的方式.

Python学习二(生成器和八皇后算法)的更多相关文章

  1. Python学习二:词典基础详解

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7862377.html 邮箱:moyi@moyib ...

  2. python基础教程总结8——特殊方法,属性,迭代器,生成器,八皇后问题

    1. 重写一般方法和特殊的构造方法 1.1 如果一个方法在B类的一个实例中被调用(或一个属性被访问),但在B类中没有找到该方法,那么会去它的超类A里面找. class A: ... def hello ...

  3. 八皇后算法的另一种实现(c#版本)

    八皇后: 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于 ...

  4. python学习笔记系列----(八)python常用的标准库

    终于学到了python手册的最后一部分:常用标准库.这部分内容主要就是介绍了一些基础的常用的基础库,可以大概了解下,在以后真正使用的时候也能想起来再拿出来用. 8.1 操作系统接口模块:OS OS模块 ...

  5. Prolog学习:数独和八皇后问题

    上一篇简单介绍了下Prolog的一些基本概念,今天我们来利用这些基本概念解决两个问题:数独和八皇后问题. 数独 数独是一个很经典的游戏: 玩家需要根据n×n盘面上的已知数字,推理出所有剩余空格的数字, ...

  6. python学习之生成器

    4.6 生成器Generrator ​ 生成器本质就是迭代器.python社区生成器与迭代器是一种. ​ 生成器与迭代器的唯一区别:生成器是我们自己用python代码构建的 4.6.1生成器初识 py ...

  7. Python学习二十八周(vue.js)

    一.指令 1.一个例子简单实用vue: 下载vue.js(这里实用1.0.21版本) 编写html代码: <!DOCTYPE html> <html lang="en&qu ...

  8. python学习 (二十八) Python的for 循环

    1: for 循环可以循环如下类型: my_string = "abcabc" // 字符串类型 for c in my_string: print(c, end=' ') car ...

  9. python学习之---生成器

    通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含1000万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元 ...

随机推荐

  1. bash while/until循环学习

    while循环:条件满足,则循环:失败,则退出 如何退出? 必须有时刻,条件测试不成功 ? :条件控制变量 while 条件测试:do 循环体 done until循环:条件不满足,则循环:否则,退出 ...

  2. 在skyDriver上保存代码

    在家里写的代码, 有时候在公司也想打开改一改. 以前, 我都是使用优盘进行拷贝, 或者直接在优盘上进行操作. 有时, 忘了带优盘就傻眼了. 也想过直接托管到代码托管网站. 但主流的一些托管,都是要开源 ...

  3. Matlab 进阶学习记录

    最近在看 Faster RCNN的Matlab code,发现很多matlab技巧,在此记录: 1. conf_proposal  =  proposal_config('image_means', ...

  4. JSBinding+Bridge.Net:框架代码与逻辑代码的关系

    在JSB+Bridge工程中你可以同时维护Cs版本和Js版本的游戏. 框架代码:简称framework,表示那些不进行热更的代码.注意,这包括你自己写的代码,也包括引用的Dll,比如UnityEngi ...

  5. .NET设计规范————类型设计规范

    类型设计规范 从CLR的角度看,只有值类型和引用类型两种类型,但是从框架设计的角度我们把类型从逻辑上分了更多的组.如下所示: 类是引用类型的一般情况,占了框架中的大多情况,类的流行归于它支持面向对象的 ...

  6. RAID简介

    RAID(独立磁盘冗余阵列)可以提供较普通磁盘更高的速度,安全性,所以服务器在安装时会选择创建RAID.RAID的创建有两种方式:软RAID(通过操作系统软件来实现)和硬raid(使用硬件整列卡) r ...

  7. [2014.01.27]WFsoft.wfLibrary.wfIniFile 1.5

    完全支持.net 2.0编写,对下一代操作系统平稳过渡.     不使用[DllImport("kernel32")]的方式,完全自主的.net 2.0自主解析.    完整支持键 ...

  8. 承接Holograms外包 Holograms内容定制 Holograms场景外包开发

    HoloLens仿真器与文档现已向开发者们开放 如何为Microsoft HoloLens全息眼镜开发应用? 每款运行Windows 10的设备都使用了相同统一的Windows内核.所以你学习了所有有 ...

  9. IOCP和WSA异步协同客户端版

    有些小伙伴看了之前发的WIN平台下IOCP和WSA异步协同处理SOCKET后有些疑惑,所以就画了个简易流程图+架构图发上来给小伙伴参考 简单说,WSA异步控制CONNECT,IOCP控制WSASend ...

  10. 【DNS】简单聊聊DNS如何工作

    随便聊聊 我们知道,网络上传输的数据包是一层一层的包起来的,典型的是mac地址层,ip层,tcp/udp层,应用层数据 这么几个层,那用户在浏览器中打开www.baidu.com数据包如何传到baid ...