《C语言程序设计(第3版)》题目集

错题记录

  • 函数题
      • 习题5-6 使用函数输出水仙花数
      • 习题5-7 使用函数求余弦函数的近似值
      • 使用函数输出指定范围内的Fibonacci数
  • 编程题
      • 练习3-5 输出闰年
      • 习题3-2 高速公路超速处罚
      • 习题3-3 出租车计价
      • 习题3-5 三角形判断
      • 习题4-3 求分数序列前N项和
      • 习题4-6 水仙花数
      • 习题4-7 最大公约数和最小公倍数(*)
          • 最大公约数
          • 最小公倍数
      • 习题4-8 高空坠球
      • 习题4-10 猴子吃桃问题(***)
      • 习题4-11 兔子繁衍问题(斐波那契数列)(**)
      • 习题6-8 统计一行文本的单词个数(**)
      • 练习7-4 找出不是两个数组共有的元素(*)
      • 练习7-8 方阵循环右移(*)
      • 习题7-2 求一批整数中出现最多的个位数字

函数题

习题5-6 使用函数输出水仙花数

水仙花数是指一个N位正整数(N≥3),它的每个位上的数字的N次幂之和等于它本身。例如:153=1​3​​+5​3​​+33​​。 本题要求编写两个函数,一个判断给定整数是否水仙花数,另一个按从小到大的顺序打印出给定区间(m,n)内所有的水仙花数。

函数接口定义

int narcissistic( int number );
void PrintN( int m, int n );

函数narcissistic判断number是否为水仙花数,是则返回1,否则返回0。
函数PrintN则打印开区间(m, n)内所有的水仙花数,每个数字占一行。题目保证100≤m≤n≤10000。

裁判测试程序样例

#include <stdio.h>

int narcissistic( int number );
void PrintN( int m, int n );

int main()
{
    int m, n;

    scanf("%d %d", &m, &n);
    if ( narcissistic(m) ) printf("%d is a narcissistic number\n", m);
    PrintN(m, n);
    if ( narcissistic(n) ) printf("%d is a narcissistic number\n", n);

    return 0;
}

/* 你的代码将被嵌在这里 */

测试点
《C语言程序设计(第3版)》题目集_第1张图片出错点:(判断是否水仙花数)

  1. 忽略幂的次数跟位数相同,即没有计算number位数

(用了math头文件)

#include <math.h>
int narcissistic( int number )
{
    int tmp;
    int sum = 0;
    int is = 0; //默认为不是水仙花数
    int digit = 0; //记每位数字
    int cnt = 0; //记位数
    tmp = number;
    
    //计算位数(因为位数>=3,所以do-while和while都可以)
    do{
        cnt++;
        tmp /= 10;
    }while( tmp!=0 );
    tmp = number;
    
    for ( int i=1; i<=cnt; i++ ){ //加cnt次
        digit = tmp%10; //取个位数
        sum += pow(digit,cnt);
        tmp /= 10;
    }
    
    if ( sum==number ) is = 1;
    
    return is;
}
void PrintN( int m, int n )
{
    for ( int i=m+1; i<n; i++ ){
        if ( narcissistic(i) ) printf("%d\n", i);
    }
}

习题5-7 使用函数求余弦函数的近似值

本题要求实现一个函数,用下列公式求cos(x)的近似值,精确到最后一项的绝对值小于e:cos(x)=x​0​​/0!−x​2​​/2!+x​4​​/4!−x​6​​/6!+⋯

思路:写一个函数计算阶乘,再写计算cos(x)的函数

出错点:测试点1——精度高,不可直接计算阶乘

解决:原本用long long,改成用double

double fact(int n)
{
    double fact = 1;
    for ( int i=2; i<=n; i++ ){
        fact *= i;
    }
    return fact;
}
double funcos( double e, double x )
{
    double factor = 1.0;
    double item = 0;
    int i = 0;
    double cos = 0;
    
    do{ //因为包含绝对值小于e的最后一项,所以用do-while
        item = pow(x,i) / fact(i);
        i += 2;
        cos += factor * item;
        factor = -factor;
    }while( item>=e );
    
    return cos;
}

