0.展示PTA总分
0.1.一维数组
0.2.二维数组
0.3.字符数组
1.本章学习总结
1.1 学习内容总结
数组查找数据.
- 遍历数组,用if语句判断数组中的数是否与寻找的数字相等。
- 灵活使用flag,判断有无需要查找的数组。
定义数组变量a[10]用来储存输入10个之内的数字 定义变量x用来储存需要寻找的数字 定义变量flag=0用来判断有无需要寻找的数字 for int i=0 to 10 do i++ if(a[i]==x) then flag=1 //找到x,flag重新赋值用以输出找没找到 break //找到X,就跳出循环,减少运行时间 end if end for if(flag==1) then 输出“找到了” else //flag初始化为0,如果if条件不满足不会进入下面的语句,flag的值一直为0 输出“没找到” end if
数组插入数据.
- 该题的前提是有序数组(从大到小或者是从小到大),首先找到插入的位置,因为是遍历数组,只要判断插入的数字大于(或者小于)数组中的数字即可,找到插入的位置后,break结束循环。
- 将数组从最后一个数字开始往后挪(不能从插入位置开始往后挪,因为把每个数字往后移一个后,原来该位置上的数字就会被顶替掉,数据会丢失)。
- 再将X赋值给插入的位置。
定义数组变量Num[n]用来储存输入的有序数列 定义变量X用来储存插入的数字 for int i=0 to n do i++ if(a[i]>X) then //假设该数列是从小到大的排序,如果是从大到小排序的数列,判断条件为a[i]<X break //找到插入位置就退出循环,这个时候就不在对i做任何运算要确保i为插入数字的位置 end if end for for int j=n-1 to i do j-- (这里的i也要进行后移) a[j+1]=a[j] //因为这里要插入一个数,定义数组的时候尽量大一点,防止越界 end for a[i]=X //完成后移的循环后,i位置上的数字就空了用来把X放在该位置上 输出插入X数字的"a[i]"数组
数组删除数据.
- 两个数组删除数据,一个数组储存输入的数据,另一个数组储存删除后的数据。
- 一个数组删除数据,在输入数据的数组中做变换。
两个数组删除数据.
定义数组Num1[n]用来储存输入的数字 定义数组Num2[n]用来储存删除数据后的数字 定义变量X用来储存要删除的数字 for int i=0 to n do i++ if(Num1[i]!= X)then Num2[(int j=0)++]=Num1[i] //把不要删除的数字储存到Num2数组中 end if end for 输出删除X数字的"Num2[j]"数组
一个数组删除数据.
定义数组变量a[n]用来储存输入的数字 定义变量X用来储存删除的数字 for int i=0 to n do i++ if(a[i]==X) then //如果数组中的元素有要删除的数字,就把后面的元素依次向前移一个位置,这样就可以把那个需要删除的数字顶掉 for int j=i to n do j++ a[i]=a[i+1] end for end if end for 输出删除X数字的"a[i]"数组
注解
两种代码各有优劣,只使用一个数组来删除数据,可以减少一个数组变量,整个代码的内存可以减少,但是这种方法也容易出错,使用不恰当会丢失后面的数据,替换的时候容易出错(像数组的倒序一样);使用两个数组删除数据比一个数组要更容易一点,这种方法的代码只需要遍历输入的数组,判断是否与要删除的数字相等,不相等就存进另一个数组。我个人更偏向二个数组的方法,简单明了。
排序方法.
- 选择法排序:每一次内层循环找到最值,记录最值所在位置的下标,内层循环结束后,交换最值所在的位置和外层循环当前所在的位置。
- 冒泡法排序:相邻两个数字依次做比较,并做交换,每一次内循环的结果就是把最大的数排列在数组的最后面。
选择法排序.
代码1
代码2
运行结果1
运行结果2
注解
两个代码的功能是一样的,但是代码二的运行时间会更长,因为它会把前面的数大于后面一个的数字进行交换,交换一轮循环。其实这样的循环完全没必要,这种循环更像是冒泡法排序的方法,最大的数经过一轮循环后在最后面。消耗的时间更多。代码一是直接找到最小数的下标,结束内层循环后再进行交换,也就是说代码一的内层循环只是用来寻找最小数所对应的下标,不进行任何的赋值计算,这样运行更快。代码二是我之前自己打PTA的时候写的代码,看过书之后就知道代码一的优化功能了,所以编程技巧要慢慢的学到后面去掌握以及每一个程序的优化。
冒泡法排序.
代码
运行结果
两种排序法的区别
不同:冒泡法顾名思义就是把最大的数沉在底下,最小的浮在上面,每一次循环都要进行交换;选择法是在冒泡法的基础上进行简化,它不着急交换,只是记录最值的位置,在外层循环才来交换。这样的简化可以减少运行时间。
相同:都是用来排序的方法;两者都是要逐个比较的,找出最值。
数组做枚举用法.
数组的下标是从0开始累计加一和枚举变量一样,枚举变量中是默认第一个变量的数值为0,之后的变量依次累加1。所以可以用枚举的方式表达数组的下标。
(忽略这些红色的线条,VS不支持这个没得法,但是代码本身没有错!!!)
哈希数组.
哈希表,是根据关键码值而直接进行访问的数据结构。也是就说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度(来自百度)。我不是很懂这个哈希算法是啥,有点无助.....老师发布的题集里面好像有一道重复数据的题目:要将一个数组的元素作为另一个元素的下标。
1.2 本章学习体会
学习感受.
老师在讲数组这一章之前,我把课本以及慕课翁恺老师的视频反反复复的看,看了三天左右,颗粒无收,能看懂老师写的代码,也能看懂课本上的代码,但是自己写不出来。(可能是本人的脑子原因,不知道为什么当时咋都不明白数组的使用,现在想想都觉得自己那个时候挺傻的。)数组的用法很广泛,在结构里面用的也比较多。数组相当于一个容器,依次把你输入的数据有序的储存出来,当你要使用它时候,用对应的下标表达即可。从数组开始,一直到后面的指针、结构、链表等等,这些内容都是C语言的灵魂(借用林老师的话)。我最直观的感受就是:C语言的大门从数组开始才是真正意义上打开了。前面所学的一切都是在为后面的精华做准备。不得不说,编程语言有一种魔力。在我没有接触它之前,编程语言离我很遥远,不选择关于计算机方面的专业,我怕是会离它远远的,但是现在,我拜倒在它的石榴裙下,它把我征服了。当时我看不懂数组的时候,内心慌得一批,恐惧了。但是怎么说呢,既然是人编的东西,那我们肯定就能看懂,我硬着头发去阅读了一些别人的写的规范的代码,找到了其中的秘诀,后面就慢慢的顺了。其实不只是数组,后面的难的内容,不是我看个一两遍就会的,这可能算是正常的,但是千万不要灰心,看不懂就一直看,不丢人,看到懂为止。中国人的阿Q精神是很强大的。既然选择远方,便只顾风雨兼程。
代码量.
2.PTA实验作业
2.1 一维数组-数组循环左移
2.1.1 伪代码
定义一个数组a[n]用来储存输入的序列数字 定义变量n用来储存输入的数字的总个数 定义一个变量m用来储存移动的位数 m=m%n //判断移动位数与输入总个数的关系 if(m==n) then //移动位数是总个数的整数倍 原样输出"a[n]"数组 else //输出移动后的数组 for int i=m+1 to n do i++ 依次输出数组元素"a[i]" end for for int i=0 to m do i++ 输出剩下的数组元素"a[i]" end for end if
2.1.2 代码截图
2.1.3造测试数据
2.1.4 PTA提交列表及说明
Q1:没有考虑到m比n大导致一个测试点过不去。
A1:直接加上m=m%n的表达式后是直接按移动后的数据输出。
Q2:加上Q1的表达式后又忽略是m是n的整数倍的关系报错另一个测试点。
A2:整个函数功能要分为两步,一个是m是n的整数倍关系原样输出,另一个是用取余表达式移动后的数据输出。使用取余表达式可以解决m与n大小的问题。
2.2 二维数组-螺旋方阵
2.2.1 伪代码
定义二维数组a[20][20]用来储存输入的方阵 定义变量t=0用来累加赋值给方阵中的元素 定义一个变量count=0用来计算方阵中元素改变的次数 定义二维数组b[20][20]用来判断a[20][20]中数字有没有被替换 for int i=0 to 20 do i++ for int j=0 to 20 do j++ b[20][20]初始化所有元素均为1 end for end for 输入n,表示是n阶方阵 for i=0 to n do i++ for j=0 to n dp j++ b[n][n]赋值为0//表明这些元素要填入合适的数字 end for end for for i=0 to n do i++ for j=0 to n do j++ b[n][n]赋值为0 end for end for while(count< n*n) do while((int y=0) < n &&b[(int x=0)][y] ==0) do 将t赋值给a[x][y] 令b[x][y]为1//表明a方阵的该元素已经是被成功赋值了 t++;y++;count++; end y--;x++ while(y < n &&b[(int x=0)][y] ==0) do 将t赋值给a[x][y] 令b[x][y]为1//表明a方阵的该元素已经是被成功赋值了 t++;x++;count++; end x--;y-- while(y >=0 &&b[(int x=0)][y] ==0) do 将t赋值给a[x][y] 令b[x][y]为1//表明a方阵的该元素已经是被成功赋值了 t++;y--;count++; end x--;y++; while(x >=0 &&b[(int x=0)][y] ==0) do 将t赋值给a[x][y] 令b[x][y]为1//表明a方阵的该元素已经是被成功赋值了 t++;x--;count++; end x++;y++; end 完成上述循环后,输出n阶螺旋方阵"a[n][n]"
2.2.2 代码截图
2.2.3造测试数据
2.2.4PTA提交列表及说明
这道题目,我出现的错误不止提交列表那么简单,我就不按照提交列表来说了。
Q1:当时思路没有理清楚,输入出来的是行式S形方阵
A1:我当时没找到螺旋方阵的规律,改了一种循环方式,输出来的又是列式S形方阵。
Q2:继A1之后又是一番大改动,可是仍旧输出来的是别的类型方阵,还有一个循环越界了。
A2:经历了N多次这样的大改动循环仍旧无故,然后我只能取百度了,借鉴别的优秀的代码,当时还没怎么明白那个螺旋的规律就开始去折腾自己的代码。
Q3:是的,没错,输出的依然是乱七八糟的方阵,毫不夸张的说--乱七八糟,当时心里急得一批,脑子都炸了......就差撞豆腐了
A3:错了总是要改错的勒,万能的度娘又来了,又是去网上找答案咯,看网上的代码,慢慢的知道螺旋的规律,就自己在纸上罗列了那个规律,慢慢的就把那个代码差不多快写出来了....
.
. 这处省略复杂的调试过程
.
部分正确:好不容易把样例的正确答案搞出来了,一提交,OMG,最大的N那个测试点过不了,那个心情真的是想用面条上吊啊!!!
解决方式:我们的助教,隆重出场了,助教说,数组的大小写大一点,虽然题目的要求是小于10的N阶方阵,但是数组的范围大一点会比较好。所以把数组写为了20的范围,然后我又改了一个条件
部分正确:之前的那个条件改错了,再加上没有把b[n][n]初始化为0导致的错误。
解决方式:把前面两个错误修正,让b[n][n]赋值为0的原因是判断改位置是否填入对应的t。
2.3字符串数组-大数加法
2.3.1伪代码
定义字符串数组a[1005]用来储存输入的其中一个相加的大数 定义字符串数组b[1005]用来储存输入的另一个相加的大数 定义数组a1[1005]用来储存倒序的数组a 定义数组b1[1005]用来储存倒序的数组b 定义数组c1[1005]用来储存两个数组中长度较长的倒序后的数组元素 定义变量len1记录数组a的长度 定义变量len2记录数组b的长度 定义变量flag=0用来进位计算 if(len1 > len2) then for int i=0 to len1 do i++ c[i] = c[i] + b1[i] + flag if(c[i] >= 10) c[i] = c[i] - 10 flag=1//如果某一位相加超过十,则上一位对应加1 else flag=0 end if end for if ((c[len1 - 1] + b1[len1 - 1]) >= 10) then 输出"1" //最高位超过十,输出1,不往数组里面写元素是怕会越界 end if for i = len1 -1 to 0 do i-- 输出"c[i]" end for else for int i=0 to len2 do i++ c[i] = c[i] + b1[i] + flag if(c[i] >= 10) then c[i] = c[i] - 10 flag=1//如果某一位相加超过十,则上一位对应加1 else flag=0 end if end for if ((c[len2 - 1] + b1[len2 - 1]) >= 10) 输出"1" //最高位超过十,输出1,不往数组里面写元素是怕会越界 end if for i = len2 -1 to 0 do i-- 输出"c[i]" end for end if
2.3.2代码截图
2.3.3造测试数据
2.3.4PTA提交列表及说明
Q1:当时那个进位那个地方的代码写错了,一旦有一个进位,之后的每一位数字都要加1
A1:灵活定义一个flag=0;如果进入那个要进位的条件就让它等于1,这样下一组相加就会多加1。不满足进位条件仍旧为0,不影响下一组运算。
Q2:最高位进位的测试点没有考虑完全,我把最高位进位放到那个数组最后一个元素+1里面了
A2:如果加1就要放到数组中去,有可能会越界,之前没有考虑到这一方面的问题,所以在输出之前加一个条件,如果最高位也要进位,则另外输出1
3.阅读代码
代码解析:
- while循环条件那条语句使用的是EOF,关于这个EOF我也是前不久才知道的。EOF是End Of File的意思,在C语言中定义的一个宏,用作文件结束标志。从数值角度看,就是-1。这一条是我们可以学习的。
- "#define clr(x)memset(x,0,sizeof(x))",这一条语句很特别,它的常量定义不像我们是直接一个数,该代码是直接宏定义,这样做可以不浪费数字。值得学习