函数题
习题5-6 使用函数输出水仙花数
水仙花数是指一个N位正整数(N≥3),它的每个位上的数字的N次幂之和等于它本身。例如:153=13+53+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;
}
/* 你的代码将被嵌在这里 */
测试点:
出错点:(判断是否水仙花数)
- 忽略幂的次数跟位数相同,即没有计算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)=x0/0!−x2/2!+x4/4!−x6/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<m≤n≤10000)之间的所有Fibonacci数。所谓Fibonacci数列就是满足任一项数字是前两项的和(最开始两项均定义为1)的数列。
函数接口定义:
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 );
void PrintFN( int m, int n );
- 找到符合条件的第一项Fibonacci并标记含Fib
- 若没有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);
}
}
}
习题11-5 指定位置输出字符串
本题要求实现一个函数,对给定的一个字符串和两个字符,打印出给定字符串中从与第一个字符匹配的位置开始到与第二个字符匹配的位置之间的所有字符。
函数接口定义:
char *match( char *s, char ch1, char ch2 );
函数match应打印s中从ch1到ch2之间的所有字符,并且返回ch1的地址。
裁判测试程序样例:
#include <stdio.h>
#define MAXS 10
char *match( char *s, char ch1, char ch2 );
int main()
{
char str[MAXS], ch_start, ch_end, *p;
scanf("%s\n", str);
scanf("%c %c", &ch_start, &ch_end);
p = match(str, ch_start, ch_end);
printf("%s\n", p);
return 0;
}
/* 你的代码将被嵌在这里 */
CODE
#include <string.h>
char *match( char *s, char ch1, char ch2 )
{
int index = -1; //存放子串起始位置
int i = 0;
while( s[i] && s[i]!=ch1 ) i++; //跳过ch1之前的内容
if ( s[i]==ch1 ){ //如果前面是因为s遍历结束了(没有找到ch1),这里就不会进入
index = i; //记录起始位置
while( s[i] ){ //ch2及之前直接输出;如果找不到ch2,也会因为s结束而结束
printf("%c", s[i]);
if ( s[i]==ch2 ) break;
i++;
}
}
else index = strlen(s); //让返回值为空串即可
printf("\n"); //注意,不管是否存在子串都要换行
return s+index;
}
实验11-2-1 建立学生信息链表
本题要求实现一个将输入的学生成绩组织成单向链表的简单函数。
函数接口定义:
void input();
该函数利用scanf从输入中获取学生的信息,并将其组织成单向链表。链表节点结构定义如下:
struct stud_node {
int num; /*学号*/
char name[20]; /*姓名*/
int score; /*成绩*/
struct stud_node *next; /*指向下个结点的指针*/
};
单向链表的头尾指针保存在全局变量head和tail中。
输入为若干个学生的信息(学号、姓名、成绩),当输入学号为0时结束。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stud_node {
int num;
char name[20];
int score;
struct stud_node *next;
};
struct stud_node *head, *tail;
void input();
int main()
{
struct stud_node *p;
head = tail = NULL;
input();
for ( p = head; p != NULL; p = p->next )
printf("%d %s %d\n", p->num, p->name, p->score);
return 0;
}
/* 你的代码将被嵌在这里 */
CODE
void input()
{
struct stud_node *p; //一个空节点
int num, score;
char name[20];
int size = sizeof(struct stud_node);
scanf("%d", &num);
while( num!=0 ){
p = (struct stud_node *)malloc(size); //动态分配内存空间
scanf("%s%d", name, &score);
p->num = num; //填充数据
strcpy(p->name,name);
p->score = score;
if ( head==NULL){ //空链表,则新节点成为头节点
head = p;
//p->next = NULL;
}
else{ //非空链表,则新节点为原来的尾节点的下一个节点
tail->next = p;
}
p->next = NULL;
tail = p; //不论空表还是非空,都是尾节点
scanf("%d", &num);
}
}
实验11-2-2 学生成绩链表处理
本题要求实现一个将输入的学生成绩组织成单向链表的简单函数。
函数接口定义:
struct stud_node *createlist();
struct stud_node *deletelist( struct stud_node *head, int min_score );
该函数利用scanf从输入中获取学生的信息,并将其组织成单向链表。链表节点结构定义如下:
struct stud_node {
int num; /*学号*/
char name[20]; /*姓名*/
int score; /*成绩*/
struct stud_node *next; /*指向下个结点的指针*/
};
输入为若干个学生的信息(学号、姓名、成绩),当输入学号为0时结束。
函数deletelist从以head为头指针的链表中删除成绩低于min_score的学生,并返回结果链表的头指针。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
struct stud_node {
int num;
char name[20];
int score;
struct stud_node *next;
};
struct stud_node *createlist();
struct stud_node *deletelist( struct stud_node *head, int min_score );
int main()
{
int min_score;
struct stud_node *p, *head = NULL;
head = createlist();
scanf("%d", &min_score);
head = deletelist(head, min_score);
for ( p = head; p != NULL; p = p->next )
printf("%d %s %d\n", p->num, p->name, p->score);
return 0;
}
/* 你的代码将被嵌在这里 */
CODE
#include <string.h>
struct stud_node *createlist()
{
struct stud_node *head, *p, *tail; //分别为表头,新节点,表尾
int num, score;
char name[20];
int size = sizeof(struct stud_node);
head = tail = NULL; //建立空表
scanf("%d", &num);
while( num!=0 ){
p = (struct stud_node *)malloc(size); //申请存储空间
scanf("%s%d", name, &score);
p->num = num; //复制数据
strcpy(p->name,name);
p->score = score;
/*插入*/
if ( head==NULL ){ //空表,新节点为表头
head = p;
//p->next = NULL;
}
else{ //非空表,新节点作表尾
tail->next = p;
}
p->next = NULL;
tail = p;
scanf("%d", &num);
}
return head;
}
struct stud_node *deletelist( struct stud_node *head, int min_score )
{
struct stud_node *ptr1, *ptr2;
/*若为表头节点*/
while ( head!=NULL && head->score < min_score ){
ptr2 = head; //ptr2指向头节点
head = head->next; //头节点后移
free(ptr2); //释放原来的头节点
}
/*若链表空*/
if ( head == NULL ) return NULL;
/*非头节点*/
ptr1 = head; //ptr1指向头节点
ptr2 = head->next; //用ptr2从头节点的下一个开始搜索
while ( ptr2!=NULL ){
if ( ptr2->score < min_score ){ //找到
ptr1->next = ptr2->next; //架空ptr2
free(ptr2); //释放ptr2
}
else //没找到
ptr1 = ptr2; //ptr1后移一位
ptr2 = ptr1->next; //ptr2在ptr1后面
}
return head;
}
编程题
练习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]范围内的数字,即三个点的坐标x1、y1、x2、y2、x3、y3。
输出:若这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=13+53+33。 本题要求编写程序,计算所有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 最大公约数和最小公倍数(*)
最大公约数
- 穷举法
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;
}
- 相减法
①若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;
}
- 辗转相除法
①找出较大值,假设为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;
}
最小公倍数
- 最小公倍数=两数之积 / 最大公约数
multiple = m * n / divisor;
- 穷举法
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次反弹的高度,其间以一个空格分隔,保留一位小数。题目保证计算结果不超过双精度范围。
分析:
- 输入非负整数,即包括0,则①初始化反弹高度和路程为0,②添加if条件区分
- 输入的n是落地次数,而不是反弹次数
- 第一次落地:路程=初始高度,第一次反弹高度=1/2 * 初始高度
- 第二次落地:路程+=2 * 第一次反弹高度,第二次反弹高度=1/2 * 第一次反弹高度
- 第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) = 2Sn + 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的正整数)
分析
- S1 = 1
- S2 = 1
- S3 = 1 + 1–>1 = 1 + 1 = 2
- S4 = 2 + 1–>1 = 2 + 1 = 3
- S5 = 3 + 1–>1 + 1–>1 = 3 + 2 = 5
- S6 = 5 + 1–>1 + 1–>1 + 1–>1 = 5 + 3 =8
- S7 = 8 + 1–>1 + 1–>1 +1–>1 + (1–>1 + 1–>1) = 8 + 5 = 13
- S8 = 13 + 1–>1 + 1–>1 +1–>1 + 1–>1 + 1–>1 + (1–>1 + 1–>1 + 1–>1) = 13 + 8 = 21
- 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
- 可见,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个整数,其间以空格分隔。
输出:在一行中按照数字给出的顺序输出不是两数组共有的元素,数字间以空格分隔,但行末不得有多余的空格。题目保证至少存在一个这样的数字。同一数字不重复输出。
分析:
- 分别找出a[]中有但b[]中没有的,以及b[]中有但a[]中没有的,并且都放入数组c[]中
- 输出c[]时,需注意:①最后不能有空格;②若与已输出的数重复了,则不输出
- 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看起来不太聪明的亚子,有些冗余的亚子( ̄▽ ̄)"
改进:
- 试试直接用 int 型数组装数字串,但是输入时的空格是否有影响呢?没有影响。
- 原本的 x[ ] 数组下标即代表数字,可以直接用 x[digit]++; 来记录数字的出现次数
- 找出所有最大值并且选择排序太麻烦了,①仍然用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;
}
本文精选了一系列经典的编程题目,覆盖了从基础到进阶的算法实践,包括水仙花数、余弦函数近似值计算、Fibonacci数列、链表操作、闰年判断、高速公路超速处罚等,提供了详细的解题思路与代码实现,适合编程初学者及算法爱好者参考。
1553

被折叠的 条评论
为什么被折叠?



