C语言博客作业04--数组

0.展示PTA总分



1.本章学习总结

1.1 学习内容总结

  • 查找数据:
    • 二分查找法:适用于规则按照大小顺序排列的整型数列。
    • 遍历查找法:运用循环,从数列的第一个开始循环查找。
int BinSearch(int *a,int n,int key,int *count)
{
    int left;
    int right;
    int mid;
    left=0;
    right=n-1;
    while(left<=right)
    {
        mid=(left+right)/2;
        (*count)++;
        if(key==a[mid])
        {
            return mid;
        }
        else if(key<a[mid])
        {
            right=mid-1;
        }
        else
        {
            left=mid+1;
        }
    }
    return -1;
}

这里是运用是指针实现二分法查找的函数。二分法的具体步骤为:将数组从中间分为左右两边,找到数组的中间数,与需要查找的数对比,若相等,则结束;否则,若比中间数大,去右半边,反之则取左半边。之后重复上述步骤。

  • 数组中插入数据
    • 方法一:遍历数组,找到对应插入位置后,先将该位置之后所有元素向后移动一位,在将插入元素插入。
    • 方法二:重新定义一个数组,找到插入位置后将数字插入并赋值给新数组。
#include<stdio.h>
#define N 10
int main()
{
	int n;
	int a[N];
	int i;
	int j;
	int x;
	int flag = 0;
	scanf("%d", &n);
	for (i = 0;i < n;i++)
	{
		scanf("%d", &a[i]);
	}
	scanf("%d", &x);
	for (i = 0;i < n ;i++)
	{
		if (x > a[i])
		{
			continue;
		}
		j = n - 1;
		while (j >= i)
		{
			a[j + 1] = a[j];
			j--;
		}
		a[i] = x;
		flag = 1;
		break;
	}
	if (flag==0)
	{
		a[n] = x;
	}/*考虑x是所有数中最大的,放在最后一位或者最小的放在第一位*/
	for (i = 0;i < n + 1;i++)
	{
		printf("%d ", a[i]);
	}
	
	
	return 0;
}

  • 数组中数据的删除
    • 方法一:直接找到需要删除的元素,从该位置之后开始,使用后一个覆盖掉前一个数,实现删除。
    • 方法二:重新定义一个数组,分别按顺序把除了删除数的其他数字赋值给新数组。
#include<stdio.h>
#define N 1000
int main()
{
	int n;
	scanf("%d", &n);
	int i;
	int a[N];
	int j;
	for (i = 0; i < n; i++)
	{
		scanf("%d", &a[i]);
	}
	int k;
	int x;
	int t;
	scanf("%d", &k);
	for (i = 1; i <= k; i++)
	{
		scanf("%d", &x);
		t = x - 1;
		for (j = t; j < n-1; j++)
		{
			a[j] = a[j+1];
		}
		n--;
	}
	for (i = 0; i < n-1; i++)
	{
		printf("%d ", a[i]);
	}
	printf("%d",a[n - 1]);
	return 0;
}
  • 数组中的排序方法
    • 选择法排序:使用嵌套循环,从第一个数开始,先固定一个数的位置后,从他下一位开始诸逐个比较,找到比他大/小的数便交换,最后实现排序。
    • 冒泡法排序:每轮循环会把相邻的两个数进行比较,将大/小的放在后面,逐个比较,最后会将最大/最小的放在最后一位,以此类推。

冒泡法:

#include<stdio.h>
#define N 100
int main()
{
	int a[N];
	int n;
	int k;
	scanf("%d %d",&n,&k);
	int i;
	for (i = 0;i < n;i++)
	{
		scanf("%d", &a[i]);
	}
	int item;
	int count = 0;
	int j;
	int temp = n;
	for (j = 1;j <= k;j++)
	{
		for (i = 0;i < temp - 1;i++)
		{
			if (a[i] > a[i + 1])
			{
				item = a[i];
				a[i] = a[i + 1];
				a[i + 1] = item;
			}
		}
		temp--;
	}
	for (i = 0;i < n-1;i++)
	{
		printf("%d ", a[i]);
	}
	printf("%d", a[n-1]);
	return 0;
}
  • 数组做枚举用法,有哪些案例
    • 例如c07-一维数组 7-5 有重复的数据I
      代码如下:
#include<stdio.h>
#define MAX 100000
int IsSame(int n);
int main()
{
	int n;
	scanf("%d", &n);
	if (IsSame(n)==1)
	{
		printf("YES");
	}
	else
	{
		printf("NO");
	}
	return 0;
}
int IsSame(int n)
{
	int i;
	int data;
	static int hash[MAX];
	for (i = 0; i < n; i++)
	{
		scanf("%d", &data);
		if (hash[data] == 1)
		{
			return 1;//有重复
		}
		else
		{
			hash[data] = 1;
		}
	}
	return 0;//没有重复
}

