打印输入单词字符数量统计直方图-C语言第二版

1. 编程要求

多年前写过一篇用 C 语言实现打印单词字符数量统计的直方图的文章, 现在看上去有些混乱, 对一些任务划分不清晰, 全部混在一起. 于是重写了这个编程题, 希望可以给初学者一些参考, 并且我分别用 C, C++, Java, Python 四种语言完成了这道编程题, 有兴趣的可以看我另外三篇文章用 C++ / Java / Python 实现的. 当然, 没有标准答案, 只能是参考. 原题是<<C程序设计语言第2版>>练习1-13的编程题. 原文如下:

练习1-13  编写一个程序, 打印输入中单词长度的直方图. 水平方向的直方图比较容易绘制, 垂直方向的直方图则要困难些.

我这里实现的是 垂直 方向的, 对于初学者来说学习语言只要时间和精力允许, 则尽可能的挑战难一点的要求去完成. 如果你还能用 3 种及以上的方式(指的是同一种语言)完成编程要求, 那更好

我发现如果一篇文章一上来就扔一堆代码, 文字讲解太少的话, 没什么人愿意有耐心的看, 尤其是关键部分的算法讲解太少的话. 所以我这里还是对这个小小编程题的核心算法部分描述一下. 其它三篇 C++ / Java / Python 的核心部分都是使用的相同的算法. 所以我这里核心的那一点算法描述都是一样的, 只是用不同语言去实现而已. OK, 核心部分并且也是实现垂直直方图的难点的部分的算法如下:

2. 算法设计

直方图是竖着显示单词的数量,而不是横着显示,可程序只能一行一行打印,这里是打印垂直直方图的一个难点.那我们怎么确定什么时候该打印图案,什么时候不打印图案呢?

关键算法

我们定义一个 words 数组下标代标表示单词长度, 数组值表示对应下标长度值的单词数量.可以发现直方图Y轴部分刚好和行号相对应,在我们统计的单词数组中的单词数量刚好可以和行号对应,比如长度为 2 的单词我们统计有 5 个,那我们打印Y轴最少要打印 5 行,同时从第 5 行并与之对应的单词长度的列上就要开始打印图案.

如何实现

我们通过一个双层循环,外层控行最大行数,内层用迭代变量例如 j 来访问单词数组 words[] .比如在第 1 列就是 words[j] 上与当前行号例如第 6 行比对,如果 words[j] >= 6 为真则说明j长度的单词还有 6 个没打印,则从当前第 6 行就要开始打印图案. 这样依次打印第 6 行所有长度(列) j = 6 ~ 1,然后下一轮进入第 5 行打印有 5 个单词数量(只要单词数量pw[j] >= i行号, 打印过第6行的那一列在5, 4, 3, 2, 1行继续打印)的相应单词长度的数量,一直到长度为1. (注: 下面用指针 pw 访问words数组)

