任务描述
本关任务:利用分治法求一组数据中最大的两个数和最小的两个数。
编程要求
请在右侧编辑器
Begin-End
处补充代码,完成本关任务。
测试说明
平台会对你编写的代码进行测试,比对你输出的数值与实际正确数值,只有所有数据全部计算正确才能通过测试:
测试输入:
10 //数据的总个数
1 //此行及以下为具体的每个数据
3
5
7
9
10
8
6
4
2
预期输出:
max1=10 max2=9
min1=1 min2=2
接下来我讲一下思路!
首先读题分治求解最大两个数和最小的树,那么思索之后,其实先排序是最好的
分治算法中有两种排序方法:
快速排序法
合并排序法
那么我先暂时用快速排序来解。(对于代码讲解比较细腻一些)
下面文字叙述(不够形象可以看一下b站)
快速排序:
其实就是找一个值p作为基准(也就是比较的对象),然后通常用最左侧的值作为p值,
将左侧的值和右侧的值与p进行比较,
左>p,那么左就要放到右边。否则左边的指针向右移动。
右<p,那么右就要放到左边。否则右边的指针向左移动。
那么当左指向与右指向相同的时候,将p放在此处。
此时我们已经利用p分开了左右:
左边一定是比p小的,右边一定是比p大的。
那么接下来递归调用此函数,左半部分依旧按照上述步骤,右半部分也是按照上述步骤即可。
下面就看一下代码部分,详细标注在代码注释中
#include <stdio.h>
void quick_sort(int arr[], int l, int r); // 函数声明
int main()
{
int num,i;
scanf("%d",&num);
int a[num];
for(i=0;i<num;i++)
scanf("%d",&a[i]);
/********** Begin **********/
quick_sort(a,0,num-1); #调用函数,数组直接a表示,左侧0,右侧num-1
printf("max1=%d max2=%d\n",a[num-1],a[num-2]); #最大则是右边两个
printf("min1=%d min2=%d",a[0],a[1]); #最小左侧两个
/********** End **********/
}
void quick_sort(int arr[],int l,int r){ #写代码思路和书写顺序不大相同
if(l>=r) return; #因为下面要递归调用,这里作为判断左边的数大于等于r就结束
int left=l,right=r; #left和right作为指针,会发生变动,保留l和r的值。
int p=arr[l]; #将左侧给p
while(left<right){ #循环直到不符合结束
while(left<right && arr[right]>=p) --right; #右侧的值大于p,指针左移一位,同时减 # #到与左指针相同的位置时结束
if(arr[right]<p) arr[left] = arr[right]; #右侧值小于p,移动至左侧位置
while(left<right && arr[left]<=p) ++left; #同上
if(arr[left]>p) arr[right] = arr[left];
if(arr[left]>=arr[right]) arr[left]=p; #指针指向统一位置,赋值给p
} #此时完成一部分
quick_sort(arr,l,right-1); #调用左侧,用到初始值l
quick_sort(arr,right+1,r); #调用右侧,用到初始值r
}
1、为什么if(l>=r)
因为当进行到最后一个的时候,不只是l在减1,r也在加,不一定会相等
2、最外层一个while有必要吗?
问出这个问题,你可能还没理清楚,代码思路,或者出现了盲点。
他不是只停了一次,换了位置结束了就,而是多次比较多次换位。