为了避免出现运行超时的情况,定义了一个hash数组,即哈希数组,利用数组的下标做枚举法,可以大大的简化代码,减少运行时间。但是该做法有弊端,即只适用于0和正整数,无法处理小数以及负数的情况。

1.2 本章学习体会

学习感受
随着校运会以及大部分活动的结束,部门方面的工作也没有那么忙,终于可以有时间来好好研究代码了。高数,线代,PTA,C语言的复习与做题渐渐安排的有条不紊,似乎在暑假中一股劲写代码的感觉又回来了。由于时间的充足,我开始慢慢学会去优化代码,不在像以前那样只要写的出来就算可以。上次的大作业最后的完成度并不太令我自己满意,一个是完成的太仓促,也有我自己的一个原因,另一个就是我发现自己的思维还是太局限了,比如为什么别人想到使用计时器、使用清屏函数,而我却没有想到呢?所以,一个是思维的局限,另一个可能就是在学习中我开始变得被动,老师说一步我做一步。因此,我要开始慢慢改变自己的思路,在写出题目的同时,多阅读分析别人与自己不同的代码,拓宽自己的思路。
这两周还学习了指针,个人认为自己几乎只学到了一点皮毛,到现在为止感觉自己还是对指针懵懵的,希望尽快通过练习来弥补自己的不足吧。

代码量统计

2.PTA实验作业


2.1 PTA题目1

c07-一维数组
7-5 有重复的数据
本题要求:你的程序首先会读到一个正整数n,1<=n<=100000。 然后是n个整数,这些整数的范围是[1,100000]。如果这些整数中存在重复的,就输出:YES。否则,就输出: NO

2.1.1 伪代码

定义 MAX =100000
定义 IsSame函数
主函数main中:
	定义输入的整数个数n 并输入;
    if IsSame(n) == 1 then
        printf("YES");
	else
		printf("NO");
	end if
	return 0;
在函数IsSame(int n)中
	定义循环变量i;
	定义输入数据data;
	定义静态局部变量static int hash[MAX];
	for i = 0 to n-1 do
		输入整数data
		if hash[data] == 1
			return 1;//有重复
		else
			hash[data] = 1;
	return 0;//没有重复

2.1.2 代码截图

2.1.3 造测试数据

注:因为在PTA的测试中,有较大n的测试,自己在调试时不方便测试,就没有输入较大n了,但是一样是可以通过的。

2.1.4 PTA提交列表及说明

Q1:在开始的两次编写中,分别是直接写代码与运用函数封装,但是都只是部分正确。
A1:因为不论是直接写还是函数封装,都使用了嵌套2个for循环,在系统使用较大n测试时,造成运行超时。
Q2:之后解决方法。
A2:在看了林丽老师超星平台的视频后,借鉴了老师的思路,在函数中运用判断该数字data对应的数组hash[data]是否为1的巧妙方法,在整体中只使用了 一次循环,简化了代码,最后成功通过。

2.2 PTA题目2

c08-二维数组
7-6 阅览室 
天梯图书阅览室请你编写一个简单的图书借阅统计程序。当读者借书时,管理员输入书号并按下S键,程序开始计时;当读者还书时,管理员输入书号并按下E键,程序结束计时。书号为不超过1000的正整数。当管理员将0作为书号输入时,表示一天工作结束,你的程序应输出当天的读者借书次数和平均阅读时间。
注意:由于线路偶尔会有故障,可能出现不完整的纪录,即只有S没有E,或者只有E没有S的纪录,系统应能自动忽略这种无效纪录。另外,题目保证书号是书的唯一标识,同一本书在任何时间区间内只可能被一位读者借阅。
输入格式:
输入在第一行给出一个正整数N(≤10),随后给出N天的纪录。每天的纪录由若干次借阅操作组成,每次操作占一行,格式为:书号([1, 1000]内的整数) 键值(S或E) 发生时间(hh:mm,其中hh是[0,23]内的整数,mm是[0, 59]内整数)每一天的纪录保证按时间递增的顺序给出。
输出格式:
对每天的纪录,在一行中输出当天的读者借书次数和平均阅读时间(以分钟为单位的精确到个位的整数时间)。

2.2.1 伪代码

