递归地查找数组中的最小值和最大值

Recursively find min and max value in array

本文关键字:最小值 最大值 查找 数组 递归      更新时间:2023-10-16

我做了一个递归函数,从一个可以包含任意数量元素的数组中找到最大值和最小值。这样做的主要原因是为了从Dicom图像的像素数据中找到最小最大值。我将这个递归函数作为测试代码,其中我用0-1000范围内的随机数填充int类型数组。我的代码如下。我给出了整个代码,你可以很容易地在Visual Studio中自己运行程序。

#include <stdio.h>
#include <string>
#include <iostream>
#include <math.h>
#include <time.h>
using  namespace std;
void recursMax(int* a, int size, int* maxValue)
{
    int half = size/2;
    int* newMax = new int[half];
    for(int i=0; i<half; i++)
    {
        newMax[i]=a[i]>a[size-i-1]?a[i]:a[size-i-1];
    }
    if(half>1)
    {
        recursMax(newMax, half, maxValue);
    }
    if(half == 1)
    {
        *maxValue = newMax[0];
        delete [] newMax;
    }
}
void recursMin(int* a, int size, int* minValue)
{
    int half = size/2;
    int* newMin = new int[half];
    for(int i=0; i<half; i++)
    {
        newMin[i]=a[i]<a[size-i-1]?a[i]:a[size-i-1];
    }
    if(half>1)
    {
        recursMin(newMin, half, minValue);
    }
    if(half == 1)
    {
        *minValue = newMin[0];
        delete [] newMin;
    }
}
int main ()
{
    int size = 100;
    int* a = new int[size];
    srand(time(NULL));
    for(int i=0; i<size; i++)
    {
        a[i]=rand()%1000;
        cout<<"Index : "<<i+1<<",  "<<a[i]<<endl;
    }
    cout<<endl<<endl<<"Now we look to find the max!"<<endl;
    int maxValue = 0;
    int minValue = 0;
    recursMax(a, size, &maxValue);
    cout<<maxValue<<endl;
    recursMin(a, size, &minValue);
    cout<<"Now we look for the min value!"<<endl<<minValue<<endl;
    cout<<"Checking the accuracy! First for Max value!"<<endl;
    for(int i=0; i<size; i++)
    {
        cout<<"Index : "<<i+1<<",  "<<maxValue-a[i]<<endl;
    }
    cout<<"Checking the accuracy! Now for min value!"<<endl;
    for(int i=0; i<size; i++)
    {
        cout<<"Index : "<<i+1<<",  "<<a[i]-minValue<<endl;
    }
    delete [] a;
    return 0;
}

我的问题是,你认为我的算法工作正确吗?我有点怀疑。此外,我是否正确处理或维护内存?或者在代码中会有一些内存泄漏?

您应该将delete [] newMax;从最后的if语句中取出,否则您将永远无法释放内存。这样的:

if(half == 1)
{
    *maxValue = newMax[0];
}
delete [] newMax;

对于recursMin函数也是如此。

你的算法似乎有效,但过度。使用递归和分配内存只是为了找到最小和最大不是一个好的风格。

对于最大值,我会这样做:

int ArrayMax(const int *begin, const int *end)
{
  int maxSoFar = *begin;  // Assume there's at least one item
  ++begin;
  for(const int *it = begin; it!=end; ++it)
  {
    maxSoFar = std::max(maxSoFar, *it);
  }
  return maxSoFar
}

现在你可以说:

int main ()
{
  int size = 100;
  int* a = new int[size];
  srand(time(NULL));
  for(int i=0; i<size; i++)
  {
    a[i]=rand()%1000;
    cout<<"Index : "<<i+1<<",  "<<a[i]<<endl;
  }
  int theMax = ArrayMax(a, a+size);
}

不用说,您可以将ArrayMax转换为任何类型的模板函数,并且ArrayMin可以使用相同的模式轻松实现。

我建议这个代码查找最小值,最大值是类似的:

int min = std::numeric_limits<int>::max();
for(int i = 0; i < size ; i++) min = std::min(min,a[i]);

短得多,没有内存分配,容易循环,所以编译器可能会1)向量化它以获得最大速度2)使用正确的预取以获得更高的速度

只是部分答案,因为我还没有详细验证算法,但是您最好先复制数组,然后使用该副本破坏性地存储您的值。
它可能会使用更多的内存,但可以节省运行时间和内存管理上的bug追踪时间。

如果您冒着遇到导致深度递归的退化情况的风险,您可能会使用迭代实现而不是递归实现来改进。

使用STL中的算法:

  • 从c++ 11开始,您可以使用std::minmax_element同时检索两者:https://ideone.com/rjFlZi

    const int a[] = {0, 1, 42, -1, 4};
    auto it = std::minmax_element(std::begin(a), std::end(a));
    std::cout << *it.first << " " << *it.second << std::endl;
    
  • 在c++ 03中,你可以使用std::min_elementstd::max_element

这是一个寻找最小值和最大值的糟糕算法。您可以使用更简单、更短、更快速的解决方案:

const int maxInArray( const int* beg, const int* end) {
const int* it  = std::max_element( beg, end);
    if ( it == end)
    {
        std::cout << "There is no smallest element" << std::endl;
    }
    else
    {
        std::cout << "The smallest element is " << *it << std::endl;
    }
return *it;
}

或遍历数组:

int maxInArray( const int* beg, const int* end) {
    int max;
    if ( end - beg < 1 ) return -1;
    max = *beg
    while ( beg++ != end) {
        if ( *beg > max) max = *beg;
    }
    return max;
}

不支持boost:

#include <iostream>
#include <limits>
int main() {
    int max = std::numeric_limits<int>::min();
    int min = std::numeric_limits<int>::max();
    int num;
    while ( std::cin >> num) {
            if (num > max) {
                max = num;
            }
            if (num < min) {
                min = num;
            }
    }
    std::cout << "min: " << min << std::endl;
    std::cout << "max: " << max << std::endl;
    return 0;
}

或使用boost:

#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/max.hpp>
using namespace boost::accumulators;

int main() {
    // Define an accumulator set for calculating the mean, max, and min
    accumulator_set<double, features<tag::min, tag::max> > acc;
    int num = -1;
    bool empty = true;
    while ( std::cin >> num && num >= 0) {
        empty = false;
        acc( num);
    }
    if ( ! empty) {
        // Display the results ...
        std::cout << "Min: " << min( acc) << std::endl;
        std::cout << "Max: " << max( acc) << std::endl;  
    }
    return 0;
}

基本上不建议通过递归在数组中查找max,因为它不是必需的。分治算法(递归)耗时更大。但即使你想用它,你也可以用我下面的算法。基本上,它将数组中最大的元素放在第一个位置,并且几乎具有线性运行时间。(这个算法只是一个递归的错觉!):

    int getRecursiveMax(int arr[], int size){
      if(size==1){
                  return arr[0];
      }else{
             if(arr[0]< arr[size-1]){
                                  arr[0]=arr[size-1];
                 }
             return(getRecursiveMax(arr,size-1));
        }
      }