《C程序设计语言》第二版 Exercise1-13

Exercise 1-13. Write a program to print a histogram of the lengths of words in its input. It is easy to draw the histogram with the bars horizontal; a vertical orientation is more challenging. 

比起之前的几道题,这一题开始作者给我们上难度了。作者让我们输出读取到的(伪)单词长度的直方图。笔者认为作者的意思是:

  1. 先弄清楚输入内容中,有多少种不同的输入(伪)单词长度,比如出现了长度为 5 的(伪)单词、长度为8的(伪)单词等等;
  2. 统计在输入中每种(伪)单词长度分别有多少个(伪)单词,比如长度为 5 的(伪)单词出现了几次,长度为 8 的(伪)单词又出现了几次。笔者认为在计数的时候,对出现了多次的同一单词,应该进行重复计数;
  3. 对上面的统计结果输出直方图。(有水平和垂直两种,但是垂直的稍有难度)

不管是输出水平直方图还是垂直直方图,首先我们都必须解决统计上的问题。因此我们需要一个数组,来存放输入中不同的(伪)单词长度对应的(伪)单词次数。

在进入 main() 函数之前,因为我们只能设置定长数组,所以我们不得不给能纳入我们计算的(伪)单词长度设置一个上限。在这里笔者设置的上限是 20 。即我们只统计长度在 20 和 20 以内的(伪)单词个数。所以我们先设置一个宏确定上限:

#define WORD_MAX_LENGTH 20

由于我们要计算每个(伪)单词的长度,也就是重复多次“ 1, 2,··· ”这样的过程。我们必须得告诉计算机,什么时候是一个新的(伪)单词,要重新从 1 开始计数;以及什么时候计算完了一个(伪)单词的长度,要给相应的(伪)单词长度对应的(伪)单词个数的统计结果 +1 。笔者这里定义了两个宏用来表示读单词的状态:

#define OUT 0
#define IN 1

接着我们进入 main() 函数(头文件啥的应该都不会忘记吧,不会真有人忘记了吧)。

首先我们先得选取一种形式来存放我们的统计结果。从抽象上来说,我们统计的结果应该是形如 (WordLength, WordCount) 这样的二元有序数对。而一维数组从抽象上恰好也可以视为 (Index, Value) 这样的二元有序数对,所以一维数组对我们来说是一个很好的选择。

int wordLength[WORD_MAX_LENGTH + 1];

因为笔者想让 wordLength[i] 来记录长为 i 的(伪)单词个数,如果我们设置数组长度为 WORD_MAX_LENGTH 的话,数组的最后一个下标是 WORD_MA_LENGTH - 1 ,所以我们设置的数组长度是 WORD_MAX_LENGTH + 1 。(记得所有元素初始化为0)

因为我们记录(伪)单词长度的方法是:

每当进入一个新的(伪)单词,就开始计算字符的个数,直到遇到空白符为止。

所以我们需要一个变量用来当作是否进入新的(伪)单词、以及是否发现空白的标记。并且用一个变量来记录(伪)单词的长度。由于我们一开始不在任何(伪)单词之内,所以我们对他们进行如下的初始化:

int state, len;
state = OUT;
len = 0;

如果我们还想计算有多少(伪)单词的长度超过了我们给定的范围——20。我们还需要一个新的变量来存放超长的(伪)单词个数。

int overLen = 0;

接着我们就可以开始读取字符并进行计数了。由于根据当前字符是空白符还是非空白符,以及 state 状态是 IN 还是 OUT ,我们分为以下几种情况:

  • 读到空白符
    1. state == IN: 表示前一个读到的字符是非空白,因此现在是从非空白刚进入到空白的阶段,这个时候意味着我们读完了一个(伪)单词,如果此时 len 小于我们设置的上限20,我们应该将数组中对应该长度的值加 1 ,表示新纪录了一个具有该长度的(伪)单词。我们还应该将 state 改成 OUT ,刷新目前状态,并且将 len 赋值为0,为下一次计算作准备。(如果 len > 20, 那么 overLen++ 。)
    2. state == OUT: 表示前一个读到的字符还是空白,此时我们不需要做什么。
  • 读到非空白符
    1. state == IN:表示前一个读到的字符是非空白,我们目前还在某个(伪)单词的内部,我们只需要给 len 加 1 。刷新我们在这个(伪)单词内遇到的字符个数。
    2. state == OUT: 表示前一个读到的字符是空白,说明此时我们遇到了一个新单词的开头,我们需要将 len 加一,并且刷新 state 为 IN 状态。