定义天数n,并输入
定义2000行3列的二维数组record[2000][3] = { {0} ,{0} }并初始化位0;
定义循环变量i = 0;
定义循环变量j = 0;
定义循环变量a = 0;
定义k = 0;
定义书号num;
定义小时,分钟hour, min;
定义借阅控制建位flag;
定义借阅次数count = 0;
定义平均阅读时间avg = 0;
for i = 0 to n do
	k = 0;
	count = 0;
	avg = 0;
	while (1)
	{
		输入("%d %c %d:%d", &num, &flag, &hour, &min);
		if num == 0 then
			break;//结束工作
		end if
		record[k][0] = num;
		record[k][1] = flag;
		record[k][2] = hour * 60 + min;//将输入的书号值赋给数组第一列,建位赋给第二列,时间转化位分钟后赋给第三列
		k++;
	}
	for j = 0 to k do
		if record[j][1] == 'S' then
			for a = j + 1 to k do
				if record[j][0] == record[a][0] && record[a][1] == 'S' then/*当出现同一本书借出后没有还回又输入‘S’或已还回却多次输入‘E’这些不合法输入*/
					break;
				end if
				if record[j][0] == record[a][0] && record[a][1] == 'E' then/*合法输入时,循环找寻书号相同 第二列为‘E’的行*/
					count++;
					avg = avg + record[a][2] - record[j][2];
					break;
				end if
			end for
		end if
	end for
	if count != 0 then
		输出("%d %.0f\n", count, avg / count);
	else
		输出("0 0\n");//借阅次数为0时
	end if
end for
return 0;

2.1.2 代码截图

2.1.3 造测试数据

2.1.4 PTA提交列表及说明

Q1:出现段错误
A1:在访问数组时越界,后经修改后解决
Q2:出现多次的部分正确,几次修改后并没有解决
A2:在观看了林丽老师的视频后,发现是一开始我自己写时函数接口没有处理好,导致传入的参数出现异常,最后只有输出“0 0”是正确的。后来参考了林丽老师的思路,写出了这个不加函数的代码。

2.3 PTA题目3

c09-字符数组
7-7 jmu-c-大数加法 
输入2个大数,每个数的最高位数可达1000位,求2数的和。输入格式:保证输入数都是数字,不能有空格。输出格式:输出2数相加的结果

2.3.1 伪代码


#define M 10000
定义全局变量char s1[M], s2[M];
定义全局变量int a[M], b[M], c[M];

定义循环变量 i;
定义变量j, k, n, m;
定义变量 t;
输入两个字符串
memset(c, 0, sizeof(c));//把c的全部函数重置为0
n = strlen(s1);//第一个字符串的长度
m = strlen(s2);//第二个字符串的长度
//printf("s1的长度= %d s2的长度= %d\n", n, m);
for i = 0 to n do
	a[i] = s1[n - i - 1] - '0';
end for
for i = 0 to m do
	b[i] = s2[m - i - 1] - '0';
/*这两步是将字符串从最后一位开始变成数字后赋给a,b数组 */
if n > m do//第一个数组更长
	k = n;
else
	k = m;
end if//令k等于长的那个
for i = 0 to k do
	c[i] += a[i] + b[i];
	if c[i] > 9 then
		c[i + 1]++;
		c[i] %= 10;
	end if//进位
end for
	i = k;
while (c[i] == 0)
{
	i--;
}/*判断最高位是否有进位。如:若 k=3,如果是100+100,那么c[3]就是0,所以此时没有进位,输出时i从k-1到0输出数组;
	 如果是900+200,那么那么c[3]就是1,所以此时进位,输出时i从k到0输出数组,所以这也是为什么上面数组加法是要从0到k
	 进行赋值*/
if (i < 0)
	printf("0");
else
	for t = i to 0 do
		printf("%d", c[t]);//从最后一个开始输出,因为输出的其实是没有间隔的数组,所以避免了直接输出数字的越界问题
end if
	printf("\n");

return 0;

2.3.2 代码截图

2.3.3 造测试数据

2.3.4 PTA提交列表及说明

Q1:运行超时
A1:一开始是没有想到使用数组的方式进行输出,还是想使用int,而且在循环方面没有处理好范围,导致了死循环。后来想到数组输出的方法,进行了几次调试,最后成功。


3.阅读代码:

  • 代码功能
    计算输入算式中的未知数并输出

  • 代码优点

    • 灵活定义了全局变量,有利于数据在函数之间的传递。
    • 封装了多个函数,使主函数更加简洁,将对输入字符串的判断一并写入函数中。在执行完第一个函数内容后返回主函数并前往下一个函数,函数接口处理的十分漂亮。
    • 在第一个函数中设置了其他函数,这些函数内容简短但是关键,我们以后也需要学会用更简短的代码达到我们的目的。
    • 逻辑条理清晰,想法独特但是易懂,各个函数的功能区分的很明显,函数与函数之间的联系也很紧密,避免了代码的大量重复,值得我们学习。
posted on 2019-11-17 22:10  蔡浩伟  阅读(495)  评论(0编辑  收藏  举报