以下程序使用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;
}
答案 0 :(得分:2)
使用else来最小化比较。如果你找到一个新的最大值,那么它不能是最小值(或者如果你想要的话,反之亦然):
if (ptr[lower] > *maximum) {
*maximum = ptr[lower];
} else {
if (ptr[lower] < *min) {
*min = ptr[lower];
}
为此,您需要将min和max初始化为数组中的任何值:
minimum = maximum = ptr[0];
请注意,在您的情况下,递归模式是绝对无用的,对数组进行简单的增量解析就足够了,可以节省大量的操作(计算中间,测试基本情况,传递参数,函数)调用)。另一种方法是在扫描输入时计算结果......
答案 1 :(得分:2)
是否可以最大限度地减少查找所需的比较次数 最小值和最大值?
简答:否
您的代码实际需要
n * 4 - 1
比较,其中n
是数组中的项目数。
以上计算1比较以检查lower==upper
,如果它评估了真正的2个比较以检查max
和min
如果您只是使用for循环从开头到结尾解析数组,那么
n * 2
比较
但是等一下:因为你还需要在每次迭代时都有一个for循环,还有一个额外的比较来检查循环是否结束。
所以实际上有
n * 3
比较
您发布的代码效率不高,此外,您必须在每次调用mid
时计算max()
以及递归函数调用的开销。
由于你有一个无序的数组或数字,你必须找到最小和最大的解决方案(正如其他人指出的那样)迭代数组。
如果你想要一个证明,你可以测试它......
这是输出:
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;
}
答案 2 :(得分:0)
我想指出两件事 1.如果数组已排序,则查找最小值和最大值需要O(1)时间。 2.如果数组不是按排序顺序排列,那么如果您的目标只是找到最小和最大数字,那么排序对您没有帮助。原因如下:任何基于比较的排序算法都需要Ω(nlogn)时间,而最大值和最小值可以在单个for循环迭代中一起找到。每次比较下一个元素到目前为止发现的最大值和最小值。所以只使用一个for循环。这很简单
如果你的作业强制你以递归方式进行,那么它仍然可以在O(n)比较中完成。简单而不是编写for循环使用recurssion函数,在循环中编写的代码稍作修改。