当前位置: 首页 > 知识库问答 >
问题:

求数组中的最小值和最大值

和弘博
2023-03-14

这是一个非常基本的算法(不能再简单了),但我被难住了。我们有一个元素数组,我们必须确定最小值和最大值。

通常的方法是遍历数组,找出最小值和最大值,即2n比较。

稍微有效的方法是首先对数组的连续元素进行比较,以确定任意两个元素的最大值和最小值(N/2比较)。我们现在有n/2 min和n/2 max元素。现在我们可以在n/2+n/2+n/2(前一步)=3/2*n或1.5n中得到最终的max和min

那很好。从理论上讲,在第二种情况下,代码应该花费更少的时间来运行,因为我们做的比较更少。但是当我运行代码时,结果却不是这样。

public class MinMax {
public static void nonEfficient(int [] array){
    int min=array[0],max=array[0];
    for (int anArray : array) {
        if (anArray < min)
            min = anArray;
        else {
            if (anArray > max)
                max = anArray;
        }
    }
    System.out.println("Max is :" + max);
    System.out.println("Min is :" + min);
}
public static void efficient(int [] arr,int length){
    int max,min;
    max = min = arr[0];
    int i = 0;
    for (; i < length / 2; i++)
    {
        int number1 = arr[i * 2];
        int number2 = arr[i * 2 + 1];
        if (arr[i * 2] >= arr[i * 2 + 1])
        {
            if (number1 > max)
                max = number1;
            if (number2 < min)
                min = number2;
        }
        else
        {
            if (number2 > max)
                max = number2;
            if (number1 < min)
                min = number1;
        }
    }
    if (i * 2 < length)
    {
        int num = arr[i * 2];
        if (num > max)
            max = num;
        if (num < min)
            min = num;
    }
    System.out.println("***********************");
    System.out.println("Max is :" + max);
    System.out.println("Min is :" + min);
}
public static void main(String[] args) {
    int [] array =  new int[10000000];
    Random rand = new Random();
    for(int i=0;i<array.length;i++)
        array[i] = rand.nextInt(100000)-144;
    long startTime = System.currentTimeMillis();
    nonEfficient(array); //theoretically non efficient 2n compares
    long stopTime = System.currentTimeMillis();
    long elapsedTime = stopTime - startTime;
    System.out.println(elapsedTime);// just 11ms

    startTime = System.currentTimeMillis();
    efficient(array, 10000000);///theoretically more efficient 1.5n compares
    stopTime = System.currentTimeMillis();
    elapsedTime = stopTime - startTime;
    System.out.println(elapsedTime);//whooping 37 ms..what happpened ????
}
}

共有1个答案

祁飞飙
2023-03-14

首先:基准是完全有缺陷的。您测量的时间跨度太短,没有JIT预热,您在测量中包括了system.out.println的时间。通过应用“通常的”微基准测试模式,可以使其更有意义(请参见本答案的结尾部分)

但即使有了这个“基准”,也存在显著差异。原因有很多:

我们可以假设,在现代CPU上的一次比较需要(摊销)一个CPU周期。一个CPU周期是一束光传播10厘米所需的时间。现在,测量一下;-)基本上,算法中的每一个其他操作都将花费至少相同的时间,或者更长的时间:每一个i++都将花费相同的时间,每一个min=x都将花费相同的时间或者更长的时间,每一个i*2都很可能花费更长的时间...

另外,我认为这里最重要的一点是:CPU速度快,但内存慢。在(not)“not entificial”的情况下,您将顺序运行数组。这非常适合缓存。每次读取一个缓存行都将被充分利用。与此相反,在(不是)“高效”的情况下,内存访问基本上分散在整个数组中。它将不得不从主存中读取数据块到高速缓存中,其中大部分数据将不得不被丢弃,因为它不会立即被使用,而是在下一次传递中再次被读取。

关于基准测试:可以通过多次重复相应的方法,并占用平均时间,在增加数组大小的情况下重复这样做,从而使其更有意义-大致如下所示:

public static void main(String[] args)
{
    Random rand = new Random();
    long beforeNS = 0;
    long afterNS = 0;
    int results[] = { 0, 0 };
    int runs = 100;
    for (int size=10000; size<=10000000; size*=2)
    {
        int[] array = new int[size];
        for (int i = 0; i < array.length; i++)
            array[i] = rand.nextInt(size) - 144;

        beforeNS = System.nanoTime();
        for (int i=0; i<runs; i++)
        {
            nonEfficient(array, results);
        }
        afterNS = System.nanoTime();
        System.out.println(
            "Not efficient, size "+size+
            " duration "+(afterNS-beforeNS)/1e6+
            ", results "+Arrays.toString(results));

        beforeNS = System.nanoTime();
        for (int i=0; i<runs; i++)
        {
            efficient(array, array.length, results);
        }
        afterNS = System.nanoTime();
        System.out.println(
            "Efficient    , size "+size+
            " duration "+(afterNS-beforeNS)/1e6+
            ", results "+Arrays.toString(results));
    }
}

尽管如此,结果可能会受到质疑,只要VM选项不知道等等,但它至少给出了两种方法之间是否有“显著”差异的稍微可靠的指示。

 类似资料:
  • 我想从数组的一部分找到最大值和最小值。我知道我可以通过复制数组将所需的数组部分复制到另一个数组中,但只是想知道是否可以不复制数组,因为我必须为不同的子数组进行循环 例如: 现在我想从1到4找到子数组的最小/最大值(如果可能,不复制子数组)

  • 问题内容: 我的代码没有给出错误,但是没有显示最小值和最大值。代码是: 我是否需要system.out.println()来显示它,否则返回应该起作用吗? 问题答案: 您正在调用方法,但不使用返回的值。

  • 本节通过求数组的最大和最小值来提高初学者对数组的一些基本应用。 程序运行结果如下: 最高成绩:100 最低成绩:67 将变量 min 与 max 初值设成数组的第 1 个元素后,再逐一与数组中的各元素相比。比 min 小,就将该元索的值指定给 min 存放,使 min 的内容保持最小。同样,当该元素比 max 大时,就将该元素的值指定给 max 存放,使 max 的内容保持最大。for 循环执行完

  • 主要内容:普通算法,分治算法程序中,我们经常使用数组(列表)存储给定的线性序列(例如 {1,2,3,4}),那么如何查找数组(序列)中的最大值或者最小值呢? 查找数组(序列)中最大值或最小值的算法有很多,接下来我们以 {3,7,2,1} 序列为例讲解两种查找最值的算法,一种是普通算法,另一种是借助 分治算法解决。 普通算法 普通算法的解决思路是:创建两个变量 max 和 min 分别记录数组中的最大值和最小值,它们的初始值都

  • 那么我如何使用这个pair类和我的方法来找到最小值和最大值。

  • 问题内容: 我想输出二维数组的最大值和最小值。Max可以很好地工作,但是即使在数组中没有零的情况下min也总是输出零。在本例中,我设置为99以防止较小的机会在数组中获得零。继承人完整代码: 问题答案: 由于您在中选择随机值的方式,不会存在小于零的值- 但也无法保证任何值都将恰好为零。但是,您将初始化为零,因为这是数组元素的默认值;没有什么比这更小了,所以答案总是零。 您应该在标记为“查找最小值”的