C语言博客作业04--数组
0.展示PTA总分
- 一维数组
- 二维数组
- 字符数组
1.本章学习总结
1.1.学习内容总结
- 一维数组
- 定义类型 数组名[数组长度];
- 数组下标从 0 to 数组长度-1
- 一般是引用下标来进行排序等操作
- 初始化可是有三种做法,分别是遍历数组等于0;使用static int a[N];使用 int a[N]={0};
- 二维数组
- 定义类型 数组名[行长度][列长度]
- 不管行标还是列标 其下标都是从0开始的
- 主对角线: a[i][i];
- 反对角线: a[i][n-i-1];
- 上三角矩阵: i<j 即行标小于列标
- 下三角矩阵: i>j 即行标大于列标
- 字符数组和字符串
- 字符数组以'\0'为终止符 也可以利用字符数组来输入字符串 但是数组长度要比输入的字符+1 用来存'\0'
- 字符串的头文件 是 #include <string.h>
- 字符串的输入可以通过 scanf("%s",&str[N]);以空格或者回车结束 也可以通过 fgets(str,N,stdin);以回车结束 gets太危险已经被淘汰 还有利用循环来输入
while((str=getchar())!='\n')
注意:如果是使用fgets来输入 缺点是输入字符长度少于n-1,会多带一个换行符。
循环条件需要这样设置:
for(i=0;str[i]&&str[i]!='\n';i++) - 字符串的输入 可以是 循环输出 for (i=0;str[i]!='\0';i++) putchar(str[i]); 也可以是 printf("%s",str); 也可以是puts(str); 注输出后会自动换行
- 数组数据的查找
- 顺序查找法 即一个数一个数的列出来查找
//例如 这里给出一数组 其长度为10 int a[10]={0,1,2,3,4,5,6,7,8,9}
//用枚举法查看这个数组的每一个元素
for i=0 to 9 do
printf("%d",a[i]);//输出每一个数组所储存的数
end for
//找到需要的数 然后输出
- 二分查找法 即利用二分法在有序数组中查找需要的元素
//定义数组 这个有序数组a中存在一个元素 定义为key
//例如 有序数列{1,2,3,4,5,6,7,8,9,10}查找key
//输入要查找的key
//设置这个二分查找的函数将key和有序数组a存放进去 找到就返回这个数在这个数组的下标 找不到就返回-1 然后输出找不到
low=0,high=10;//定义两个临界的下标
while (low <= high) do
mid=(low+high)/2; //设置中间数的下标
取中间数a[mid]
if(key>a[mid]) low=mid+1;//右区间 缩小范围
else if(key<a[mid]) high=mid+1;//左区间 缩小范围
else return mid;
end while
return -1;//找不到
-
哈希查找
适用于大数据查找,但我不是很会 -
数组数据的插入
- 思路:
1)先确定它是一个有序数组如果不是就对他进行排序 然后决定插入数据
2)查找插入位置loc 进行有序的插入
3)数组右移:从最后一个数右移扩展 然后--到loc右移一个位置。
- 思路:
for i=0 to n-1 do //按顺序找插入位置
if 找到插入位置loc
for j=n to loc+1 do j-- //因为只插入一个位置 所以数组长度应该扩展n+1 下标为n
a[j]=a[j-1];
end for
右移完成后 令a[loc]=num 即插入的数据就可以break了
否则就是直接放在 a[n]=num 再break num是最大或者最小数
end for
- 数组数据的删除
- 一般应用于字符串或者数组 例如删除空格
思路:
1)输入一串字符 有空格的
2)当字符串输出不遇到空格的时候就putchar
- 一般应用于字符串或者数组 例如删除空格
输入字符串 例如 char *p="sajij jsiaj"
char c;
while ((c=p[i++])!='\0') do
if c!=' ' putchar(c);
end if
end while
- 也应用于删除某个数后 的数组输出
思路:
1)删除第几位的下标的数等于下一位
2)左移数组到删除后的下一位的数
//假设要删除的是第x位数
a[x-1]=a[x];
for i=x to n-1
a[i]=[i+1];
- 也应用于重构数组保存未删除前的数组
例如在循环左移时 储存要移动的数 之后 输出移动的数之后原来的数组 从一开始 然后再输出已经储存的要移动的数
这样子可以减少 移动次数
定义 a为原来的数组 b是暂存数据
n是数组长度 m是移动次数 move=m/n
for i=0 to move
b[i] = a[i];
end for
用来暂存移动的数 因为如果移动的话 前面的数是没办法储存的
移动数据左移
最后再令后面的数等于移动的数
- 数组的排序
- 选择法排序
思路:
例如: 4 2 5 8 1 用选择法将它们进行排序
- 选择法排序
下标 | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
值 | 3 | 5 | 2 | 8 | 1 |
第0遍 | 1 | 5 | 2 | 8 | 3 |
第1遍 | 1 | 2 | 5 | 8 | 3 |
第2遍 | 1 | 2 | 3 | 8 | 5 |
第3遍 | 1 | 2 | 3 | 5 | 8 |
n个数需要跑n-1遍 | |||||
n个数从a[0] ~ a[n-1]中找最小数,与a[0]交换 | |||||
n-1个数a[1] ~ a[n-1]中找最小数,与a[1]交换 |
……
即每找到到一个最小数 交换后依次固定前面的数 再找
for i=0 to n-2 do//值比较到n-2个 到n-1个数的时候就停止了
for j=i to n-1 do
找最小数min
min与a[i]交换
end for
end for
- 冒泡法排序
思路:将相邻两个数比较,将小的调到前头。
动画演示:
此冒泡法动态演示出处
for i=0 to n-2 do//值比较到n-2个 到n-1个数的时候就停止了
for j=0 to n-i-2 do
找最小数min
min与a[i]交换
end for
end for
- 插入法排序
思路:找到位置 直接插入
由于此方法不太熟悉 也不常用 所以此处引用了老师的伪代码
for index=1 to n-1 do //从第二个数插入
number=a[index] //插入的数
for i=0 to index-1 do //往前找插入位置
查找插入位置loc
end for
for i=index to loc+1 do //移动数组
右移 a[i]=a[i-1]
end for
a[loc]=number //插入数
end for
- 数组做枚举的用法
- 一般用来枚举星期
首先是枚举的定义:
- 一般用来枚举星期
enum 枚举名 {枚举元素};
注:枚举如果第一个元素不进行定义 则默认初始化为0 后面的元素依次+1
没有指定值的枚举元素 它的值默认是前一个元素的值+1
还不知道有啥学过的枚举用法,太孤陋寡闻了,主要是不太熟练,不知道怎么运用
- 哈希数组用法
目前我还没有用哈希数组解题过 但是有在网上了解了哈希数组的用法
但是左看右看前看后看 我还是不太懂
可能是我的智商不够用吧 感觉是下个学期数据结构的内容
是用来对大数据进行查找的数组
会哈希数组和数组做枚举可以在下面评论和我讨论一下的哈
1.2本章学习体会
1.2.1学习体会感受
这次数组的PTA真的是刷的很慢的 老师还给我们推迟了一周时间 但是还是没能按时完成 我感觉数组是真的挺难的 特别是二维数组和字符数组 再来就是字符数组里面的字符串很容易搞混 而且我在写代码的过程中也遇到了很多问题 比如 数组堆栈被破坏导致段错误或者运行超时等 还有排序时 初始化没有做得很好 但是已经开始学着去结合函数来完成了 遇到问题也多亏了助教的循循善诱 我很开心! 我感觉应该要赶紧完成PTA所有题目 再复习巩固 才能对数组这个章节有深刻的理解吧,虽然说推迟了一周 但是前一周我的确没有很好的进行写数组的pta 因为刚学了指针 所以很多东西又容易混淆 真的感觉很惭愧 理解也比别人慢 参加活动也比较多 写题也很久 但是第二周基本能做到一天1-3题
1.2.2代码量
周次 | 合计 | |
---|---|---|
第10周 | 450 | |
第11周 | 643 | 2336 |
第12周 | 1243 | |
这几周的代码真的是删删减减改改 害 体会到了程序员的痛了! |
2.PTA实验作业
2.1 c07-一维数组 7-10 出生年
以上是新浪微博中一奇葩贴:“我出生于1988年,直到25岁才遇到4个数字都不相同的年份。”也就是说,直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求,自动填充“我出生于y
年,直到x
岁才遇到n
个数字都不相同的年份”这句话。输入格式:
输入在一行中给出出生年份
y
和目标年份中不同数字的个数n
,其中y
在[1, 3000]之间,n
可以是2、或3、或4。注意不足4位的年份要在前面补零,例如公元1年被认为是0001年,有2个不同的数字0和1。输出格式:
根据输入,输出
x
和能达到要求的年份。数字间以1个空格分隔,行首尾不得有多余空格。年份要按4位输出。注意:所谓“n
个数字都不相同”是指不同的数字正好是n
个。如“2013”被视为满足“4位数字都不同”的条件,但不被视为满足2位或3位数字不同的条件。
2.1.1 伪代码
判断是否满足 封装了一个函数 返回得到的年份
int satisgyIs(int inputYear,int n)
while 循环至遇到满足的条件为止
拆分用户输入的inputYear 将每个数存进数组b中;
定义一个小数组a[4]={-1,-1,-1,-1} 存进负数 因为年份不能出现负数
//a数组的作用是为了数不同
for i=0 to 3
建立一个flag=1
for j=0 to 3
检查a数组的各个值是否有等于数组b的数 有的话标记flag为0 跳出内循环
if(flag==1)
a[index++]=b[i];//index++主要是为了计算存进去的数目
end if
end for
当index=n时即找到了这个年份 就可以返回这个年份了 因为a里面的数都不相同 已经储存够了这么多
用户输入的数每一年都递增 所以用户年++ 继续下一轮循环
2.1.2 代码截图
2.1.3 造测试数据
输入数据 | 输出数据 | 说明 |
---|---|---|
1988 4 | 25 2013 | 正常数据 |
1 2 | 0 0001 | 不足4位补零数据 |
- 运行效果
2.1.4 PTA提交列表及说明
- 提交列表
其实这道题虽然提交列表很少 但是我是停滞了一天的 遇到了问题不知道如何解决 思路卡住了 - 提交列表说明
Q1 部分正确:问题就是我一开始 其实是将b数组之间每一个数都比较是否不相等 一次不相等我就记录一次count 后来发现测试数据全错了
比如 1988 4: 1和8不相等出现了两次 又或者 1 2:即0001 0和1不相等出现了四次。。。
为此我停顿了很久毫无思路
A1:后来我就询问了助教 助教告诉我换个思路 用小数组暂存 然后让小数组里不同的年份拆数 出现过的就不储存 这样就可以完美解决我的问题了
我觉得这个方法和思路都非常巧妙 所以尝试做了一遍 发现真的可以完成!
2.2 2019-c08-二维数组 7-5 找鞍点
一个矩阵元素的“鞍点”是指该位置上的元素值在该行上最大、在该列上最小。
本题要求编写程序,求一个给定的n阶方阵的鞍点。
输入格式:
输入第一行给出一个正整数n(1≤n≤6)。随后n行,每行给出n个整数,其间以空格分隔。
输出格式:
输出在一行中按照“行下标 列下标”(下标从0开始)的格式输出鞍点的位置。如果鞍点不存在,则输出“NONE”。题目保证给出的矩阵至多存在一个鞍点。
2.2.1 伪代码
- 思路:这里注意要求是行的最大数,列的最小数 而且题目也控制了它的输入 那么就先比较行的最大数是不是列的最小数 是就是鞍点 不是就下一行 到最后还没找到就输出NONE
封装一个函数是否找到 找到返回1 没找到返回0
int find(int a[N][N],int n,int *row,int *col) 把这个函数放在主函数的if中
for i to i-1 do//先固定行 比较行的最大值
一定要对row和col进行初始化 再记录一个flag=1 一开始默认找到
for j to j-1 do//开始比较每一个数 找最大的
if(a[i][j]>a[i][*col]) 记录行标和列标
end if
end for
//找到这行的最大 然后就开始判断它是不是这一列最小的
for k to k-1 do //因为要比较的是列 所以要把列数控制住 移动行
if(a[*row][*col]>a[k][*col]) 修改flag 记录不是鞍点
end if
end for//找完后
判断flag有没有没修改过 修改过就继续下一行 没修改过就可以直接返回1了
end for
每一行都找过了 flag都被改了 所以都没有鞍点 返回0
2.2.2 代码截图
2.2.3 造测试数据
输入数据 | 输出数据 | 说明 |
---|---|---|
4 1 7 4 1 4 8 3 6 1 6 1 2 0 7 8 9 |
2 1 | 存在鞍点 |
2 1 7 4 1 |
NONE | 不存在鞍点 |
4 1 7 4 12 4 8 3 11 1 6 1 10 0 7 8 9 |
3 3 | 最大规模,有并列极值元素,最后一个是鞍点 |
2 5 4 6 1 |
0 0 | 最小规模 |
- 运行效果
2.2.4 PTA提交列表及说明
- PTA提交列表
- 说明
Q1 运行超时:这里是个小错误 输入的时候行列都写成了i<n
A1:改过来就对了
Q2 部分正确:这里是逻辑错误 这里判断不是鞍点后 我直接返回零 导致即使鞍点存在 但后面行再出现鞍点时也会输出NONE
A2:所以我设置了一个flag 让flag一开始就默认是1 即鞍点存在 如果判断不是鞍点的时候就可以记录一下 修改flag 这样就可以避免这种情况
Q3 部分正确:这里是我修改上一个错误修改错了 我没有利用flag 只是让它判断不是鞍点的时候的返回零删掉了 把return 0放在最外层循环外面 甚至还把return 1 用在了if else的语句里 所以错误离谱 只得了两份
A3:所以发现行不通之后 我就设置了一个flag
Q4 部分正确:这里是初始化问题 进入循环的时候我没有对row和col进行初始化
A4:要进行初始化 如果不进行初始化 则row就会不被赋值 比较也会出错 所以要进行初始化每次都跟从0开始比
Q5 部分正确:这里的问题是 我在比较行最大的时候写的是 if(a[i][j]>a[i][col])
A5:如果这样写的话 就会使得如果没有满足这个条件 即换行第一个数就是最大数的时候 row和col就不会被记录 所以应该修改成 if(a[i][j]>=a[i][col])
2.3 2019-c09-字符数组 7-7 jmu-c-大数加法
输入2个大数,每个数的最高位数可达1000位,求2数的和。
输入格式:
保证输入数都是数字,不能有空格
输出格式:
输出2数相加的结果
输入样例:
92345434336786876823540234787293542423 13343434323979878542919487294910345782
输出样例:
105688868660766755366459722082203888205
2.3.1 伪代码
- 思路:
1)从最后一位开始相加 如果相加大于或等于十则 和-10 然后下一位进1
2)将它们逆序存放进一个答案数组里 这个答案数组最后再逆序输出即可得到正确的答案
3)要考虑两个数位数不相同的情况 哪一个长就用循环让它剩余位数再逆序存放进答案数组中 同时也要考虑进位问题
4)最高位进1问题!
//先定义两个字符串str1[MAX] str2[MAX] 再计算两个字符串的长度len1,len2
//建立一个flag=0来判断是否进位 是则改为1,否则为0 和一个储存答案的字符数组resultStr[MAX]
for i=len-1,j=len-1 to i=0||j=0 do
将两个数转成数字num1和num2
if (num1 + num2 + flag >= 10)//判断是否进位
和-10 记录进位
else 直接相加 记录进位
end for
while(i>=0)//或者while(j>=0) 这是为了考虑两个数不等长的情况
转成数字
考虑进位 如果进位 就让和-10 再存放进答案数组里 记录进位
不进位就直接逆序存放进答案数组里 记录进位
end while
//判断最高位是否补1
if(flag) 让最后一个存放进resultStr数组的字符为'1'
else 就让答案数组的输出长度减- 否则会多出空格
for k to 0
逆序输出答案数组
end for
2.3.2 代码截图
2.3.3 造测试数据
输入数据 | 输出数据 | 说明 |
---|---|---|
92345434336786876823540234787293542423 13343434323979878542919487294910345782 |
105688868660766755366459722082203888205 | 最高位进位 |
45252656451262625152362755136658484844 41121212541214122414152232514124514141 |
86373868992476747566514987650782998985 | 最高位没进位 |
45152654856 5654848262325151 |
5654893414980007 | 第一个数的位数比较少 |
1223251323515152325154 1546565845485262 |
1223252870080997810416 | 第一个数的位数比较多 |
- 运行效果
2.3.4 PTA提交列表及说明
- PTA提交列表
Q1答案错误:没有考虑到字符与数字之间的转化
A1:因为我用的是字符数组来储存答案 而且字符之间不能进行运算 要先转化成数字运算完之后转成字符 存进数组里
Q2答案错误:在第一个for循环的循环条件没有考虑到长度不相等的情况
A2:所以第一个for循环的条件 应该是只有i和j都>=0的情况下才能继续 如果长度不相等 因为肯定有一方先为0
Q3答案错误:因为没有考虑到补一的情况
A3:当i和j都为0后要考虑 最高位是否要补1 在上面的代码中 注释里我写的很清楚了为什么要那样做 为什么要k--是因为不补1的时候要除去空格
Q4答案错误:我利用了fgets来输入 计算长度的时候 换行符也被计算进去了 导致后面程序很崩溃
A4:所以计算两个字符串的长度的时候要-1 才可以得出真正输入的字符总数
Q5答案错误:没有考虑到当两个数不相等的时候 多出来的数的进位问题
A5:采用了类似第一个for循环里的方法 对多出来的数进行进位处理和存放
3.阅读代码
- 优秀代码 题目源于ACM题集
- 题目
- 翻译
- 题目
Mirko在由M个上锁的猪舍组成的养猪场工作,而Mirko由于没有钥匙,因此无法解锁任何猪舍。客户接连来到农场。他们每个人都有一些养猪场的钥匙,并想购买一定数量的猪。
Mirko可以在清晨获得与计划在特定日期访问农场的客户有关的所有数据,以便他制定销售计划,以最大限度地出售生猪。
更准确地说,过程如下:客户到达,打开他拥有钥匙的所有养猪场,Mirko从所有未上锁的养猪场向他出售一定数量的猪,如果Mirko想要,他可以将剩余的猪重新分配到解锁的猪舍中。
每个猪舍中可以放无限数量的猪。
编写一个程序,以查找他当天可以出售的最大数量的猪。
输入描述
输入的第一行包含两个整数M和N 下一行包含M个整数,用于每个养猪场的初始猪数量。每个猪舍中的猪的数量大于或等于0且小于或等于1000。
接下来的N行包含以下形式的有关客户的记录(有关第i个客户的记录写在第(i + 2)行中):
A K1 K2 ... KA B这表示该客户拥有标有数字K1,K2,...,KA(降序排列)的养猪场的钥匙,并且他想购买B头猪。
数字A和B可以等于0。
输出描述
输出的第一行(也是唯一一行)应包含出售的猪的数量。
输入例子
3 3
3 1 10
2 1 2 2
2 1 3 3
1 2 6
输出例子
7
-
代码截图
-
代码理解
由题目可知,此代码的作用是通过操作算出Mirko应该出售多少头猪。- 代码功能及其优点 有些内容是没学过的 所以答得不一定对
- 头文件中加了using namespace std 设置了命名空间 防止引起命名冲突 (好像这是C++的内容)
-
define inf 0x3f3f3f3f 设置最大整型数 防止堆栈被破坏
C++内容就不做过多理解了,因为我也不会
3)它每一个主函数只调用了两个函数 但是 其它函数之前的关系又能很紧密的联结在一起,增加了代码的可读性 不用老是一直返回看主函数
4) 使用了两个特别的函数 memset()和memcpy() 前者是将某一块内存中的内容全部设置为指定的值, 这个函数通常为新申请的内存做初始化工作。 后者是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中
但是这一大串代码没写注释 所以看得很困难啊……
阅读优秀代码对于我来说是真的很困难了...