数据结构_OJ第一次作业

引言

  1. 这种错题本类型的博客,本学期我大概会写十几篇(包括以后做实验遇到的错题)。
  2. 文章结构:每一题主要是由题目解析与注意事项代码三部分组成。在文章的结尾,记录了我的一些做题心得和暂时还未解决的疑问对于疑问部分,希望能得到各位学霸和大佬指点!
  3. 建议第一次写这些题目的同学可以先看一下题目与解析,自己先敲一下代码,然后再参考参考文章中的代码。
  4. 本人是代码小白一枚,不足之处,烦请各位大佬多多指教!

第一题

题目

  1. 题目描述:
    输入n组数据;
    下面n组,每组两个数a,b;(0<=a,b<=100)
    输出a+b的值。
  2. 输入:
    第一行 n,
    下面n组,每组两个数a,b;(0<=a,b<=100)。
  3. 输出:
    对于每组输入,输出a+b的值,具体见样例。
  4. 样例输入 Copy
    2
    5 6
    7 9
  5. 样例输出 Copy
    Case #1:
    11
    Case #2:
    16

解析与注意事项

  1. a, b两个变量可以重复赋值(不需要保留每一次的a, b的值,只要保留a+b的值即可)。
  2. 两个小Bug。 题目意思应该是要考虑 0<=a,b<=100,并且数组的长度应该是不确定的。但实际敲代码时,不考虑 0<=a,b<=100,并且用确定长度的数组也能过。
  3. C语言使用动态数组一定要包含头文件 <stdlib.h> 。

代码

  1. 第一版。(未考虑 0<=a,b<=100和数组长度不确定的问题。但OJ居然能通过,醉了)
#include<stdio.h>
int main(void) 
{
	int n, a, b;
	int sum[100];
	int i, j;
	scanf("%d", &n);//输入n
	
	//输入并计算a+b的值
	for (i = 0; i < n; i++) 
	{
		scanf("%d%d", &a,&b);
		sum[i] = a + b;
	}
	
	//输出a+b的值
	for (j = 0; j < n; j++)
	{
		printf("Case #%d:\n%d\n",j+1, sum[j]);
	}
	return 0;
}
  1. 第二版。(考虑了 0<=a,b<=100的问题。)
