问题描述
在屏幕上打印出杨辉三角图形。
我记得最早接触杨辉三角是在小学的数学课本上,是一个课后思考题,通过前面的规律推导出后面的数字。杨辉三角的规律有:第n行就会有n个数字;每行数字都交错排列使其看起来像三角形;第一行一个数字1;第二行两个数字1和1;从第三行开始,除了第一个和最后一个数字是1以外,其余的第x个数字都等于上一行第x-1个数字与第x个数字之和。
这个问题的本质就是需要我们设计一个程序输出n行杨辉三角数字,并且要使每行数字都交错排列,形成一个等腰三角形。
杨辉三角生成器
我们先做一个杨辉三角生成器,来帮我们生成n行杨辉三角数字。我们可以考虑把每一行杨辉三角数字都使用列表来输出,第一行[1]第二行[1, 1]第三行[1, 2, 1]...。因为函数之间传递数据时通常采用列表或字典,列表形式的杨辉三角数据方便我们向绘图模块传递数据,例如网页前端、pyside6、tinkter等。那么根据上面的想法来创建一个杨辉三角生成器吧,代码如下:
def yanghui_generator(n: int):
"""
杨辉三角生成器
:param n: 行数
:return: Generator
"""
layer_list = [] # 创建存储每一行杨辉三角数据的列表
for i in range(1, n+1): # 循环n次来输出n行杨辉数据
_list = [1] # 创建一个中间存储列表,因为每一行的第一个数字一定是1,所以直接确定第一个元素1
for x in range(1, i-1): # 通过循环来给每一行除第一个和最后一个元素赋值,行数i为1和2时不能进入循环
_list.append(layer_list[x-1] + layer_list[x]) # 第x个数字都等于上一行第x-1个数字与第x个数字之和
if i > 1: # 当行数i大于1时(第一行只有一个数字1)
_list.append(1) # 在行末增加一个数字1
layer_list = _list # 把得到的i行数据列表赋值给layer_list
yield layer_list # 被next函数调用时返回i行杨辉三角数据的列表,暂停循环,等待下一次被next函数调用时进入下一次循环
通过这个杨辉三角生成器,我们已经可以得到n层的杨辉三角数据了。接下来就只需要打印出这些数据了,为了不给大家增加额外的负担,这里就不使用Django、PySide6、tinkter等框架来显示杨辉三角了,只用最简单的print函数。
打印杨辉三角
print函数可以帮我们打印出杨辉三角,但要想打印出一个左右对称的等腰三角形,需要对数据做一些处理。我们首先要确定最大的打印宽度,让每一行数据都在这个宽度内居中显示,就可以达到等腰三角形的效果。为了更好看,我们还需要保持每个数据之间的间隔相等,相邻行的数据不会出现纵向重叠,每个数字都应保持居中。代码如下:
def yanghui_triangle(n: int):
"""
在运行终端打印出杨辉三角
:param n: 行数
:return:
"""
y_list = list(yanghui_generator(n)) # 使用list把杨辉三角生成器中的n个数据列表取出来,组成一个新列表
interval = len(str(y_list[n - 1][n // 2])) # 求出杨辉三角中最大一个数的位数
width = interval * (2 * n + 1) # 设置打印总宽度
for i in y_list: # 从列表中循环取出每一行的列表
y_str = ' ' * interval # 设置打印前边距
for n in i: # 从每一行列表中循环取出每一个数字
y_str += str(n).center(interval) # 把数字转换为字符串,用center处理字符串,使数字在宽度为interval的字符串中处于居中位置
y_str += ' ' * interval # 设置相邻字符串的间距
print(f'{y_str:^{width}}') # 打印当前行的杨辉三角数字,在总宽度中居中显示
完整代码
完整代码如下:
def yanghui_generator(n: int):
"""
杨辉三角生成器
:param n: 行数
:return: Generator
"""
layer_list = [] # 创建存储每一行杨辉三角数据的列表
for i in range(1, n+1): # 循环n次来输出n行杨辉数据
_list = [1] # 创建一个中间存储列表,因为每一行的第一个数字一定是1,所以直接确定第一个元素1
for x in range(1, i-1): # 通过循环来给每一行除第一个和最后一个元素赋值,行数i为1和2时不能进入循环
_list.append(layer_list[x-1] + layer_list[x]) # 第x个数字都等于上一行第x-1个数字与第x个数字之和
if i > 1: # 当行数i大于1时(第一行只有一个数字1)
_list.append(1) # 在行末增加一个数字1
layer_list = _list # 把得到的i行数据列表赋值给layer_list
yield layer_list # 被next函数调用时返回i行杨辉三角数据的列表,暂停循环,等待下一次被next函数调用时进入下一次循环
def yanghui_triangle(n: int):
"""
在运行终端打印出杨辉三角
:param n: 行数
:return:
"""
y_list = list(yanghui_generator(n)) # 使用list把杨辉三角生成器中的n个数据列表取出来,组成一个新列表
interval = len(str(y_list[n - 1][n // 2])) # 求出杨辉三角中最大一个数的位数
width = interval * (2 * n + 1) # 设置打印总宽度
for i in y_list: # 从列表中循环取出每一行的列表
y_str = ' ' * interval # 设置打印前边距
for n in i: # 从每一行列表中循环取出每一个数字
y_str += str(n).center(interval) # 把数字转换为字符串,用center处理字符串,使数字在宽度为interval的字符串中处于居中位置
y_str += ' ' * interval # 设置相邻字符串的间距
print(f'{y_str:^{width}}') # 打印当前行的杨辉三角数字,在总宽度中居中显示
yanghui_triangle(10)
执行结果如下:
打印出了10行杨辉三角。