(十一)数组 -- 4. 使用数组制作表格

4. 使用数组制作表格

程序的数据结构反映了在实际应用领域中数据的组织形式。

一般来说,只要应用中包含的数据能表示成以下列表的形式:
a 0 , a 1 , a 2 , a 3 , a 4 , . . . , a N − 1 a_0,a_1,a_2,a_3,a_4,...,a_{N-1} a0a1a2a3a4...aN1

就可以选择数组来表示这组数据。

  • 下角标(subscript)
    一般会把数组元素的下标称作下角标。

然而,对某些应用来说,不是在数组的连续元素中存放数值,而是用数据生成数组下标值。

这些下标值被用来选择数组中的元素,记录数据的某些统计特性。


例如,假设要写一个程序读入用户输入的文本行,并记录26个英文字母出现的次数。

当用户输入一个空行表示输入结束的时候,程序应该输出一个表,说明在输入数据中各个字母出现的次数。

运行示例如下:

这个程序值得注意的地方是:
要设计一种数据结构,可以记录26个字母出现的次数。

好的方法就是把26个变量放入一个数组,然后使用字符代码选择数组中合适的元素。
每个元素里存放一个整型数值,表示对应于数组中该下标的字母当前出现的次数。

数组letterCounts,声明如下:

int letterCounts[NLetters];

Nletters被定义为常数26。


在输入数据中每出现一个字母时,就要增加letteCounts中相应元素的值。

寻找需要自增的元素的过程,就是用字符运算把一个字母转换成在范围0~25中的整数。

这个转换过程由函数LetterIndex实现:

int LetterIndex(char ch) {
    if (isalpha(ch)) {
        return (toupper(ch) - 'A');
    } else {
        return (-1);
    }
}

其中,character相关返回值,示例如下:

// character vs ASCII value
printf("%d\n", 'a');
printf("%c\n", 'a');
printf("%d\n", toupper('a'));
printf("%c\n", toupper('a'));
97
a
65
A

为了记录每个字母出现的次数,需要:
(1) 通过调用函数LetterIndex把字母转化为下标值。
(2) 如果下标值不是-1,就要自增数组letterCounts中相应下标值的元素的值。

函数RecordLetter的实现如下:

void RecordLetter(char ch, int letterCounts[]) {
    int idx;
    idx = LetterIndex(ch);
    if (idx != -1) {
        letterCounts[idx]++;
    }
}

其中,检测函数LetterIndex返回的值是否是-1很重要。

如果不作这个检测,程序就有可能增加 lettercount[-1] 中的数值。

即使此元素事实上不存在,大部分的编译器还是会检查正好位于数组开始前的那个整型字。

因为在数组letterCounts之前的内存中可能存放程序需要的其他数据,所以改变这个位置的数据就有可能导致程序运行结果不正确,也有可能使程序无法运行。


在记录每个字母出现的次数之前,应该先确保数组中元素的初始值在程序运行之前为0。

函数ClearIntegerArray,实现如下:

void ClearIntegerArray(int array[], int n){
    int i;
    for (i = 0; i < n; i++)
    {
        array[i] = 0;
    }
}

最后,函数DisplayLetterCounts生成字母出现频率表,实现如下:

void DisplayletterCounts(int letterCounts[]) {
    char ch;
    int num;
    for (ch = 'A'; ch <= 'Z' ; ch++) {
        num = letterCounts[LetterIndex(ch)];
        if (num != 0) {
            printf("%c  %d\n", ch, num);
        }
    }
}

其中,for循环语句的循环范围是从’A’~’Z’,而不是从0~25是很重要的。

因为用对应于问题的下标值,会有利于理解for循环语句。



最后,完整的实现如下:

/*  
* File: countlet.c
* ----------------
* This program counts the occurrences of individual letters 
* that appear in the text inputted by user.
*/

#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include "strlib.h"

#define NLetters 26


/* Function Prototype */

static void ClearIntegerArray(int array[], int n);
static void CountLetters(int letterCounts[]);
static void CountLettersInString(string str, int letterCounts[]);
static void RecordLetter(char ch, int letterCounts[]);
static int LetterIndex(char ch);
static void DisplayletterCounts(int letterCounts[]);


/* Main Program */

main() {
    int letterCounts[NLetters];
    printf("This program counts letter frequencies.\n");
    printf("Enter a blank line to signal end of input.\n");
    ClearIntegerArray(letterCounts, NLetters);
    CountLetters(letterCounts);
    DisplayletterCounts(letterCounts);
}


/* Function */

static void ClearIntegerArray(int array[], int n){
    int i;
    for (i = 0; i < n; i++)
    {
        array[i] = 0;
    }
}

static void CountLetters(int letterCounts[]) {
    char line[1000];
    int i, length;
    string str;

    while (true)
    {
        str = "";
        fgets(line, 1000, stdin);
        if (IthChar(line, 0) == '\n') {
            break;
        } else {
            length = StringLength(line);
            for (i = 0; i < length; i++) {
                str = Concat(str, CharToString(IthChar(line, i)));
            }
        }
        CountLettersInString(str, letterCounts);
    }
}

static void CountLettersInString(string str, int letterCounts[]) {
    int i, length;
    length = StringLength(str);
    for (i = 0; i < length;i++) {
        RecordLetter(IthChar(str, i), letterCounts);
    }
}

static void RecordLetter(char ch, int letterCounts[]) {
    int idx;
    idx = LetterIndex(ch);
    if (idx != -1) {
        letterCounts[idx]++;
    }
}

static int LetterIndex(char ch) {
    if (isalpha(ch)) {
        return (toupper(ch) - 'A');
    } else {
        return (-1);
    }
}

static void DisplayletterCounts(int letterCounts[]) {
    char ch;
    int num;
    for (ch = 'A'; ch <= 'Z' ; ch++) {
        num = letterCounts[LetterIndex(ch)];
        if (num != 0) {
            printf("%c  %d\n", ch, num);
        }
    }
}




参考
《C语言的科学和艺术》 —— 第11章 数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值