使用函数输出指定范围内的Fibonacci数

本题要求实现一个计算Fibonacci数的简单函数,并利用其实现另一个函数,输出两正整数m和n(0

函数接口定义

int fib( int n );
void PrintFN( int m, int n );

其中函数fib须返回第n项Fibonacci数;函数PrintFN要在一行中输出给定范围[m, n]内的所有Fibonacci数,相邻数字间有一个空格,行末不得有多余空格。如果给定区间内没有Fibonacci数,则输出一行“No Fibonacci number”。

思路

int fib( int n );

主要方法同输出前 n 个菲波那契Fibonacci数

void PrintFN( int m, int n );
  1. 找到符合条件的第一项Fibonacci并标记含Fib
  2. 若没有Fib则直接按题意输出;若有,在n内(含n)逐项输出Fib
int fib( int n )
{
    int ret = 0;
    int a, b, c=0;
    a = b = 1;
    
    if ( n==1 || n==2 ) ret = 1;
    else{
        for( int i=3; i<=n; i++ ){
            c = a+b;
            a = b;
            b = c;
        }
        ret = c;
    }
    
    return ret;
}
void PrintFN( int m, int n )
{
    int is_fib = 0; //默认没有fib
    int f1 = 0;
    int i = 1;
    
    //判断第一项fib,以及是否有fib
    f1 = fib(i);
    while( f1<=n ){
        if ( f1>=m ){
            is_fib = 1; //标记为有Fib
            break; //直接退出循环
        }
        i++;
        f1 = fib(i);
    }
    
    if ( is_fib==0 ) printf("No Fibonacci number");
    else{
        printf("%d", f1); //先打印出第一项,后面好控制空格
        i++;
        f1 = fib(i);
        while( f1<=n ){
            printf(" %d", f1);
            i++;
            f1 = fib(i);
        }
    }
}

编程题

练习3-5 输出闰年

输出21世纪中截止某个年份以来的所有闰年年份。注意:闰年的判别条件是该年年份能被4整除但不能被100整除、或者能被400整除。

输出:逐行输出满足条件的所有闰年年份,即每个年份占一行。输入若非21世纪的年份则输出"Invalid year!"。若不存在任何闰年,则输出“None”。

出错点:本来想偷懒,从2004开始以4递增,但根据闰年的判别条件知,2100年不是闰年,闰年并不是简单地每四年一次

#include <stdio.h>

int leap(int year);

int main()
{
    int year;
    int cnt = 0;
    
    scanf("%d", &year);
    if ( year>2000 && year<=2100 ){
        for ( int i=2001; i<=year; i++ ){ //2100不是闰年
            if ( leap(i) ){
                printf("%d\n", i);
                cnt++;
            }
        }
        if ( cnt==0 ) printf("None");
    }
    else printf("Invalid year!");
    
    return 0;
}

int leap(int year)
{
    int is_leap = 0;//默认为平年
    
    if ( year%4==0 && year%100 || year%400==0 ) is_leap = 1;
    
    return is_leap;
}

可改进点:判别闰年的函数用一个变量代替,如下

int is_leap;
is_leap = year%4==0 && year%100 || year%400==0;

习题3-2 高速公路超速处罚

按照规定,在高速公路上行使的机动车,达到或超出本车道限速的10%则处200元罚款;若达到或超出50%,就要吊销驾驶证。请编写程序根据车速和限速自动判别对该机动车的处理。

如何输出百分号%? %%

int speed, limit;
double x = 0;

scanf("%d %d", &speed, &limit);
if ( speed<(limit+limit*0.1) ) printf("OK");
else if ( speed<(limit+limit*0.5) ){
    x = 1.0 * (speed-limit) / limit * 100;
    printf("Exceed %.0f%%. Ticket 200", x);
}
else{
    x = 1.0 * (speed-limit) / limit * 100;
    printf("Exceed %.0f%%. License Revoked", x);
}

习题3-3 出租车计价

输出:在一行中输出乘客应支付的车费(单位为元),结果四舍五入,保留到元。

如何四舍五入?

double a = 3.1;
int result;
result = (int)(a + 0.5);
double mile;
int minute;
int cost = 0;

scanf("%lf %d", &mile, &minute);
if ( mile<3 ) cost = 10;
else if ( mile<10 ) cost = (int)(10 + 2 * (mile-3) + 0.5);
else cost = (int)(10 + 2*(10-3) + 3 * (mile-10) + 0.5);

if ( minute>=5 ){
    cost += minute/5 * 2;
}

printf("%d", cost);

习题3-5 三角形判断

输入:在一行中顺序给出六个[−100,100]范围内的数字,即三个点的坐标x​1​​、y​1​​、x​2​​、y​2​​、x​3​​、y​3​​。

输出:若这3个点不能构成三角形,则在一行中输出“Impossible”;若可以,则在一行中输出该三角形的周长和面积,格式为“L = 周长, A = 面积”,输出到小数点后2位。

知三角形三边长,如何求其面积?

s = (a+b+c) / 2; //周长的一半
area = sqrt(s*(s-a)*(s-b)*(s-c));

CODE

#include <stdio.h>
#include <math.h>

int main()
{
    double x1, y1, x2, y2, x3, y3;
    double a, b, c, l, area, s;
    a = b = c = l = area = s = 0;
    
    scanf("%lf%lf%lf%lf%lf%lf", &x1, &y1, &x2, &y2, &x3, &y3);
    //求三边长
    a = sqrt(pow((x1-x2),2)+pow((y1-y2),2));
    b = sqrt(pow((x1-x3),2)+pow((y1-y3),2));
    c = sqrt(pow((x2-x3),2)+pow((y2-y3),2));
    
    if ( a+b>c && a+c>b && b+c>a ){ //构成三角形的条件
        l = a + b + c;
        s = l / 2;
        area = sqrt(s*(s-a)*(s-b)*(s-c));
        printf("L = %.2f, A = %.2f", l, area);
    }
    else printf("Impossible");
    
    return 0;
}

习题4-3 求分数序列前N项和

计算序列 2/1+3/2+5/3+8/5+… 的前N项之和。注意该序列从第2项起,每一项的分子是前一项分子与分母的和,分母是前一项的分子。题目保证计算结果不超过双精度范围。

测试点:较大N——错误

解决:分子、分母需改成double型

int n;
double sum = 0;
//int a=1, b=2, c=0;
double a=1, b=2, c=0;
double item = 0;

scanf("%d", &n);
for ( int i=1; i<=n; i++ ){
    item = 1.0 * b / a;
    sum += item;
    c = b; //存着分子
    b = a + c; //分子=分母+分子
    a = c; //分母=分子
}

printf("%.2f", sum);

习题4-6 水仙花数

水仙花数是指一个N位正整数(3≤N≤7),它的每个位上的数字的N次幂之和等于它本身。例如:153=1​3​​+5​3​​+3​3​​。 本题要求编写程序,计算所有N位水仙花数。

出错点:测试点3——最大N,输出4个——运行超时

解决:原本用的math.pow计算幂函数,自己写一个pow运行更快。

**即当幂次>=7时,最好用自己写的pow函数

#include<stdio.h>

int pow(int x,int n); //计算幂次,因为最大到八位数,所以用int就够了
int narcissus(int number, int n); //返回1则是水仙花数,返回0则不是

int main()
{
	int n;
	int lower, higher;
    
    scanf("%d", &n);
    lower = pow(10,n-1);
    higher = pow(10,n); //单独计算出来就不用每次判断的时候调用一次了
    
    for ( int i=lower; i<higher; i++ ){
        if ( narcissus(i,n) ) printf("%d\n", i);
    }
    
    return 0;
}

int pow(int x,int n)
{
	int p=1;
	for(int i=1; i<=n; i++) //n个x相乘,即x的n次方
		p *= x;
	return p;
}

int narcissus(int number, int n)
{
    int is = 0; //默认为不是水仙花数
    int digit = 0;
    int sum = 0;
    int tmp = number;
    
    for ( int i=1; i<=n; i++ ){
        digit = tmp%10;
        sum += pow(digit,n);
        tmp /= 10;
    }
    
    if ( sum==number ) is = 1;
    
    return is;
}

习题4-7 最大公约数和最小公倍数(*)

最大公约数
  1. 穷举法
int commonDivisor(int m, int n)
{
    int divisor = 0;
    //找出更小的值
    int min = m; 
    if ( n<min ) min = n;
    //只要从更小的值开始递减,找最大公约数即可
    for ( int i=min; i>0; i-- ){
        if ( m%i==0 && n%i==0 ){
        	divisor = i;
        	break;
        }
    }
    return divisor;
}
  1. 相减法
    ①若m==n:divisor = m
    ②若m!=n:较大值=较大值-较小值
int commonDivisor(int m, int n)
{
    while( m!=n ){
        if ( m>n ) m = m - n;
        else n = n - m;
    }
    return m;
}
  1. 辗转相除法
    ①找出较大值,假设为m
    ②m%n = c:若c==0 —— divisor = n;若c!=0 —— 令除数n作被除数m,令余数c作除数n
int commonDivisor(int m, int n)
{
    int tmp=0, c=0;
    if ( n>m ){
        tmp = n;
        n = m;
        m = tmp;
    }
    while( n!=0 ){
        c = m % n;
        m = n; //除数n赋给被除数m
        n = c; //余数c赋给n
    }
    return m;
}
最小公倍数
  1. 最小公倍数=两数之积 / 最大公约数
multiple = m * n / divisor;
  1. 穷举法
int commonMultiple(int m, int n)
{
    int multiple = 0, i = 0;
    int max = m;
    if ( n>max ) max = n; //找出更大值
    i = max; //从较大值开始循环
    while(1){
        if ( i%m==0 && i%n==0 ){
            multiple = i;
            break;
        }
        i++;
    }
    return i;
}

习题4-8 高空坠球

皮球从某给定高度自由落下,触地后反弹到原高度的一半,再落下,再反弹,……,如此反复。问皮球在第n次落地时,在空中一共经过多少距离?第n次反弹的高度是多少?

输入:在一行中给出两个非负整数,分别是皮球的初始高度和n,均在长整型范围内。

输出:在一行中顺序输出皮球第n次落地时在空中经过的距离、以及第n次反弹的高度,其间以一个空格分隔,保留一位小数。题目保证计算结果不超过双精度范围。

分析

  1. 输入非负整数,即包括0,则①初始化反弹高度和路程为0,②添加if条件区分
  2. 输入的n是落地次数,而不是反弹次数
  3. 第一次落地:路程=初始高度,第一次反弹高度=1/2 * 初始高度
  4. 第二次落地:路程+=2 * 第一次反弹高度,第二次反弹高度=1/2 * 第一次反弹高度
  5. 第n次落地(n>1):路程+=2 * 第(n-1)次反弹高度,第n次反弹高度=1/2 * 第(n-1)次反弹高度
long long m, n;
double height=0, sum=0; //初始化为0

scanf("%ld%ld", &m, &n);
if ( n!=0 ){ //若n=0,输出的就是初始化的值0
    height = m;
    
    //第一次落地比较特殊,路程等于初始高度
    sum += height;
    height /= 2;
	//大于一次
    if ( n>1 ){
        for ( int i=2; i<=n; i++ ){ //从第二次落地开始
            sum += 2*height; //路程增加前一次反弹高度的两倍
            height /= 2; //这一次反弹的高度;也作为下一次路程增加的因子
        }
    }
}

printf("%.1f %.1f", sum, height);

习题4-10 猴子吃桃问题(***)

一只猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个;第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半加一个。到第N天早上想再吃时,见只剩下一个桃子了。问:第一天共摘了多少个桃子?

分析
假设第1天有x个桃子,记为总共有S1个桃子
第1天:吃了1/2x +1; S2=x-(1/2x +1)=1/2S1 - 1
第2天:吃了1/2
[x-(1/2x +1)] +1; S3=x-{1/2[x-(1/2x +1)] +1}=1/2S2 - 1

第n-1天:Sn=1/2S(n-1) - 1,且由题意知,Sn = 1
∴S(n-1) = 2
Sn + 2,求S1是多少?

小结:知道的是第n-1天剩下的总数,求第一天的总数,就要找总数之间的规律

CODE

int n, peach=1; //初始为1个  
scanf("%d", &n);
for ( int i=1; i<n; i++ ){ //循环n-1次
    peach = 2 * peach + 2;
}
printf("%d", peach);

习题4-11 兔子繁衍问题(斐波那契数列)(**)

一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。假如兔子都不死,请问第1个月出生的一对兔子,至少需要繁衍到第几个月时兔子总数才可以达到N对?(N为不超过10000的正整数)

分析

  1. S1 = 1
  2. S2 = 1
  3. S3 = 1 + 1–>1 = 1 + 1 = 2
  4. S4 = 2 + 1–>1 = 2 + 1 = 3
  5. S5 = 3 + 1–>1 + 1–>1 = 3 + 2 = 5
  6. S6 = 5 + 1–>1 + 1–>1 + 1–>1 = 5 + 3 =8
  7. S7 = 8 + 1–>1 + 1–>1 +1–>1 + (1–>1 + 1–>1) = 8 + 5 = 13
  8. S8 = 13 + 1–>1 + 1–>1 +1–>1 + 1–>1 + 1–>1 + (1–>1 + 1–>1 + 1–>1) = 13 + 8 = 21
  9. S9 = 21 + 1–>1 + 1–>1 +1–>1 + 1–>1 + 1–>1 + 1–>1 + 1–>1 + 1–>1 + 1–>1 + (1–>1 + 1–>1 +1–>1 + 1–>1 + 1–>1) = 21 + 13 = 34
  10. 可见,1,1,2,3,5,8,… 为斐波那契(Fibonacci)数列

CODE

int n, a=1, b=1, c=0, sum=1;
int month = 1;

scanf("%d", &n);
if ( n>1 ){ //当n==1时,month=1
    month = 2; //当n从2开始时,month从3开始
    while( sum<n ){
        sum = a + b;
        month++;
        c = a + b;
        a = b;
        b = c;
    }
}

printf("%d", month);

习题6-8 统计一行文本的单词个数(**)

统计一行字符中单词的个数。所谓“单词”是指连续不含空格的字符串,各单词之间用空格分隔,空格数可以是多个。

输入样例

Let's go to room 209.

输出样例

5

CODE 1

** 单词+1:① 空格前一个字符不是空格;②’\0’前的字符不是空格。

#include <stdio.h>
#define N 255

int main()
{
    char ch[N];
    int i=0, cnt=0;
    
    gets(ch);
    
    while( ch[i]!='\0' ){
        if ( ch[i]!=' ' && ch[i+1]==' ' ) cnt++;
        i++;
    }
    
    if ( ch[i-1]!=' ' ) cnt++;
    
    printf("%d", cnt);
    
    return 0;
}

出错点:测试点2——空格结尾——运行时错误

分析错因:可能是数组下标越界的问题,因为只循环到 i ,却用了 i+1 作判断

CODE 2

** 单词+1:①第一个字符即开始一个单词;②空格后字符为非空格。

#include <stdio.h>
#define N 255

int main()
{
    char ch[N], *p;
    int cnt=0;
    int flag = 1; //默认为1,为了第一个非空格先标记
    
    gets(ch);
    for( p = ch; *p!='\0'; p++ ){
        if ( *p==' ' ) flag = 1;
        if ( *p!=' ' && flag==1 ){
            cnt++;
            flag = 0; //一旦增加了一个单词,就需要马上重置flag,跳过同一个单词其他字符
        }
    }
    
    printf("%d", cnt);
    
    return 0;
}

结果还是出现相同的错误…

**最后发现,是给数组的空间太小…估计是测试点的字符串长度超过了我设置的255
两个方法都把数组长度改成1000即可通过

练习7-4 找出不是两个数组共有的元素(*)

给定两个整型数组,本题要求找出不是两者共有的元素。

输入:分别在两行中给出两个整型数组,每行先给出正整数N(≤20),随后是N个整数,其间以空格分隔。

输出:在一行中按照数字给出的顺序输出不是两数组共有的元素,数字间以空格分隔,但行末不得有多余的空格。题目保证至少存在一个这样的数字。同一数字不重复输出。

分析

  1. 分别找出a[]中有但b[]中没有的,以及b[]中有但a[]中没有的,并且都放入数组c[]中
  2. 输出c[]时,需注意:①最后不能有空格;②若与已输出的数重复了,则不输出
  3. c[]的大小上限应是两数组上限之和,即有可能都不相同

CODE

#include <stdio.h>
#define N 20
#define M 40 //有可能都不相同

int main()
{
    int a[N], b[N], c[M];
    int n1, n2;
    int i, j, k=0;
    int has = 0; //有相同为1,没有相同为0
    int flag = 0; //c[]中有内容为1,没有为0
    
    scanf("%d", &n1);
    for ( i=0; i<n1; i++ )
        scanf("%d", &a[i]);
    
    scanf("%d", &n2);
    for ( i=0; i<n2; i++ ){
        scanf("%d", &b[i]);
    }
    
    //a[]中有,b[]中没有的
    for ( i=0; i<n1; i++ ){
        has = 0; //每轮都需要重置
        for ( j=0; j<n2; j++ ){
            if ( a[i]==b[j] ){
                has = 1;
                break;
            }
        }
        if ( has==0 ){ //如果不同
            c[k] = a[i];
            k++;
            flag = 1;
        }
    }
    //b[]中有,a[]中没有
    for ( i=0; i<n2; i++ ){
        has = 0; //每轮都需要重置
        for ( j=0; j<n1; j++ ){
            if ( b[i]==a[j] ){
                has = 1;
                break;
            }
        }
        if ( has==0 ){ //如果不同
            c[k] = b[i];
            k++;
            flag = 1;
        }
    }
    
    if( flag ){ //如果两数组有不同的数字
        printf("%d", c[0]); //控制空格
        for ( i=1; i<k; i++ ){ //一共有k个数字
            for ( j=0; j<i; j++ ){ //将要输出的数与前面已输出的每个数作比较
                if ( c[i]==c[j] ) break; //有重复则不输出,也不会有j++使j==i
            }
            if ( i==j ) printf(" %d", c[i]);
        }
    }
    
    return 0;
}

练习7-8 方阵循环右移(*)

本题要求编写程序,将给定n×n方阵中的每个元素循环向右移m个位置,即将第0、1、⋯、n−1列变换为第n−m、n−m+1、⋯、n−1、0、1、⋯、n−m−1列。

输入:第一行给出两个正整数m和n(1≤n≤6)。接下来一共n行,每行n个整数,表示一个n阶的方阵。

输出:照输入格式输出移动后的方阵:即输出n行,每行n个整数,每个整数后输出一个空格。

输入样例

2 3
1 2 3
4 5 6
7 8 9

输出样例

2 3 1 
5 6 4 
8 9 7 

分析

//   假设第i行的列下标为: 0          1          2          3
//         对应的数字为: 1          2          3          4
//    右移一位后的数字为: 4          1          2          3 
//实际输出对应的原下标为: 3          0          1          2
//实际输出对应的原下标为:(4-1+0)%4  (4-1+1)%4  (4-1+2)%4  (4-1+3)%4
//    右移一位后的数字为: 3          4          1          2 
//实际输出对应的原下标为: 2          3          1          2
//实际输出对应的原下标为:(4-2+0)%4  (4-2+1)%4  (4-2+2)%4  (4-2+3)%4
//右移m位输出对应的原下标:a[j]-->a[(n-m+j)%n]

CODE

#include <stdio.h>
#define N 6

int main()
{
    int m, n;
    int a[N][N];
    int i, j;
    
    scanf("%d%d", &m, &n);
    for ( i=0; i<n; i++ ){
        for ( j=0; j<n; j++ ){
            scanf("%d", &a[i][j]);
        }
    }
    
    m = m % n; //只要右移[0,n-1]位即可

    for ( i=0; i<n; i++ ){
        for ( j=0; j<n; j++ ){
            printf("%d ", a[i][(n-m+j)%n]); //直接输出相应的数字即可
        }
        printf("\n");
    }
    
    return 0;
}

习题7-2 求一批整数中出现最多的个位数字

给定一批整数,分析每个整数的每一位数字,求出现次数最多的个位数字。例如给定3个整数1234、2345、3456,其中出现最多次数的数字是3和4,均出现了3次。

输入:在第1行中给出正整数N(≤1000),在第二行中给出N个不超过整型范围的非负整数,数字间以空格分隔。

输出:在一行中按格式“M: n1 n2 …”输出,其中M是最大次数,n1、n2、……为出现次数最多的个位数字,按从小到大的顺序排列。数字间以空格分隔,但末尾不得有多余空格。

输入样例

3
1234 2345 3456

输出样例

3: 3 4

CODE

#include <stdio.h>
#define N 1000

int main()
{
    char a[N][N];
    int n; //数字串个数
    int i, j, k, index; //数组下标
    int tmp; //交换数组位置时临时存放
    int x[10] = {0}; //x[]的下标与数字一一对应,数字出现的次数则是数组元素的内容
    int max; //记录出现次数最多的数字的下标,也即数字本身
    int m[10]; //记录所有出现次数最多的数字的下标,也即数字本身
    
    scanf("%d", &n);
    //getchar();
    for ( i=0; i<n; i++ ){
//         j = 0; //每轮都需要重置
//         scanf("%c", &a[i][j]);
//         while( a[i][j]!=' ' && a[i][j]!='\0' ){ //遇到空格或'\0'则退出
//             j++;
//             scanf("%c", &a[i][j]);
//         }
		//用以上输入,就需要在前面加个getchar()收下换行
        scanf("%s", &a[i]); //用这种就不需要在前面用getchar()
		getchar();
    }
    
    for ( i=0; i<n; i++ ){
        j = 0; //每行都要重置j=0
        while( a[i][j]!='\0' ){
            switch(a[i][j]){  //统计每个数字出现的次数
                case '0': x[0]++; break;
                case '1': x[1]++; break;
                case '2': x[2]++; break;
                case '3': x[3]++; break;
                case '4': x[4]++; break;
                case '5': x[5]++; break;
                case '6': x[6]++; break;
                case '7': x[7]++; break;
                case '8': x[8]++; break;
                case '9': x[9]++; break;
                default: break;
            }
            j++;
        }
    }
    
    //找到出现次数最多的数字对应的下标
    max = 0;
    for ( i=1; i<10; i++ ){
        if ( x[i]>x[max] ) max = i;
    }
    
    //找到所有出现次数一样最多的数字的下标,存放在m[]中
    k = 0;
    m[k] = max; //m[]装出现次数最多的数对应的下标,也即数字本身
    for ( i=0; i<10; i++ ){
        if ( x[i]==x[max] && i!=max ){ //次数相同,但下标不同
            k++;
            m[k] = i; //最后,m[]一共有k+1个数
        }
    }
    
    //将m[]按从小到大的顺序排序
    for ( i=0; i<k; i++ ){
        index = i;
        for ( j=i+1; j<k+1; j++ ){
            if ( m[j]<m[index] ) index = j;
        }
        tmp = m[i];
        m[i] = m[index];
        m[index] = tmp;
    }
    
    printf("%d:", x[max]);
    for ( i=0; i<k+1; i++ )
        printf(" %d", m[i]);
    
    return 0;
}

**但是这片code看起来不太聪明的亚子,有些冗余的亚子( ̄▽ ̄)"

改进

  1. 试试直接用 int 型数组装数字串,但是输入时的空格是否有影响呢?没有影响。
  2. 原本的 x[ ] 数组下标即代表数字,可以直接用 x[digit]++; 来记录数字的出现次数
  3. 找出所有最大值并且选择排序太麻烦了,①仍然用max记录最大次数的下标,之后按 x[ ] 的下标顺序输出值与 x[max] 相等的元素的下标;②用max直接记录最大值,之后按 x[ ] 的下标顺序输出值与max相等的元素的下标

更改的CODE

//更改和添加变量
int num[N]; //改为 int 型数组
int digit = 0; //记录个位数
//删去原本记录下标的数组 m[]、tmp、j、k的定义

//更改输入,并与统计合并
scanf("%d", &n);
for ( i=0; i<n; i++ ){
    scanf("%d", &num[i]);
    //统计每个数字出现的次数
    do{
        digit = num[i] % 10;
        x[digit]++;
        num[i] /= 10;
    }while( num[i]!=0 );
}

//更改方法① —— 直接更改输出即可
printf("%d:", x[max]);
for ( i=0; i<10; i++ ){
    if ( x[i]==x[max] )
        printf(" %d", i);
}

//更改方法② —— a.找最大次数;b.输出
//找到最大的次数
max = x[0];
for ( i=1; i<10; i++ ){
    if ( x[i]>max ) 
        max = x[i];
}
//输出
printf("%d:", max);
for ( i=0; i<10; i++ ){
     //与最大值相同,则输出相应下标,自然是从小到大排序
    if ( x[i]==max ){
        printf(" %d", i);
    }
}

完整的CODE

#include <stdio.h>
#define N 1000

int main()
{
    int num[N];
    int n; //数字串个数
    int digit = 0; //记录个位数
    int x[10] = {0}; //x[]的下标与数字一一对应,数字出现的次数则是数组元素的内容
    int i;
    int max; //记录①最大的次数或②对应下标
    
    scanf("%d", &n);
    for ( i=0; i<n; i++ ){
        scanf("%d", &num[i]);
        //统计每个数字出现的次数
        do{
            digit = num[i] % 10;
            x[digit]++;
            num[i] /= 10;
        }while( num[i]!=0 );
    }

//更改方法①    
//      //找到出现次数最多的数字对应的下标
//     max = 0;
//     for ( i=1; i<10; i++ ){
//         if ( x[i]>x[max] ) max = i;
//     }
    
//     printf("%d:", x[max]);
//     for ( i=0; i<10; i++ ){
//         if ( x[i]==x[max] )
//             printf(" %d", i);
//     }

//更改方法②
    //找到最大的次数
    max = x[0];
    for ( i=1; i<10; i++ ){
        if ( x[i]>max ) 
            max = x[i];
    }
    
    printf("%d:", max);
    for ( i=0; i<10; i++ ){
         //与最大值相同,则输出相应下标,自然是从小到大排序
        if ( x[i]==max ){
            printf(" %d", i);
        }
    }
    
    return 0;
}

你可能感兴趣的:(PTA基础题目集,c语言)