所以, 关键算法部分转换成代码就这一点点:


    /*打印Y轴和直方图案*/
    for (i = len - 1; i > 0; i--) {      /*i控制直方图高度即行数*/
        printf("%3d|", i);               /*打印Y轴量度值和Y轴*/
        for (j = 1; j < len; j++) {     /*j作下标来访问words数组中单词数量*/

            if (pw[j] >= i) {               /*如果当前长度单词字符数不少于行号这么多数量*/
                printf("%3c", '*');      /*则打印直方图图案*/
            } else {                          /*否则当前长度单词数打印空白*/
                printf("%3c", ' ');
            }

 

3. 完整代码

/* << C程序设计语言第二版 >> 练习1-13 实现打印输入中单词长度的直方图*/
/* 本程序实现的是垂直方向的直方图 */
#include <stdio.h>
#include <ctype.h>
#define MAXLEN 10/*初始化单词数量数组*/
void InitWords(int (*pw)[MAXLEN]);
/*完成各单词长度的统计*/
void CountWord(int *pw, int len);
/*根据words数组信息打印直方图*/
void PrintHisto(int *pw, int len);int main()
{int words[MAXLEN];          /*存放各长度的单词数量,下标即单词长度*/InitWords(&words);          /*初始始化单词数量数组*/CountWord(words, MAXLEN);   /*统计输入的各长度单词数量*/PrintHisto(words, MAXLEN);  /*根据words数组信息打印直方图*/printf("\nDone.\n\n");return 0;
}/*初始化单词数量数组*/
/*pw是一个数组指针,这里传给pw的是数组words的地址*/
/*是传址,不是常见的传值,当然无论传值还是传址都可以*/
/*这个数组指针有点像函数指针,只不过右边是方括号*/
void InitWords(int (*pw)[MAXLEN])
{int i;for (i = 0; i < MAXLEN; i++) {(*pw)[i] = 0; /*pw是指向数组的指针,*pw代表数组*/}
}/*完成各单词长度的统计*/
void CountWord(int *pw, int len)
{char ch;int wordin = 0;  /*是否在单词中的状态*/int chcount = 0; /*统计单词的长度*/printf("\nEnter some words(# to quit): \n");while ((ch = getchar()) != '#') {if (isalpha(ch)) {                         /*如果是字母*/if (0 == wordin) { wordin = 1; }       /*不在单词内则置为进入单词*/if (chcount < len - 1) { chcount++; }  /*如果当前单词不超长则计数*/} else {                                   /*如果是非字母字符*/if (1 == wordin) {                     /*如果在单词中则*/wordin = 0;                        /*置为出单词状态*/pw[chcount]++;                     /*当前长度单词数加1*/chcount = 0;                       /*重置单词字符个数*/}}}pw[chcount]++; /*统计最后一个单词*/
}/*根据words数组信息打印直方图*/
/*我们将打印直方图分成两大部分*/
/*第一部分是打印Y轴和直方图图案,第二部分是打印X轴及下方*/
void PrintHisto(int *pw, int len)
{int i, j;/*第一部分,打印Y轴及直方图图案*/printf("\n   Y The count of word\n");printf("%4c\n", '|');/*打印Y轴和直方图案*/for (i = len - 1; i > 0; i--) {  /*i控制直方图高度即行数*/printf("%3d|", i);           /*打印Y轴量度值和Y轴*/for (j = 1; j < len; j++) {  /*j作下标来访问words数组中单词数量*/if (pw[j] >= i) {        /*如果当前长度单词字符数不少于行号这么多数量*/printf("%3c", '*');  /*则打印直方图图案*/} else {                 /*否则当前长度单词数打印空白*/printf("%3c", ' ');}}printf("\n");}/*第二部分,打印X轴及量度值*/printf("  +");for (i = 0; i < len; i++) {         /*X轴*/printf("---");}printf(">X The length of word\n");printf("  0 ");                     /*打印原点*/for (i = 1; i < len; i++) {         /*X轴数字*/printf("%3d", i);}printf("\n");
}

4. 运行结果

5. 结语

写文章不容易, 支持原创, 如转载请注明出处. 喜欢就点赞收藏, 您的点赞收藏是我创作的动力. 祝我的文章读者工作顺利. 谢谢.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/68044.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【QT】-explicit关键字

explicit explicit 是一个 C 关键字&#xff0c;用于修饰构造函数。它的作用是防止构造函数进行隐式转换。 为什么需要 explicit&#xff1f; 在没有 explicit 的情况下&#xff0c;构造函数可以用于隐式类型转换。这意味着&#xff0c;如果你有一个接受某种类型的参数的构造…

【C++模板】:如何判断自定义类型是否实现某个函数

一、引子 偶尔我们会面对这样的尴尬的场景&#xff0c;我们需要显示的去判断在某个自定义类型中&#xff0c;是否已经提供了我们期待的API接口&#xff0c;以避免产生“莫须有”的错误。阁下该如何破解此问题&#xff01; 这里&#xff0c;直接给出一种通用的方法&#xff0c;…

认识Django项目模版文件——Django学习日志(二)

1.默认文件介绍 └── djangoproject1/├── djangoproject1/│ ├── urls.py [URL和函数的对应关系]【常用文件】│ ├── settings.py [项目配置文件]【常用文件】│ ├── _init_.py│ ├── wsgi.py [接受网络请求] 【不要动】│ └──…

【JS逆向】前端加密对抗基础

目录 逆向基础断掉调试基本常见的加解密方式 encrypt-labs靶场搭建过程靶场基本教程AES加密key前端体现(固定key)AES服务端获取keyRSA非对称加密DES加密存在规律key明文加签sign加签key在服务端signAESRAS组合 逆向基础 断掉调试 通过浏览器站点控制台(F12)&#xff0c;进行断…

C# 多线程同步(Mutex | Semaphore)

Mutex: 用于保护临界区&#xff0c;确保同一时间只有一个线程能够访问共享资源&#xff1b; Semaphore: 允许同时有多个线程访问共享资源&#xff0c;但会限制并发访问的数量。 Mutex运行输出 Semaphore运行输出 namespace SyncThreadDemo {internal class Program{static stri…

复位信号的同步与释放(同步复位、异步复位、异步复位同步释放)

文章目录 背景前言一、复位信号的同步与释放1.1 同步复位1.1.1 综述1.1.2 优缺点 1.2 recovery time和removal time1.3 异步复位1.3.1 综述1.3.2 优缺点 1.4 同步复位 与 异步复位1.5 异步复位、同步释放1.5.1 总述1.5.2 机理1.5.3 复位网络 二、思考与补充2.1 复…

git远程仓库如何修改

1.需要做的事情&#xff1a;把git的远程仓库修改掉&#xff0c;在git创建一个自己的仓库 如果你是私有化的话&#xff0c;可以生成一个自己token令牌也可以。到时候push的时候会让你登录你就可以输入你的token令牌和用户名。 2.查看当前仓库的远程地址是不是自己的 &#xff…

mysql 学习3 SQL语句--整体概述。SQL通用语法;DDL创建数据库,查看数据库,删除数据库,使用数据库;

SQL通用语法 SQL语句分类 DDL data definition language : 用来创建数据库&#xff0c;创建表&#xff0c;创建表中的字段&#xff0c;创建索引。因此成为 数据定义语言 DML data manipulation language 有了数据库和表以及字段后&#xff0c;那么我们就需要给这个表中 添加数…

【xcode 16.2】升级xcode后mac端flutter版的sentry报错

sentry_flutter 7.11.0 报错 3 errors in SentryCrashMonitor_CPPException with the errors No type named terminate_handler in namespace std (line 60) and No member named set_terminate in namespace std 替换sentry_flutter版本为&#xff1a; 8.3.0 从而保证oc的…

【回忆迷宫——处理方法+DFS】

题目 代码 #include <bits/stdc.h> using namespace std; const int N 250; int g[N][N]; bool vis[N][N]; int dx[4] {0, 0, -1, 1}; int dy[4] {-1, 1, 0, 0}; int nx 999, ny 999, mx, my; int x 101, y 101; //0墙 (1空地 2远方) bool jud(int x, int y) {if…

wireshark工具简介

目录 1 wireshark介绍 2 wireshark抓包流程 2.1 选择网卡 2.2 停止抓包 2.3 保存数据 3 wireshark过滤器设置 3.1 显示过滤器的设置 3.2 抓包过滤器 4 wireshark的封包列表与封包详情 4.1 封包列表 4.2 封包详情 参考文献 1 wireshark介绍 wireshark是非常流行的网络…

⽤vector数组实现树的存储(孩⼦表示法)c++

在我们遇到的算法题中&#xff0c; ⼀般给出的树结构都是有编号的&#xff0c;这样会简化我们之后存储树的操作 &#xff0c;⼀般提供两个信息&#xff1b; 结点的个数 n;n-1条x结点与y结点相连的边 题⽬描述: ⼀共9个结点셈 1号结点为根节点&#xff0c;接下来8⾏&#xff…

C语言-内存管理

1、malloc()函数 用于动态分配一块指定大小的内存&#xff0c;并返回指向这块内存的指针。如果分配失败&#xff0c; 返回 NULL。 int* ptr (int*)malloc(sizeof(int) * 10); // 分配一个包含 10 个整数的内存 if (ptr NULL) {printf("Memory allocation failed!\n&q…

蓝桥杯lesson3---string的使用

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” string的概念 string字符串是一种更加高级的封装&#xff0c;string字符串中包含了大量的方法&#xff0c;这些方法使得字符串的操作变得更加简单&#xff0c;string的使用&…

動態住宅IP提升網站訪問成功率

動態住宅IP通常與普通家庭用戶的網路連接相關聯。這種IP地址的特點在於&#xff0c;它是動態變化的&#xff0c;用戶在每次連接時可能會獲得不同的IP地址。這與靜態IP形成了鮮明對比&#xff0c;後者在連接期間保持不變。傳統上&#xff0c;IP地址分為住宅IP和數據中心IP兩類。…

进制之间转换

「 一、十进制 二进制 」 1.十进制转二进制&#xff1a;一直除以2直到商为0&#xff0c;再反向取余数。 例&#xff1a;13&#xff08;十进制&#xff09;转1101&#xff08;二进制&#xff09; 2.二进制转十进制:最后一位数开始是2^0&#xff0c;然后一直按照指数递增的方式…

3b1b线性代数基础

零、写在前面 3b1b之前没认真看&#xff0c;闲了整理整理。 一、向量 学习物理的时候&#xff0c;向量是空间中的箭头。由其方向和长度决定。 学习数据结构的时候&#xff0c;向量是有序的数字列表。向量的每一维度有着不同含义。 线性代数中&#xff0c;我们通常认为**向量…

Consul持久化配置报错1067---consul_start

报错都是文件写的有问题或者格式问题&#xff0c;直接复制我的这个改改地址就行 先创建文本文件consul_start.txt--->再复制代码保存---->再把.txt改成.bat 持久化存储的地址在&#xff1a;mydata 注&#xff1a;D:\consul\consul_1.20.2_windows_386改成自己consul的…

linux中关闭服务的开机自启动

引言 systemctl 是 Linux 系统中用于管理 systemd 服务的命令行工具。它可以用来启动、停止、重启服务&#xff0c;管理服务的开机自启动&#xff0c;以及查看服务的状态等。 什么是 systemd&#xff1f; systemd 是现代 Linux 发行版中默认的 初始化系统&#xff08;init sys…

【Unity3D】Unity混淆工具Obfuscator使用

目录 一、导入工具 二、各种混淆形式介绍 2.1 程序集混淆 2.2 命名空间混淆 2.3 类混淆 2.4 函数混淆 2.5 参数混淆 2.6 字段混淆 2.7 属性混淆 2.8 事件混淆 三、安全混淆 四、兼容性处理 4.1 动画方法兼容 4.2 GUI方法兼容 4.3 协程方法兼容 五、选项 5.1 调…