目录
练习7-4 找出不是两个数组共有的元素 (20 分)
输入格式:
输出格式:
输入样例:
输出样例:
前言:
总结与收获:
最后美化紧凑版
伪代码逻辑实现的注释版
给定两个整型数组,本题要求找出不是两者共有的元素。
输入分别在两行中给出两个整型数组,每行先给出正整数N(≤20),随后是N个整数,其间以空格分隔。
在一行中按照数字给出的顺序输出不是两数组共有的元素,数字间以空格分隔,但行末不得有多余的空格。题目保证至少存在一个这样的数字。同一数字不重复输出。
10 3 -5 2 8 0 3 5 -15 9 100
11 6 4 8 2 6 -5 9 0 100 8 1
3 5 -15 6 4 1
这道题耗了我一天,一整天!都在debug!!!,写这篇博客是为了让我永远铭记曾经犯下的错,以及等我学成归来,要以傲视群雄的姿态对这道题说一句:呵呵,就这?
第一步:读懂题意,明确任务。
任务1:分别在两行中给出两个整型数组,每行先给出正整数N(≤20),随后是N个整数,其间以空格分隔。
解读:此条件看上去人畜无害,实则让你不能用构造函数的方式实现输入。(反证我是不会!)只能分两次输入,其实现也比较简单,核心逻辑如下,用两次,两次的循环变量都可以用 int i 。
for (int i = 0; i < na; i++) { //i语句内的循环变量,离开语句就失效,因为本题会用很多次循环,有些循环变量需的变量作用域比较大,有利于重复利用变量名
scanf("%d",&a[i]);
}
任务2:在一行中 按照数字给出的顺序输出 不是两数组共有的元素,数字间以空格分隔,但行末不得有多余的空格。题目保证至少存在一个这样的数字。同一数字不重复输出。
兄弟们,看上个这条件,表面上简简单单的,实际上句句都是要点,句句的实现都要人掉头发!
首先我们用过样例来具体理解和分析一下:
输入样例的具体形式:
假设na=10 ,则输入的 数组每个值具体如下:a[0]=3 a[1]=-5 a[2]=2 a[3]=8 a[4]=0 a[5]=3 a[6]=5 a[7]= -15 a[8]=9 a[9]=100
假设nb=11 ,则输入的 数组每个值具体如下:b[0]=6 b[1]=4 b[2]=8 b[3]=2 b[4]=6 b[5]= -5 b[6]=9 b[7]=0 b[8]=100 b[9]=8 b[10]=1
输出样式分析:
条件指出:要输出的数据 “不是两数组共有的元素” ,
其基本逻辑便是: 首先拿数组a的第一个元素3 依次和数组b中的每一个元素进行比较,若有相同就跳过本a[ i ] ,继续拿数组a的下一个元素重新和b数组的第一个比较。
直到和b数组的每一个元素都比较依次,而且每一个都不相同,则可以输出数组a[ ] 在该个位置的值。
比如 a[0]=3 和b数组的每一个元素都不相同,所以可以输出3。
为了各位看起来方便:我把数组a和数组b中,对应一致的颜色标记成一样的。
所以我们可以简单的思考:首先通过简单的循环比较,把两个数组之间 不是共同的元素找出来,然后直接输出。
但是,这里我们看到了出题人的险恶之处,数组a 内部 0 号位置 和 5 号位置 都是3 重复了, 数组b内部 0号位和4 号位重复了。 所以不能直接输出,除此之外,还有行末不得有多余的空格,这种恶心的条件也同样对输出格式做出了严格的限制。
所以我们自然要思考另外一种方式,本章主要是学习内容是数组,所以自然而然我们可以新建一个数组C 先存储比较的出来的数值 ,最终其内部变量应该为C[ ] ={3 , 3 ,5 , -15 , 6 , 4 ,6 ,1},然后,我们在通过遍历这个数组,不重样的输出结果。
还有一种思维方式:就是在将数组A B比较的结果,在存入输出 数组C之前,就先查看,数组C内部是否已经有了和当前找到的 非共同元素 相等的值,若已经存在,就跳过这次的存储。
通过上述的分析:
任务2可继续拆解成5个小步骤。
伪代码:
步骤1:在数组A中按序取一个值 (for 的 i 到 na 的循环,此处的循环变量 用 mian() 函数内部的全局变量) 第一层遍历数组A的 i 循环
依次和数组B的第一个到最后一个比较, (for 的 j 到 nb 的循环) 第二层遍历数组B的 j 循环
若提前相同,则提前跳出本轮对于数组 A 中第 i 号位置的循环。i ++ ,判断数组A的下一个位置 的值是否是 数组B没有的。
若数组B遍历完了 都没有找到和数组A对应 i 号位匹配的值,则可以把改数值 传给输出数组C。
步骤1内部的步骤3: 在传给输出数组C之前还要判断数组C内部是否已经有和当比较得到的 非共同元素 相等的值,若已经存在,就跳过这次的存储。 第三层遍历数组C的判重循环
步骤2:和步骤1逻辑上完全相同,只是这里是在在数组B中按序取一个值,依次和数组B的第一个到最后一个比较这里就不赘述了。
步骤2内部的步骤3 :同上,略了
步骤4:执行完上述任务,就得到了一个没有重复数据的数组C,然后就是按照行末不得有多余的空格的方式输出结果,顺序遍历循环输出结果即可
三重循环,你说新手怎么受得了!!! 难怪我debug 搞到怀疑人生!
接下来是代码实现:版本1是我为了 debug 可视化每一个步骤的注释代码。共计100多行......
#include
int main(){
int na ,nb,a[20],b[20],dif[40],s;
int i,j,k=0;
//任务1:输入两个数组的输入与初始化
scanf("%d",&na);
for (int i = 0; i < na; i++) { //i语句内的循环变量,离开语句就失效
scanf("%d",&a[i]);
printf("a[%d]=%d ",i,a[i]); //debug语句
}
printf("\n");
printf("上面输出的是数组a\n");
printf("\n"); //debug语句
scanf("%d",&nb);
for(int j=0; j < nb ;j++){//j语句内的循环变量
scanf("%d",&b[j]);
printf("b[%d]=%d ",j,b[j]); //debug语句
}
printf("\n");
printf("上面输出的是数组b\n");
printf("\n"); //debug语句
printf("现在开始在数组a中取一个数,循环遍历数组b,看是否重复\n"); //debug语句
//任务2
for(i=0 ; i0){
for( s=0;s0){
for(s=0;s
以下是上述 代码的可视化执行结构 便于debug! 部分打印语句的变量没有赋值上去,眼花了,但是关键信息点都是对的!
10 3 -5 2 8 0 3 5 -15 9 100
a[0]=3 a[1]=-5 a[2]=2 a[3]=8 a[4]=0 a[5]=3 a[6]=5 a[7]=-15 a[8]=9 a[9]=100
上面输出的是数组a
11 6 4 8 2 6 -5 9 0 100 8 1
b[0]=6 b[1]=4 b[2]=8 b[3]=2 b[4]=6 b[5]=-5 b[6]=9 b[7]=0 b[8]=100 b[9]=8 b[10]=1
上面输出的是数组b
现在开始在数组a中取一个数,循环遍历数组b,看是否重复
此时a[0]=3 b[0]=6
此时a[0]=3 b[1]=4
此时a[0]=3 b[2]=8
此时a[0]=3 b[3]=2
此时a[0]=3 b[4]=6
此时a[0]=3 b[5]=-5
此时a[0]=3 b[6]=9
此时a[0]=3 b[7]=0
此时a[0]=3 b[8]=100
此时a[0]=3 b[9]=8
此时a[0]=3 b[10]=1
j循环正常跳出:即j==nb,说明b[] 中无与a[i]相同的元素,可以准备把a[i]存入数组dif【】
若k<0,执行此句:此时【dif[0]=3】
此时a[1]=-5 b[0]=6
此时a[1]=-5 b[1]=4
此时a[1]=-5 b[2]=8
此时a[1]=-5 b[3]=2
此时a[1]=-5 b[4]=6
此时a[1]=-5 b[5]=-5
b[5] == a[1]相等,跳出循环
此时a[2]=2 b[0]=6
此时a[2]=2 b[1]=4
此时a[2]=2 b[2]=8
此时a[2]=2 b[3]=2
b[3] == a[2]相等,跳出循环
此时a[3]=8 b[0]=6
此时a[3]=8 b[1]=4
此时a[3]=8 b[2]=8
b[2] == a[3]相等,跳出循环
此时a[4]=0 b[0]=6
此时a[4]=0 b[1]=4
此时a[4]=0 b[2]=8
此时a[4]=0 b[3]=2
此时a[4]=0 b[4]=6
此时a[4]=0 b[5]=-5
此时a[4]=0 b[6]=9
此时a[4]=0 b[7]=0
b[7] == a[4]相等,跳出循环
此时a[5]=3 b[0]=6
此时a[5]=3 b[1]=4
此时a[5]=3 b[2]=8
此时a[5]=3 b[3]=2
此时a[5]=3 b[4]=6
此时a[5]=3 b[5]=-5
此时a[5]=3 b[6]=9
此时a[5]=3 b[7]=0
此时a[5]=3 b[8]=100
此时a[5]=3 b[9]=8
此时a[5]=3 b[10]=1
j循环正常跳出:即j==nb,说明b[] 中无与a[i]相同的元素,可以准备把a[i]存入数组dif【】
判重循环:此时a[5]=3 【dif[0]=3】
新的数和dif数组的数有重复跳出循环,找下一个
此时a[6]=5 b[0]=6
此时a[6]=5 b[1]=4
此时a[6]=5 b[2]=8
此时a[6]=5 b[3]=2
此时a[6]=5 b[4]=6
此时a[6]=5 b[5]=-5
此时a[6]=5 b[6]=9
此时a[6]=5 b[7]=0
此时a[6]=5 b[8]=100
此时a[6]=5 b[9]=8
此时a[6]=5 b[10]=1
j循环正常跳出:即j==nb,说明b[] 中无与a[i]相同的元素,可以准备把a[i]存入数组dif【】
判重循环:此时a[6]=5 【dif[0]=3】
找到新的数了且可以赋值进dif数组
满足条件的a[6]赋值后的【dif[1]=5】
此时a[7]=-15 b[0]=6
此时a[7]=-15 b[1]=4
此时a[7]=-15 b[2]=8
此时a[7]=-15 b[3]=2
此时a[7]=-15 b[4]=6
此时a[7]=-15 b[5]=-5
此时a[7]=-15 b[6]=9
此时a[7]=-15 b[7]=0
此时a[7]=-15 b[8]=100
此时a[7]=-15 b[9]=8
此时a[7]=-15 b[10]=1
j循环正常跳出:即j==nb,说明b[] 中无与a[i]相同的元素,可以准备把a[i]存入数组dif【】
判重循环:此时a[7]=-15 【dif[0]=3】
判重循环:此时a[7]=-15 【dif[1]=5】
找到新的数了且可以赋值进dif数组
满足条件的a[7]赋值后的【dif[2]=-15】
此时a[8]=9 b[0]=6
此时a[8]=9 b[1]=4
此时a[8]=9 b[2]=8
此时a[8]=9 b[3]=2
此时a[8]=9 b[4]=6
此时a[8]=9 b[5]=-5
此时a[8]=9 b[6]=9
b[6] == a[8]相等,跳出循环
此时a[9]=100 b[0]=6
此时a[9]=100 b[1]=4
此时a[9]=100 b[2]=8
此时a[9]=100 b[3]=2
此时a[9]=100 b[4]=6
此时a[9]=100 b[5]=-5
此时a[9]=100 b[6]=9
此时a[9]=100 b[7]=0
此时a[9]=100 b[8]=100
b[8] == a[9]相等,跳出循环
现在开始在数组b中取一个数,循环遍历a,看是否重复
此时b[0]=6 a[0]=3
此时b[0]=6 a[1]=-5
此时b[0]=6 a[2]=2
此时b[0]=6 a[3]=8
此时b[0]=6 a[4]=0
此时b[0]=6 a[5]=3
此时b[0]=6 a[6]=5
此时b[0]=6 a[7]=-15
此时b[0]=6 a[8]=9
此时b[0]=6 a[9]=100
判重循环:此时b[0]=6 【dif[0]=3】
判重循环:此时b[0]=6 【dif[1]=5】
判重循环:此时b[0]=6 【dif[2]=-15】
找到新的数了且可以赋值进dif数组
满足条件的b[0]赋值后的【dif[3]=6】
此时b[1]=4 a[0]=3
此时b[1]=4 a[1]=-5
此时b[1]=4 a[2]=2
此时b[1]=4 a[3]=8
此时b[1]=4 a[4]=0
此时b[1]=4 a[5]=3
此时b[1]=4 a[6]=5
此时b[1]=4 a[7]=-15
此时b[1]=4 a[8]=9
此时b[1]=4 a[9]=100
判重循环:此时b[1]=4 【dif[0]=3】
判重循环:此时b[1]=4 【dif[1]=5】
判重循环:此时b[1]=4 【dif[2]=-15】
判重循环:此时b[1]=4 【dif[3]=6】
找到新的数了且可以赋值进dif数组
满足条件的b[1]赋值后的【dif[4]=4】
此时b[2]=8 a[0]=3
此时b[2]=8 a[1]=-5
此时b[2]=8 a[2]=2
此时b[2]=8 a[3]=8
b[2] == a[3]相等,跳出循环
此时b[3]=2 a[0]=3
此时b[3]=2 a[1]=-5
此时b[3]=2 a[2]=2
b[3] == a[2]相等,跳出循环
此时b[4]=6 a[0]=3
此时b[4]=6 a[1]=-5
此时b[4]=6 a[2]=2
此时b[4]=6 a[3]=8
此时b[4]=6 a[4]=0
此时b[4]=6 a[5]=3
此时b[4]=6 a[6]=5
此时b[4]=6 a[7]=-15
此时b[4]=6 a[8]=9
此时b[4]=6 a[9]=100
判重循环:此时b[4]=6 【dif[0]=3】
判重循环:此时b[4]=6 【dif[1]=5】
判重循环:此时b[4]=6 【dif[2]=-15】
判重循环:此时b[4]=6 【dif[3]=6】
新的数和dif数组的数有重复跳出循环,找下一个
此时b[5]=-5 a[0]=3
此时b[5]=-5 a[1]=-5
b[5] == a[1]相等,跳出循环
此时b[6]=9 a[0]=3
此时b[6]=9 a[1]=-5
此时b[6]=9 a[2]=2
此时b[6]=9 a[3]=8
此时b[6]=9 a[4]=0
此时b[6]=9 a[5]=3
此时b[6]=9 a[6]=5
此时b[6]=9 a[7]=-15
此时b[6]=9 a[8]=9
b[6] == a[8]相等,跳出循环
此时b[7]=0 a[0]=3
此时b[7]=0 a[1]=-5
此时b[7]=0 a[2]=2
此时b[7]=0 a[3]=8
此时b[7]=0 a[4]=0
b[7] == a[4]相等,跳出循环
此时b[8]=100 a[0]=3
此时b[8]=100 a[1]=-5
此时b[8]=100 a[2]=2
此时b[8]=100 a[3]=8
此时b[8]=100 a[4]=0
此时b[8]=100 a[5]=3
此时b[8]=100 a[6]=5
此时b[8]=100 a[7]=-15
此时b[8]=100 a[8]=9
此时b[8]=100 a[9]=100
b[8] == a[9]相等,跳出循环
此时b[9]=8 a[0]=3
此时b[9]=8 a[1]=-5
此时b[9]=8 a[2]=2
此时b[9]=8 a[3]=8
b[9] == a[3]相等,跳出循环
此时b[10]=1 a[0]=3
此时b[10]=1 a[1]=-5
此时b[10]=1 a[2]=2
此时b[10]=1 a[3]=8
此时b[10]=1 a[4]=0
此时b[10]=1 a[5]=3
此时b[10]=1 a[6]=5
此时b[10]=1 a[7]=-15
此时b[10]=1 a[8]=9
此时b[10]=1 a[9]=100
判重循环:此时b[10]=1 【dif[0]=3】
判重循环:此时b[10]=1 【dif[1]=5】
判重循环:此时b[10]=1 【dif[2]=-15】
判重循环:此时b[10]=1 【dif[3]=6】
判重循环:此时b[10]=1 【dif[4]=4】
找到新的数了且可以赋值进dif数组
满足条件的b[10]赋值后的【dif[5]=1】
3 5 -15 6 4 1
--------------------------------
Process exited after 16.27 seconds with return value 0
请按任意键继续. . .
当我的代码照完Bug以后可以正常运行的时候,在线测试一次性通过的感觉,真是太棒了,太有成就感了!太好哭了!,这就是编程的 快乐吧!
纯净版!可提交作业(看上去括号好多,很拉胯,其实是有原因的!)
#include
int main(){
int na ,nb,a[20],b[20],dif[40],s;
int i,j,k=0;
//任务1:输入两个数组的输入与初始化
scanf("%d",&na);
for (int i = 0; i < na; i++) { //i语句内的循环变量,离开语句就失效
scanf("%d",&a[i]);
}
scanf("%d",&nb);
for(int j=0; j < nb ;j++){//j语句内的循环变量
scanf("%d",&b[j]);
}
//任务2
for(i=0 ; i0){
for( s=0;s0){
for(s=0;s
结果:
10 3 -5 2 8 0 3 5 -15 9 100
11 6 4 8 2 6 -5 9 0 100 8 1
3 5 -15 6 4 1
--------------------------------
Process exited after 6.208 seconds with return value 0
请按任意键继续. . .
经验教训1:不要以为for语句后面只有一句就可以不打括号了,后期你修复bug的时候就知道麻烦了!,语句控制条件会乱飞!debug都找不到逻辑!,所以以后for语句除非结构很简单,可以一次作对,不然还是老老实实的每种复合语句都补上括号把。
经验教训2:本题有两段代码的逻辑完全一样,然后我就复制了上一段代码,想着直接该一下对应的变量就可以了,本想偷懒,实则在自找麻烦!
因为①你无法保证第一段代码的完全正确性,②该变量一旦有 遗漏 ,找bug 找个把小时都找不到!
经验教训3:复杂代码最好分结构,分功能验证好了再组合在一起。保证前面的代码都正确以后在来找后面的bug 才更加轻松,不然就是一杯茶,一包烟,一个bug找一天
经验教训4:循环遍历数组的时候,要非常注意循环控制条件,非常容易出现数组循环超界问题。
收获:
新学会了一种的代码的新写法
k=0;
等价:dif[k++] = a[i] //一步到位实现了 k++ 先dif[k] 再k++
等价:dif[k] = a[i] ;k++
巩固了数组的循环输入代码格式
for (int i = 0; i < na; i++) {
scanf("%d",&a[i]);
}
创新性的独立实现了复杂的三重循环嵌套和复杂分支逻辑条件的实现
//数组A
for(i=0 ; i0){
for( s=0;s
#include
int main(){
int na ,nb,a[20],b[20],dif[40],s;
int i,j,k=0;
scanf("%d",&na);
for (int i = 0; i < na; i++) {
scanf("%d",&a[i]);
}
scanf("%d",&nb);
for(int j=0; j < nb ;j++){
scanf("%d",&b[j]);
}
//数组A
for(i=0 ; i0){
for( s=0;s0){
for(s=0;s
#include
int main(){
int na,nb,a[20],b[20],dif[40],s;
int i,j,k=0;
//na 数组A的输入长度参数
//nb 数组B的输入长度参数
//a[20] 数组A的定义长度
//b[20] 数组B的定义长度
//dif[40] 两数组不同的最大输出数组C的初始化
// s 是输出数组dif[40]的循环控制变量
//i,j 分别对应二重循环的循环控制变量
//k表示输出数组当前最大有效数据的下标
scanf("%d",&na);//数组A的初始化循环
for (int i = 0; i < na; i++) { //注意此处的int i 是for语句的内部循环变量
scanf("%d",&a[i]);
}
scanf("%d",&nb);//数组B的初始化循环
for(int j=0; j < nb ;j++){ //注意此处的int j 是for语句的内部循环变量
scanf("%d",&b[j]); //这两个变量可以是任意字母出循环就失效
}
//数组A 在数组A中按序取一个值 依次和数组B的第一个到最后一个比较
for(i=0 ; i0){ //若输出数组中有数据则进行比较 判重
for( s=0;s0){
for(s=0;s
如果我呕心沥血花了一整天时间写的这篇帖子,能够帮助到更多可爱又聪明的小可爱们,我会更开心的,求点赞
以便更多人发现,从而解决彻底他们对这道题的疑惑!