[英]Finding maximum and minimum of an array in a single recursive function
下面的程序使用Divide and Conquer范例,并使用Merge Sort的思想递归地查找数组的最大和最小元素。 这是一个要求递归执行的任务,我编写了解决方案,但我的问题是它是否最小化了查找最小值和最大值所需的比较次数?
#include <stdio.h>
#include <limits.h>
void max(int *ptr, int lower, int upper, int *maximum, int *min)
{
//returns the maximum element of the array
int mid;
int left, right;
if(lower == upper){
if(ptr[lower] > *maximum)
{
*maximum = ptr[lower];
}
if(ptr[lower] < *min)
{
*min = ptr[lower];
}
return;
}
mid = (lower+upper) /2;
max(ptr, lower, mid, maximum, min);
max(ptr, mid+1, upper, maximum, min);
}
int main()
{
int n;
int i;
int *ptr;
int maximum=-1;
int minimum=INT_MAX;
printf("\nEnter the size of the array : ");
scanf("%d", &n);
ptr = (int *) malloc(sizeof(int)*n);
printf("Enter the contents of the array : ");
for(i=0 ; i<n; i++)
scanf("%d", &ptr[i]);
max(ptr,0,n-1,&maximum,&minimum);
printf("\n Maximum element is : %d", maximum);
printf("\n Minimum element is : %d", minimum);
free(ptr);
return 0;
}
使用else来最小化比较。 如果你找到一个新的最大值,那么它不能是最小值(如果你想要的话,反之亦然):
if (ptr[lower] > *maximum) {
*maximum = ptr[lower];
} else {
if (ptr[lower] < *min) {
*min = ptr[lower];
}
为此,您需要将min和max初始化为数组中的任何值:
minimum = maximum = ptr[0];
请注意,在您的情况下,递归模式是绝对无用的,对数组的简单增量解析就足够了,并且可以节省大量操作(计算中间值,测试基本情况,传递参数,函数调用)。 另一种方法是在扫描输入时计算结果......
它是否最大限度地减少了查找最小值和最大值所需的比较次数?
简答:不
您的代码实际上需要
n * 4 - 1
比较,其中n
是数组中的项数。
上面的计数1比较检查lower==upper
,如果它评估真正的2更多比较,以检查max
和min
如果您只需要使用for循环从头到尾解析数组
n * 2
比较。
但是等等:因为在每次迭代时你还需要一个for循环,所以还有一个额外的比较来检查循环是否结束。
实际上有
n * 3
比较。
您发布的代码效率不高,而且您必须在每次调用max()
计算mid
,再加上递归函数调用的开销。
由于你有一个无序的数组或数字,你必须找到最小和最大的最快解决方案(正如其他人指出)迭代数组。
如果你想要一个证明你可以测试它...
这是输出:
Elements count : 10000
Maximum element is : 99964
Minimum element is : 9
Number of comparisons : 39999
下面是嵌入测试的代码
(我刚刚添加了一个全局g_comparisons
,它在每次比较之前都会增加 - 也是使用随机值以编程方式完成数组填充的过程)
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int g_comparisons = 0;
void max(int *ptr, int lower, int upper, int *maximum, int *min)
{
//returns the maximum element of the array
int mid;
g_comparisons ++;
if(lower == upper){
g_comparisons += 2;
if(ptr[lower] > *maximum)
{
*maximum = ptr[lower];
}
if(ptr[lower] < *min)
{
*min = ptr[lower];
}
return;
}
mid = (lower+upper) /2;
max(ptr, lower, mid, maximum, min);
max(ptr, mid+1, upper, maximum, min);
}
int main()
{
int n;
int i;
int *ptr;
int maximum=-1;
int minimum=INT_MAX;
//printf("\nEnter the size of the array : ");
//scanf("%d", &n);
n = 10000;
ptr = (int *) malloc(sizeof(int)*n);
// printf("Enter the contents of the array : ");
for(i=0 ; i<n; i++)
{
// scanf("%d", &ptr[i]);
ptr[i] = rand()%100000;
}
max(ptr,0,n-1,&maximum,&minimum);
printf("\n Elements count : %d" , n);
printf("\n Maximum element is : %d", maximum);
printf("\n Minimum element is : %d", minimum);
printf("\n Number of comparisons : %d\n", g_comparisons);
free(ptr);
return 0;
}
有两件事我想指出1.如果数组已排序,则查找最小值和最大值需要O(1)时间。 2.如果数组不是按排序顺序排列,那么如果您的目标只是找到最小和最大数字,那么排序对您没有帮助。 原因如下:任何基于比较的排序算法都需要Ω(nlogn)时间,而最大值和最小值可以在单个for循环迭代中一起找到。 每次比较下一个元素到目前为止发现的最大值和最小值。 所以只使用一个for循环。 这很简单
如果你的任务强制你以递归方式执行,那么它仍然可以在O(n)比较中完成。 只需代替编写for循环,就可以在循环中编写的代码中稍作修改使用recurssion函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.