这部分代码如下:

    while ((c = getchar()) != EOF) {
        if (c == ' ' || c == '\t' || c == '\n') {
            wordLength[0]++;
            if(state == IN) {
                if (len > WORD_MAX_LENGTH)
                    overLen++;
                else
                    ++wordLength[len];
                len = 0;
            }
            state = OUT;
        } else {
            if (state == OUT) {
                len++;
                state = IN;
            } else
                len++;
        }
    }

然后我们开始输出直方图(水平)。

很简单,我们用 for 循环遍历之前的数组,每个下标元素对应一行输出:

  1. 如果该下标元素为0,说明在输入中没有遇到具有该长度的(伪)单词;
  2. 如果该下标元素大于0, 说明在输入中该长度的(伪)单词出过,出现的次数恰好等于该下标元素值。我们这时候只需要用一个 while 循环打印 ‘-’ 即可,打印次数恰好等于该下标元素值。

也就是这样:

    for (i = 1; i < WORD_MAX_LENGTH + 1; i++) {
        printf("%2d - %2d : ", i, wordLength[i]);
        while (wordLength[i]) {
            printf("-");
            wordLength[i]--;
        }
        printf("\n");
    }

到此我们的程序也就算完成了。(注意记得 return 0 )

完整的代码如下:

#include <stdio.h>

#define OUT 0
#define IN 1
#define WORD_MAX_LENGTH 20

int main() {
    int i, c, state, len, overLen;
    int wordLength[WORD_MAX_LENGTH + 1];

    state = OUT;
    len = 0;
    overLen = 0;
    for (i = 0; i < WORD_MAX_LENGTH + 1; i++)
        wordLength[i] = 0;

    while ((c = getchar()) != EOF) {
        if (c == ' ' || c == '\t' || c == '\n') {
            wordLength[0]++;
            if(state == IN) {
                if (len > WORD_MAX_LENGTH)
                    overLen++;
                else
                    ++wordLength[len];
                len = 0;
            }
            state = OUT;
        } else {
            if (state == OUT) {
                len++;
                state = IN;
            } else
                len++;
        }
    }

    for (i = 1; i < WORD_MAX_LENGTH + 1; i++) {
        printf("%2d - %2d : ", i, wordLength[i]);
        while (wordLength[i]) {
            printf("-");
            wordLength[i]--;
        }
        printf("\n");
    }
    
    return 0;
}

输出结果如下:

> Exercise1_13_1 < Exercise1_13_1.c 
 1 - 41 : -----------------------------------------
 2 - 29 : -----------------------------
 3 - 13 : -------------
 4 - 12 : ------------
 5 -  6 : ------
 6 -  6 : ------
 7 -  4 : ----
 8 -  3 : ---
 9 -  1 : -
10 -  2 : --
11 -  1 : -
12 -  1 : -
13 -  2 : --
14 -  0 : 
15 -  5 : -----
16 -  3 : ---
17 -  0 : 
18 -  1 : -
19 -  0 : 
20 -  0 : 

至于如何输出垂直的直方图,我们下回再说。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
水资源是人类社会的宝贵财富,在生活、工农业生产中是不可缺少的。随着世界人口的增长及工农业生产的发展,需水量也在日益增长,水已经变得比以往任何时候都要珍贵。但是,由于人类的生产和生活,导致水体的污染,水质恶化,使有限的水资源更加紧张。长期以来,油类物质(石油类物质和动植物油)一直是水和土壤中的重要污染源。它不仅对人的身体健康带来极大危害,而且使水质恶化,严重破坏水体生态平衡。因此各国都加强了油类物质对水体和土壤的污染的治理。对于水中油含量的检测,我国处于落后阶段,与国际先进水平存在差距,所以难以满足当今技术水平的要求。为了取得具有代表性的正确数据,使分析数据具有与现代测试技术水平相应的准确性和先进性,不断提高分析成果的可比性和应用效果,检测的方法和仪器是非常重要的。只有保证了这两方面才能保证快速和准确地测量出水中油类污染物含量,以达到保护和治理水污染的目的。开展水中油污染检测方法、技术和检测设备的研究,是提高水污染检测的一条重要措施。通过本课题的研究,探索出一套适合我国国情的水质污染现场检测技术和检测设备,具有广泛的应用前景和科学研究价值。 本课题针对我国水体的油污染,探索一套检测油污染的可行方案和方法,利用非分散红外光度法技术,开发研制具有自主知识产权的适合国情的适于野外便携式的测油仪。利用此仪器,可以检测出被测水样中亚甲基、甲基物质和动植物油脂的污染物含量,为我国众多的环境检测站点监测水体的油污染状况提供依据。
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值