目录
一.有序序列的合并
思路
1.先创建两个数组,分别存放两个有序序列。
实际上,根据题目要求,我们只需要得到两个有序序列合并后的结果,并不需要将两个有序序列数组整合到第三个有序序列数组中。
2.因为是两个正序有序序列数组,要比较它们的大小,将小的先打印出来,大的和另一个数组的下一位数进行比较。
通过下标对数组上的元素进行访问,当这个数组中的这个下标对应的元素打印完成,
下标++。
这样一个操作就构成一个循环,循环的条件设置为 下标 不大于(各自含有的元素个数-1)
当出循环时,再用if语句判断哪个有序序列没有打印完,将其剩下的数按序打印输出即可
3.为什么不用冒泡排序? 因为这需要将两个数组合并为一个数组,再进行冒泡排序。首先多创建一个数组,空间利用效率低了。其次使用冒泡排序会遍历多次数组,时间利用效率也低。
小tips:
这里题目说在输入的时候用空格分隔,而在实际的输入中,用scanf函数进行输入,其实不用在打印格式中加入空格。因为只有你在实际输入时用空格隔开两个数字时,scanf才会进行分别读取。而且分行也不用额外写代码实现,当你输入完一组数据,敲下回车,会结束这组数据的读取,并且自动进入下一行。
这是在输入格式中加了空格后的,可以看到敲完回车后并没有直接出现结果。
这是输入格式不加入空格的,可以看到直接出来结果了
代码实现
#include <stdio.h>
int main()
{
int n = 0;
int m = 0;
int arr1[100] = {0};
int arr2[100] = {0};
//输入
scanf("%d %d", &n, &m);
int i = 0;
for(i=0; i<n; i++)
{
scanf("%d", &arr1[i]);
}
for(i=0; i<m; i++)
{
scanf("%d", &arr2[i]);
}
//处理
int j = 0;
i = 0;
while(i<n && j<m)
{
if(arr1[i] < arr2[j])
{
printf("%d ", arr1[i]);
i++;
}
else
{
printf("%d ", arr2[j]);
j++;
}
}
if(i == n)
{
for(; j<m; j++)
{
printf("%d ", arr2[j]);
}
}
else
{
for(; i<n; i++)
{
printf("%d ", arr1[i]);
}
}
return 0;
}
二.有序序列的判断
思路1
难点在于有序序列的判断有三种情况,一是正序,二是逆序,三是全为一个数。
我们进行拆分,将两个数的比较看成一个最小单元,并将这个比较的结果进行累加计算。
假如这是5个数的序列,则要进行4次比较,按顺序从左到右,两两依次比较,当比较结果是四个> 或四个< 或四个== 时,则这个5个数的序列为有序,否则为无序
我们再创建两个计数器count1 和count2 分别计算> 和 < 的数量。为了区分,当有一个>时,count1++, 当有一个< 时 ,count2-- ,当比较结果为全==时,count1和count2都为0.这时也体现出设置两个计数器的必要性。因为如果只设置一个计数器count,恰好有相等数量的> 和<时,count也为0,这时若判断为有序序列就是错误判断了。
代码实现
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int i = 0;
int arr[100] = { 0 };
int count1 = 0;
int count2 = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
for (i = 0; i < n-1; i++) //循环到n-1 防止越界
{
if (arr[i] < arr[i + 1])
count1++;
else if (arr[i] > arr[i + 1])
count2--;
}
if (count1 == n-1 || count2 == 1-n || count1 == 0)
printf("sorted\n");
else
printf("unsorted\n");
return 0;
}
这里还要注意一点,因为比较中用到 i+1 和 i 这两个数组下标进行访问,所以相比于平常的遍历数组的循环设置,还要再-1
思路2
在输入数组的同时进行判断
设置两个标志flag1 和flag2.将其初始化为0
当遍历数组,两两依次比较大小,结果为> 将flag1赋值为1
结果为< 将flag2 赋值为1
结果为全== flag1 和flag2 不变。
由此flag1 + flag2 的和<=1 时,为有序。因为当序列中既有> 又有<时,两个flag都被赋值1,和为2。
代码实现
#include <stdio.h>
int main()
{
int n = 0;
int arr[50] = {0};
scanf("%d", &n); //这个数组有几个元素
int i = 0;
int flag1 = 0;
int flag2 = 0;
for(i=0; i<n; i++)
{
scanf("%d", &arr[i]);
if(i>0)
{
if(arr[i]>arr[i-1])
flag1 = 1;
else if(arr[i]<arr[i-1])
flag2 = 1;
}
}
//flag1 和 flag2 都为1是乱序的
if(flag1+flag2 > 1)
printf("unsorted\n");
else
printf("sorted\n");
return 0;
}
对比两种思路
思路1的思维方式是将有序序列的三种情况进行分析
思路2的思维方式是反过来,优先判断是否乱序的情况,当不是乱序时,就为有序。
思路2利用了乱序判断更简便的特点进行代码编写。因为只要判断的情况只有一种,那就是在序列中的数的对比结果中,同时出现> 和 < 的时候就为无序。
思路1和思路2的缺陷
思路1会将3 4 4 4 4这种情况判断为无序
原因是在count的设置上,它判断无序的标准是计数器count的值不满足全大于或全小于或全等于的情况,所以认为3 4 4 4 4这种既包含> (或<) 又包含重复的数字的序列是无序的。
当输入的数像 3 4 4 4 4时,思路2的代码会判断为sorted
原因是在设置标志flag上。这里判断无序的思路是当数组中的比较结果既有>又有<时,两个flag和>1 。
所以思路2是认为3 4 4 4 4这种包含重复数字的序列依旧为有序序列的,因为它仍然满足从小到大排列。
具体用哪种方法,就要看具体的实际需求了。这两块代码在牛客网上都是可以通过的。但这不妨碍我们可以学习思路2的这种思维方式,去思考其他类似的问题。那就是当判断一个情况是对的比较复杂时,可以优先考虑判断这个情况是错的。