Python学习二(生成器和八皇后算法)

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

书中例举了经典的八皇后问题,作为一个程序员怎么能够放过做题的机会呢,于是乎先自己来一遍,于是有了下面这个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个八皇后的解法,虽然我之前的代码改改应该也能实现,但是不会有这么精简

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

时间: 2024-12-28 16:11:23

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

[Python 学习] 二、在Linux平台上使用Python

这一节,主要介绍在Linux平台上如何使用Python 1. Python安装. 现在大部分的发行版本都是自带Python的,所以可以不用安装.如果要安装的话,可以使用对应的系统安装指令. Fedora系统:先以root登入,运行 yum install python Ubuntu系统:在root组的用户, 运行 sudo apt-get install python 2. 使用的Python的脚本 Linux是一个以文件为单位的系统,那么我们使用的Python是哪一个文件呢? 这个可以通过指令

OpenCV for Python 学习 (二 事件与回调函数)

今天主要看了OpenCV中的事件以及回调函数,这么说可能不准确,主要是下面这两个函数(OpenCV中还有很多这些函数,可以在 http://docs.opencv.org/trunk/modules/highgui/doc/user_interface.html 找到,就不一一列举了),然后自己做了一个简单的绘图程序 函数如下: cv2.setMouseCallback(windowName, onMouse[, param]) cv2.createTrackbar(trackbarName,

python学习之生成器yield

python学习之生成器yield **yield的作用是使函数生成一个结果序列而不是一个值,任何使用yield的函数都称为生成器,调用生成器会创建一个对象,该对象通过连续调用next()或者__next__()方法生成结果序列** 一般情况 >>> def count(n,m): >>> print('这是一个循环外部测试') >>> while n>0: >>> print('这是一个循环内部测试') >>>

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

八皇后: 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 高斯认为有76种方案.1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果.计算机发明后,有多种计算机语言可以解决此问题. 图示: 我的解决方案: 网上有大量的方法,大部分抽象难以理解,并且有知乎大神整理出了10

python学习之---生成器

通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含1000万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了. 所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间.在Python中,这种一边循环一边计算的机制,称为生成器(Generator). 要创建一个generator,有很多种方法.

Python学习笔记(十八)

一.datetime简介 datetime是Python处理日期和时间的标准库 二.导入datetime日期时间处理标准库 # datetime是日期时间模块,其中包括一个同名的日期时间类 from datetime import datetime 三.获取当前的年月日日期时间信息 # 获取当前日期时间信息 now = datetime.now() 四.指定日期时间 dt = datetime(2015,3,4,12,12,23) 五.将日期时间转换为Unix时间缀 # 将日期时间对象转换为Un

python学习之路(八)

今天主要来讲一下函数的应用部分~主要是生成器和迭代器~ 先说生成器: 现在有个列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],我现在想让列表中每个数值都加一. 没学迭代器之前 >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> b = [] >>> for i in a:b.append(i+1) ... >>> b [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >

Python学习二---字符串

一.字符串 1.1.字符串和转义字符 转义字符需要使用\来表示 1.2.字符串连接 print 字符串1 字符串2,打印出来的字符串直接连接在一起没有空格 print 字符串1,字符串2,打印出来的字符串直接连接在一起有空格 也可以使用变量赋值的方式来输出 字符串,使用+号将变量连接在一起,结果同上 1.3.str()与repr() str()将值转换为字符串 repr()返回值字符串表示形式,只是返回值, 并不转换 二.input与raw_input() input():输入的值默认是赋值运算

python 学习二十五天(python内置模块之序列化模块)

今日主要内容 1.python内置模块-序列化模块 python中的序列化模块 json 所有的编程语言都通用的序列化格式....它支持的数据类型非常有限 数字 字符串 列表 字典 pickle 只能在python语言的程序之间传递数据用的..pickle支持python中所有的数据类型 shelve python3.* 之后才有的 2.摘要模块---hashlib 3.一道经典面试题 第一.python内置模块---序列化 ***所有的导入模块都需要把import放在文件首位 什么叫序列化 能