打印输入单词字符数量统计直方图-Python版
1. 编程要求
多年前写过一篇用 C 语言实现打印单词字符数量统计的直方图的文章, 现在看上去有些混乱, 对一些任务划分不清晰, 全部混在一起. 于是重写了这个编程题, 希望可以给初学者一些参考, 并且我分别用 C, C++, Java, Python 四种语言完成了这道编程题, 有兴趣的可以看我另外三篇文章用 C / C++ / Java 实现的. 当然, 没有标准答案, 只能是参考. 原题是<<C程序设计语言第2版>>练习1-13的编程题. 原文如下:
练习1-13 编写一个程序, 打印输入中单词长度的直方图. 水平方向的直方图比较容易绘制, 垂直方向的直方图则要困难些.
我这里实现的是 垂直 方向的, 对于初学者来说学习语言只要时间和精力允许, 则尽可能的挑战难一点的要求去完成. 如果你还能用 3 种及以上的方式完成编程要求 (指的是同一种语言) , 那更好
我发现如果一篇文章一上来就扔一堆代码, 文字讲解太少的话, 没什么人愿意有耐心的看, 尤其是关键部分的算法讲解太少的话. 所以我这里还是对这个小小编程题的核心算法部分描述一下. 其它三篇 C / C++ / Java 的核心部分都是使用的相同的算法. 所以我这里核心的那一点算法描述都是一样的, 只是用不同语言去实现而已. OK, 核心部分并且也是实现垂直直方图的难点的部分的算法如下:
2. 算法设计
关键算法
直方图是竖着显示单词的数量,而不是横着显示,可程序只能一行一行打印,这里是打印垂直直方图的一个难点.那我们怎么确定什么时候该打印图案,什么时候不打印图案呢?
在Python中我们首先设计一个Word类, 用这个类来搞定所有问题. 设计两个类方法, 一个统计单词, 一个打图直方图. 并定义一个 类属性 words 列表 (在Python中列表list类似C语言的数组), 用下标代标表示单词长度, 列表值表示对应下标长度值的单词数量.
可以发现直方图Y轴部分刚好和行号相对应,在我们统计的单词数组中的单词数量刚好可以和行号对应,比如长度为 2 的单词我们统计有 5 个,那我们打印Y轴最少要打印 5 行,同时从第 5 行并与之对应的单词长度的列上就要开始打印图案,打印一个并将单词数组中相应长度的单词数量减 1,我们通过一个双层循环,外层控行最大行数,内层用迭代变量例如 j 来访问单词列表 words[] .比如在第 1 列就是 words[j] 上与当前行号例如第 6 行比对,如果 words[j] == 6 为真则说明j长度的单词还有 6 个没打印,则当前第 6 行要打印图案.这样依次打印第 6 行所有长度(列) j = 6 ~ 1,然后下一轮进入第 5 行打印有 5 个单词数量的相应单词长度的数量,一直到长度为1.
所以, 关键算法部分转换成代码就这一点点:
"""打印Y轴部分及直方图案"""
def Print_Y_Axix(self):
print(f"\n Y the count of word")
print(f"{'|':>4}") # 右对齐 宽度为4
for i in range(MAXLEN-1, 0, -1): # 外层循环控制直方图高度即行号
line_num = str(i) # 转换i值为行号
print(f"{line_num:>3}|", end='') # 右对齐 宽度为3 end=''表示不换行
for j in range(1, MAXLEN): # 内层循的索引j值访问words数组
if i == self.words[j]: # 如果words数组值等于当前行号值
print(f"{'*':>3}", end='') # 则说明当前长度单词有行号那样多数量打印*
self.words[j] -= 1 # 打印后要减1个,以便下一行还要打印*
else:
print(f"{' ':>3}", end='') # 否则打当空白,宽度3 右对齐
print() # 打印下一行
3. 完整代码
""" << C程序设计语言第二版 >> 练习1-13 实现打印输入中单词长度的直方图 """
""" 本程序用Python实现垂直方向的直方图 """
# 导入sys模块访问标准输入获取字符
import sys
MAXLEN = 10 # 定义最大支持单词长度
"""设计一个类来解决打印直方图的问题"""
class Word:
"""用一个列表来存放相应长度的单词数量"""
def __init__(self):
self.words = [0] * MAXLEN # 初始化列表为MAXLEN个元素,每个为0
"""统计相应长度单词数量"""
def Count_Word(self):
wordin = False # 初始单词状态置为在单词外
chcount = 0 # 初始化字母数
print(f"Enter some words: ")
while True:
ch = sys.stdin.read(1) # 读取单个字符
if ch == '#': # 遇取#结束
break
if ch.islower() or ch.isupper(): # 如果是字母
if wordin == False: # 如果在单词外
wordin = True # 则置为进入单词状态
chcount += 1 # 当前单词字母计数加1
else: # 否则非字母
if wordin == True: # 如果在单词中
wordin = False # 则置为出单词状态
if chcount > MAXLEN - 1: # 如果当前单词字母数超长
chcount = MAXLEN - 1 # 则置为最大长度MAXLEN-1
self.words[chcount] += 1 # 当前长度为chcount的单词数加1
chcount = 0 # 重置单词字母计数
self.words[chcount] += 1 # 统计最后一个单词
"""打印单词长度直方图"""
def Print_Histo(self):
self.Print_Y_Axix() # 第一部分, 打印Y轴及直方图案
self.Print_X_Axix() # 第二部分, 打印X轴
"""打印Y轴部分及直方图案"""
def Print_Y_Axix(self):
print(f"\n Y the count of word")
print(f"{'|':>4}") # 打印|符号 右对齐 宽度为4
for i in range(MAXLEN-1, 0, -1): # 外层循环控制直方图高度即行号
line_num = str(i) # 转换i值为行号
print(f"{line_num:>3}|", end='') # 打印行号和|符号,end=''表示不换行
for j in range(1, MAXLEN): # 内层循的索引j值访问words数组
if i == self.words[j]: # 如果words数组值等于当前行号值
print(f"{'*':>3}", end='') # 则说明当前长度单词有行号那样多数量打印*
self.words[j] -= 1 # 打印后要减1个,以便下一行还要打印*
else:
print(f"{' ':>3}", end='') # 否则打当空白 右对齐 宽度3
print() # 当印完一行,换行
"""打印X轴部分"""
def Print_X_Axix(self):
print(f"{'+':>3}", end='') # 打印+号 右对齐 宽度3 不换行
for i in range(0, MAXLEN): # 打印X轴
print(f"---", end='') # 循环打印---,每次打印一个---
print(f">X The length of word") # 打印X描述
# 打印X轴量度
print(f" 0 ", end='') # 打印原点
for i in range(1, MAXLEN): # 打印X轴的量度
x_num = str(i) # i值转换为X轴量度值字符串
print(f"{x_num:>3}", end='') # 打印X轴量度值 宽度3 右对齐
print()
# 开始
print(f"\nWelcome to Python world!")
# 创建Word对象
wd = Word()
# 统计单词
wd.Count_Word()
# 打印直方图
wd.Print_Histo()
# 结束
print(f"\nProgram done. Good luck to you!\n")
4. 运行结果
5. 结语
写文章不容易, 支持原创, 如转载请注明出处. 喜欢就点赞收藏, 您的点赞收藏是我创作的动力. 祝我的文章读者工作顺利. 谢谢.
原文地址:https://blog.csdn.net/losangelx/article/details/145259843
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!