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

书中例举了经典的八皇后问题,作为一个程序员怎么能够放过做题的机会呢,于是乎先自己来一遍,于是有了下面这个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. 时间戳 JavaScript parse() 方法 处理技巧

    返回1970/01/01至2012/3/21之间的毫秒数: var d = Date.parse("March 21, 2012"); d 输出结果: 1332259200000 ...

  2. 控制器(Controller) – ASP.NET MVC 4 系列

           创建一个 ASP.NET MVC 4 Web Application 项目,将程序命名为 MvcMusicStore,如下图: 控制器        MVC 模式中,控制器主要负责响应用 ...

  3. C# 创建开机启动核心代码

    #region 访问 AppSettings private void SaveAppSetting(string key, string value) { var config = Configur ...

  4. 如何使用vmware-vdiskmanager增加磁盘空间

    VMware Virtual Disk Manager Usage: vmware-vdiskmanager.exe OPTIONS <disk-name> | <mount-poi ...

  5. ETL利器Kettle实战应用解析系列二 【应用场景和实战DEMO下载】

    本文主要阅读目录如下: 1.应用场景 2.DEMO实战 3.DEMO下载 1.应用场景 这里简单概括一下几种具体的应用场景,按网络环境划分主要包括: 表视图模式:这种情况我们经常遇到,就是在同一网络环 ...

  6. 自定义 Activity 的 标题栏 TitleBar

    自定义 Activity 的 标题栏 TitleBar 1. 修改标题栏的高度,背景 编辑styles.xml,添加: <?xmlversion="1.0" encoding ...

  7. 测试dockerfile

    测试dockerfile是否ok(比如我的Dockerfile在deploy目录下) docker build -t my_image -f deploy/Dockerfile . docker im ...

  8. windows2003 IIS6.0右键属性没有asp.net选项卡的解决办法

    windows2003 IIS6.0右键属性没有asp.net选项卡的解决办法 1,如果是只安装了.net framework 1.1 在iis中是不显示那个选项卡的.默认就会支持asp.net1.1 ...

  9. STM32F4读写内部FLASH【使用库函数】

    STM32F4Discovery开发帮使用的STM32F407VGT6芯片,内部FLASH有1M之多.平时写的代码,烧写完之后还有大量的剩余.有效利用这剩余的FLASH能存储不少数据.因此研究了一下S ...

  10. Python六大开源框架对比:Web2py略胜一筹

    Python是一门动态.面向对象语言.其最初就是作为一门面向对象语言设计的,并且在后期又加入了一些更高级的特性.除了语言本身的设计目的之外,Python标准库也是值得大家称赞的,Python甚至还自带 ...