C博客作业04--数组
这个作业属于哪个班级 | C语言--网络2011/2012 |
---|---|
这个作业的地址 | C博客作业04--数组 |
这个作业的目标 | 学习数组相关内容 |
0.展示PTA总分
- 数组
- 字符数组
1.本章学习总结
1.1 学习内容总结
1.1.1 知识点梳理
一维数组
-
定义
类型名 数组名 [数组长度];
- 注意:数组长度是一个常量
-
引用
数组名 [下标]
-
注意:下标可以是整型表达式,合理取值范围为[0,数组长度-1]
不要让下标越界
-
-
初始化
类型名 数组名[数组长度」{初值表}
- 注意:只有静态存储的数组才能初始化
-
使用
将数组的下标作为循环变量,通过循环可以对数组的所有元素进行处理
输入: for(i=0;i<n;i++) { scanf("%d",&a[i]); } 输出: for(i=0;i<n;i++) { printf("%d",&a[i]); }
二维数组
-
定义
类型名 数组名[行长度][列长度];
-
引用
数组名[行下标][列下标]
-
注意:行下标的合理取值范围为[0,行长度-1],列下标的合理取值范围为[0,列长度-1]
按行→列的方式存放,先存放第0行的元素
-
-
初始化
- 分行赋初值
类型名 数组名[行长度][列长度]={{初值表0},……,{初值表k},……};
- 顺序赋初值
类型名 数组名[行长度][列长度]={初值表};
-
使用
将二维数组的行下标和列下标分别作为循环变量,通过二重循环可以遍历二维数组。将行下标作为外循环的循环变量,列下标作为内循环的循环变量。
输入: for(i=0;i<n;i++) { for(j=0;j<n;j++) scanf("%d",&a[i][j]); } 输出: for(i=0;i<n;i++) { for(j=0;j<n;j++) printf("%d",&a[i][j]); }
-
例题:
-
杨辉三角
注意:判断哪个几个地方用“1”表示,找出数字之间的关系
-
判断是否为上三角矩阵
注意:输出YES/NO是在循环内,判断上三角的条件
术语 含义 下标规律 主对角线 从矩阵的左上角至右下角的连线 i==j 上三角 主对角线以上的部分 i<=j 下三角 主对角线以下的部分 i>=j 副对角线 从矩阵的右上角至左下角的连线 i+j=N-1 -
二维数组每列排序(题目要求:每一列按从小到大的顺序排列且每行的每个数之间有一个空格)
注意:注意输出要换行!!在条件控制中,是在控制列的情况下,每列中的数字两两进行比较。用m变量标为下一个数字,如果后面的 数字大则要换位置。
-
字符数组
-
字符串
一串字符,它的结束标志时'\0',字符串的有效长度就是有效字符的个数
-
存储--赋值和输入
-
注意:区分"a"和'a'
前者是字符串常量,包括'a'和'\0'两个字符,用一维字符数组存放
后者是字符常量,只有一个字符,可以赋给字符变量
-
-
字符串的输入
-
格式化输入:
scanf("%s",str)
当输入字符串时输入'\n'、 ' '时停止录入并且会自动在输入字符后加上'\0'的结束符标志 -
循环输入:
while((str[i]=getchar())!='\n') i++; str[i]='\0' ... for(i=0;str[i]!='\0';i++) ...
- 注意:用结束符'\0'控制循环,不能省略!!!否则字符串就不能正常结束
-
函数输入:fgets()函数
读取文件当中的n-1个字符到s中,从标准输入流中读取字符串,输入的字符个数超出了字符数组的大小不会导致溢出问题。且读取到换行符、文件尾或读完n-1个字符结束。但输入字符长度少于n-1,会多带一个换行符
fgets(数组名,数组数,stdin)
当输入字符串时输入'\n'结束录入并且会将回车键录入,后在其末尾加上'\0'的结束符标志
-
1.1.2 知识点技巧总结
查找数据
-
顺序查找法
将数存入数组,再输入一个数x,在数组中一个一个查找,看是否有相同的数存在,存在即输出相应的下标。
for(i=0;i<n;i++)
{
if(a[i]==x)//如果在数组a中找到了x
{
printf("index is %d",i);//输出相应下标
}
-
二分查找法
首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
基本思想:将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果x<a[n/2],则只要在数组a的左半部分继续搜索x,如果x>a[n/2],则只要在数组a的右半部搜索x.时间复杂度即是while循环的次数。
public static int Method(int[] nums, int low, int high, int target)
{
while (low <= high)
{
int middle = (low + high) / 2;
if (target == nums[middle])
{
return middle;
}
else if (target > nums[middle])
{
low = middle + 1;
}
else if (target < nums[middle])
{
high = middle - 1;
}
}
return -1;
}
插入数据
- 插入排序
在待排序的元素中,假设前面n-1(其中n>=2)个数已经是排好顺序的,现将第n个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。按照此法对所有元素进行插入,直到整个序列排为有序的过程,称为插入排序
简化的插入排序(N给出的数 X需要插入的数 从小到大有序排列,每个数字后有一个空格):
删除数据
-
数组元素的删除
伪代码:
定义数组a[100]
定义变量k //表示进行删除的次数
定义变量n //表示输入的数组元素个数
定义变量m//表示需要删除的数字
定义变量flag//用于储存删除次数
输入n
输入数组a[]
输入删除次数k
while(k--)//循环次数减少
输入变量m
for(i=m-1;i<n;i++)//如果该数字为被删除的数字的前一个数字,则前一个数字需要往前挪
a[i]=a[i+1]
end while
/*输出*/
for(i=0;i<n-flag;i++)//循环到删除次数结束
if(i == n - flag - 1)//删除次数结束
输出数组最后一个数a[i]
else
输出a[i]’空格‘
end for
-
删除数字字符
伪代码:
定义字符串str[1000]
定义变量i 控制循环
定义变量k 控制循环//注意!k=0!!!
输入字符串
for(i=0;str[i]!='\0';i++)
if(str[i]<'0'||str[i]>'9')//如果该字符串中没有数字
str[k]=str[i]//重新建立一个字符串,用k来存储非数字的字符
k++
end if
end for
/*输出*/
for(i=0;i<k;i++)
输出字符串str[i]
end for
-
删除重复字符
伪代码:
定义字符数组a[256]代表出现的次数//ASCII 定义变量ch存储字符 定义变量i控制循环次数 while ((ch = getchar()) != '\n') a[ch]++; //以字符的形式,修改出现的字母 end while for (i = 0;i < 256;i++) if a[i] != 0 //如果对应单元不为0,说明需要输出 输出i; end if end for
排序方法
- 冒泡排序法
从头到尾比较相邻的元素,若前大则与后进行交换。
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
伪代码:
定义变量n存储数组单元个数,k表示扫描的遍数(依题意)
定义数组num[100]存储输入的变量
定义i,j控制循环,temp用于交换
定义cnt 计算交换次数
输入n,k
输入数组num
for(i=0;i<n;i++)//重复操作,直到排序完成
for(j=0;j<n-i-1;j++)//对每一对相邻元素比较大小
if(num[j + 1] < num[j])//比较相邻元素,如果前一个比后一个大,就交换
交换...
end if
end for
end for
输出数组num
- 选择排序法
要排序的一组数中,选出最小(或最大)的一个数与第一个位置的数交换;在剩下的数当中找最小的与第二个位置的数交换,即顺序放在已排好序的数列的最后,如此循环,直到全部数据元素排完为止。
伪代码:
定义数组num[10]存储输入的变量
定义变量n表示给出的数的数量
定义变量i,j控制循环
定义temp用于交换
定义index记录需要交换的下标
输入n
输入数组num
for(i=0;i<n;i++)
index=i;
for(j=i+1;j<n;j++)
if(num[j]>num[j+1])
index=j
end if
end for
交换...
end for
输出数组num
哈希数组用法
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
用一个数组的下标与输入的数据关联起来,再将输入数据与数组下标进行对照。将字母与数组的下标一一对应,对输入数据进行判断,但判断符合时,对应变量num[i]++。
2.PTA实验作业
2.1 数组循环左移
本题要求实现一个对数组进行循环左移的简单函数:一个数组a中存有n(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向左移m(≥0)个位置,即将a中的数据由(a0a1⋯an−1 )变换为(am ⋯an−1a0a1⋯am−1)(最前面的m个数循环移至最后面的m个位置)。如果还需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?
2.1.1 伪代码
定义n,m//n为数组长度,m表示移动的次数
定义变量i 控制循环
定义变量loc
定义数组a[100]
输入n,m
if(n>=m)
loc=n-m//如果n大于m 下标相减
else
loc=n-m%n//如果n小于m 则除余后相减
/*输入*/
for(i=0;i<n;i++)
m=loc%n//从第一个不需要移动的数字开始输入数组
输出新数组
loc++
end for
/*输出*/
for(i=0;i<n;i++)
if(i==0)
输出数组第一个数a[i]
else
输出a[i]’空格‘
end for
2.1.2 代码截图
2.1.3 提交列表
一开始拿到这道题,确实没什么思路,不知道如何用算式来对数组前n位数进行移动。有参考网上的做法,将数字前几位进行取余操作,能够分离出需要移动的数字。
2.1.4 代码比较
-
伪代码:
for k=1 to m for i=1 to n-1 数组左移一个位置 第一个数放在最后一个位置 end for end for
-
(老师的代码)代码截图:
-
区别:
首先,老师采用了封装函数,使代码更加简洁方便。其次,老师采用的思路更加容易理解。对数据的处理,并没有对前几位进行取余再移动而是采用了前后移动。感觉自己写复杂化了...
2.2找鞍点
一个矩阵元素的“鞍点”是指该位置上的元素值在该行上最大、在该列上最小。
本题要求编写程序,求一个给定的n阶方阵的鞍点。
2.2.1 伪代码
定义变量n//n行n列
定义i,j控制循环
定义二维数组a[6][6]
定义列row
定义行line
定义flag//标注是否有鞍点
输入n
/*输入矩阵(两层二维)*/
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",a[i][j])
end for
end for
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(a[i][j]>=a[i][line])//找出行的最大值,行不会改变列
line=j
end if
end for
end for
flag=1
for(row=0;row<n;row++)//每行中的最大值与所对应的列进行比较
if(a[row][line]<a[i][line])
flag=0
end if
end for
if(flag==1)
...
else
None
2.2.2 代码截图
2.2.3 提交列表
首先,根据题目要求需要找出该行上最大、在该列上最小,则这题显然要使用二维数组控制行和列的变化。在提交列表中,多种错误既有段错误、答案错误、格式错误。段错误是在控制row的时候最大值和最小值弄错了。 if (a[i][j] >= a[i][line])在这条语句中,没有加上等号,因为可能存在有并列极值元素,最后一个是鞍点的情况。
2.2.4 代码比较
-
伪代码:
输入二维数据 for(i=0;i<n;i++) { for(j=0;j<n;j++)//找当前i行最大值下标maxIndex for(j=0;j<n;j++) { 判断是否a[j][maxIndex]<a[i][maxIndex] 有,则a[i][maxIndex]不是鞍点,退出循环 } 没有,则a[i][maxIndex]是鞍点,输出,退出循环 } if(?) { 说明没有提前退出循环,没有鞍点 }
-
(老师的代码)代码截图:
-
区别:
学习老师的函数封装!但大体上思路是差不多的,先找到每行的最大值,再找最小值,进行比较,也使用了flag/maxIndex来储存鞍点所在的下标
2.3 切分表达式
四则运算表达式由运算数(必定包含数字,可能包含正或负符号、小数点)、运算符(包括+、-、*、/)以及小括号((和))组成,每个运算数、运算符和括号都是一个token(标记)。现在,对于给定的一个四则运算表达式,请把她的每个token切分出来。题目保证给定的表达式是正确的,不需要做有效性检查
2.3.1 伪代码
定义字符串str[50]
定义变量i 控制循环
定义flag
输入字符串fgets
for (i = 0; str[i] != '\n'; i++)
if(第一个地方就是第一个字符是正负号时)
end if
if(如果是数字或者小数点的话判断下一位是否是小数点或者数字)
end if
else if(负数的判断 前一位是数字还是其他符号)
else if(正数的判断 数字前一位是不是‘(’)
end for
2.3.2 代码截图
2.3.3 提交列表
碰到符号换行输出?碰到数字,小数点直接输出?数字什么时候结束?正负符号?格式错误是因为 str[i] != '\n',而不是str[i] != '\0'2.3.4 代码比较
- 伪代码:
if str[i]是'('或')'或'*'或'/’
找到token,换行输出str[i]
if str[i]是数字或小数点:
if后一位是数字或小数点:
输出数字,不换行
else
输出数字,数字token在这里结束,再输出换行
if str[i]是'+'或'-'
if i==0或 前一位是'(':
str[i]是正负符号,直接输出,不换行
else
是token,换行输出str[i]
- (老师的代码)代码截图:
- 区别:
老师将算式分为运算符、数字、正负号。注意:运算符可以直接换行输出,数字需要判断该数字的前一个数是数字还是小数点,这些都是输出,不换行。判断+- 是要区分是运算符号还是正负号。获取每个字符的前后字符str[i-1]、str[i+1]提前结束本次循环,无需进入不必要分支,提高效率,'+''-'是正负符号字符。老师的代码比较清晰,相比之下我的代码就比较繁琐。