#include<stdio.h>
int main(void) 
{
	int n, a, b;
	int sum[100];
	int i, j;
	scanf("%d", &n);
	for (i = 0; i < n; i++) 
	{
		scanf("%d%d", &a,&b);

		//控制0≤a,b≤100
		while (a < 0 || a>100 || b < 0 || b>100)
		{
			printf("0≤a,b≤100,请重新输入a,b的值:\n");
			scanf("%d%d", &a, &b);
		}

		sum[i] = a + b;
	}
	for (j = 0; j < n; j++)
	{
		printf("Case #%d:\n%d\n",j+1, sum[j]);
	}
	return 0;
}
  1. 第三版。((考虑了 0<=a,b<=100 和数组长度不确的问题)(C语言要用动态数组, Python之类的其他语言,好像可以直接把数组长度改为变量就行了)
#include<stdio.h>
#include<stdlib.h>//使用动态数组要包含的头文件

int main(void) 
{
	int n, a, b;
	int i, j;
	scanf("%d", &n);

	//动态分配内存
	int* sum = NULL;
	sum = (int*)calloc(n, sizeof(int));
	if (sum == NULL)
	{
		printf("内存不足!\n");
		exit(1);
	}
	
	//输入输出
	for (i = 0; i < n; i++) 
	{
		scanf("%d%d", &a,&b);
		while (a < 0 || a>100 || b < 0 || b>100)
		{
			printf("0≤a,b≤100,请重新输入a,b的值:\n");
			scanf("%d%d", &a, &b);
		}
		sum[i] = a + b;
	}
	for (j = 0; j < n; j++)
	{
		printf("Case #%d:\n%d\n",j+1, sum[j]);
	}

	free(sum);//释放内存
	return 0;
}

第二题

题目

  1. 题目描述:
    根据输入N,输出N行字符图样,如输入n=5时,输出
    1
    2 3
    4 5 6
    7 8 9 10
    11 12 13 14 15
  2. 输入:
    输入只有正整数N
  3. 输出:
    N行星形图案,每个数字之间用空格分隔。
  4. 样例输入 Copy
    5
  5. 样例输出 Copy
    1
    2 3
    4 5 6
    7 8 9 10
    11 12 13 14 15

解析与注意事项

  1. C语言中的变量只能在函数的开头处定义,不能在循环中定义变量
  2. 注意输入输出的格式要和样例的一模一样。

代码

#include<stdio.h>
int main(void)
{
	int a = 1,i,j;
	int N;
	scanf("%d", &N);
	
	//不能用i<=N,j<i,否则OJ会判定为「格式错误」
	for (i = 0; i< N; i++)
	{
		for (j = 0; j <= i; j++)
		{
			printf("%d ", a++);
		}
		printf("\n");
	}
	
	return 0;
}

如果把循环条件改为「i<=N,j<i」那么第一次进入内循环时,由于 j=0, i=0, 所以 j=i ,不满足 j<i 的条件,就不执行循环体,直接执行语句「 printf(“\n”); 」 所以第一行会先输出一个空格,而不是 1 。而这与样例输出格式不一样,所以OJ会判为「格式错误」。


第三题

题目

  1. 题目描述:
    输入三个整数a, b, c, 求出其中最大的数!
  2. 输入:
    输入有很多行,每行有三个整数,分别用空格分离。
  3. 输出:
    输出每一行三个整数的最大值,每个输出一行。
  4. 样例输入
    1 2 3
    1 3 2
  5. 样例输出
    3
    3

解析与注意事项

  1. 理解题意。 这一题乍一看就有两个问题——循环停下来的条件是什么呢?要是循环不停下来,又怎么能做到样例输入的那样,连续输入多行,再把每一行的最大值一起输出来呢?其实,这个样例挺误导人的,我以为输入输出是这样的:
    1 2 3
    1 3 2
    3
    3
    其实是这样的:
    1 2 3
    3
    1 3 2
    3
    也就是说,算法的主体其实是个无限循环。

  2. 巧妙利用scanf()的返回值。 我原本的程序是这样的:

    #include<stdio.h>
    int main(void)
    {
    	int n = 0;
    	int num1, num2, num3;
    	int a,max;
    	while (1)
    	{
    		scanf("%d %d %d", &num1, &num2, &num3);
    		a = (num1 > num2) ? num1 : num2;
    		max = (a > num3) ? a : num3;
    		printf("%d\n", max);
    	}
    	return 0;
    }
    

    这与参考答案的区别就在于把输入从循环的判断条件拿到了循环体中。但是这个答案放到OJ上去,系统总是判我 「输出超限0」 后来我才发现,原来是scanf()如果遇到非法输入(即输入的数据类型不符合num的数据类型),输出就会无限循环某个值。
    那么如何解决这个问题呢?
    其实只要将输入(即scanf())从循环体拿到循环的的判断条件中,再利用scanf()的返回值(scanf()返回值返回正确输入数据的数量)设置循环条件是每次正确输入数据的个数为三即可。

  3. 三个数比较大小。 这道题比较三个数的大小我用了两种方法, 一是用条件运算符:

    a = (num1 > num2) ? num1 : num2;
    max = (a > num3) ? a : num3;
    

    二是用 if 语句判断:

     if (num1 < num2)
     {
    	 num1 = num2;
     }            
     if (num1 < num3)
     {
    	 num1 = num3;
     }
    

    其实二者的用起来差不多,看情况选择使用其中一种即可。

代码

  1. C语言版
#include<stdio.h>
int main(void)
{
	int num1, num2, num3;
	int a,max;
	while (scanf("%d %d %d", &num1, &num2, &num3) == 3)
	{
		a = (num1 > num2) ? num1 : num2;
		max = (a > num3) ? a : num3;
		printf("%d\n", max);
	}
	return 0;
}
  1. C++版
#include<iostream>
using namespace std;
int main(void) 
{
    int num1, num2, num3;
    while ( cin >> num1 >> num2 >> num3 )
    {
        if (num1 < num2)
        {
            num1 = num2;
        }       
        if (num1 < num3)
        {
            num1 = num3;
        }
        cout << num1 << endl;
    }
    return 0;
}

做题心得

  1. 粗心易错:使用相关函数时,看看有没有包含相关头文件。使用完后要不要释放内存
  2. C语言中的变量只能在函数的开头处定义。
  3. OJ比较关心的问题:输入输出的格式。OJ没工夫关心的问题:题目的部分要求与潜在的要求。
  4. Visual Studio 2022 整段注释与取消在上方导航窗格中(注释是绿色的三条杠,取消注释是蓝色的返回箭头)
  5. Visual Studio 2022 上用 scanf() 编译过不了,可以使用 scanf_s() 代替或在文件开头加一句 「#define _CRT_SECURE_NO_WARNINGS」即可。建议使用第二种方法,因为OJ上 scanf_s() 编译过不了,上传代码时还要一个一个把scanf_s() 改过来。直接使用第二种方法,复制的时候去掉第一句话就行了。

疑问

  1. 第一题的第三版代码,为什么C语言使用动态数组时,不包含头文件「#include<stdlib.h>」也能运行(运行结果不对,但能运行起来)?不应该报错的吗?(我用的编程软件是Visual Studio 2022 )这是异常结束的图:在这里插入图片描述

    这是正常结束的图:在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值