【问题标题】:Max in array and its frequency数组中的最大值及其频率
【发布时间】:2014-09-30 22:35:57
【问题描述】:

如何编写一个函数来查找数组中的最大值以及该值在数组中出现的次数?

我们必须使用递归来解决这个问题。

到目前为止,我认为它应该是这样的:

int findMax(int[] a, int head, int last)
{
    int max = 0;

    if (head == last) {
        return a[head];
    }
    else if (a[head] < a[last]) {
        count ++;
        return findMax(a, head + 1, last);
    }
}

我不确定这是否会返回绝对最高值,而且我不确定如何更改我所拥有的

【问题讨论】:

  • 你有什么想法?您将如何使用递归来处理有关数组的这些信息?
  • 为了有效地使用递归,首先你需要建立一个基本案例,一旦整个问题得到解决,你就可以摆脱递归。其次,你必须找到能够让你从第一次调用递归函数到解决问题的规则。第三,通过递归调用函数来组合进度,直到达到第一步的基本情况。
  • 把它分成两部分。首先编写一个找到最大值的递归函数。然后添加一种方法来跟踪它发生了多少次。
  • @user3112926 提供修改。 “建立一个基本案例,一旦整个问题得到解决,你就会摆脱递归”应该更像是“建立一个基本案例,一旦子问题得到简单解决,你就会摆脱递归 ”。仅当整个问题解决后才返回,需要 N 次深度递归调用。通过在解决子问题时返回,递归深度可以小得多。

标签: c arrays algorithm


【解决方案1】:

max 的初始值设置为INT_MIN 可以解决许多问题。 @Rerito

但是 OP 使用的方法会遍历数组的每个成员,并对每个元素进行递归调用。因此,如果数组有 1000 个int,则大约有 1000 个嵌套调用。

分而治之的方法:

如果数组长度为0或1,则处理。否则从上半场和下半场找到最大答案。适当组合结果。除以 2,1000 个元素数组的堆栈深度使用不会超过 10 次嵌套调用。

注意:在任何一种方法中,调用次数都是相同的。不同之处在于最大程度的嵌套。在一个简单的for() 循环就足够的情况下使用递归是有问题的。克服更复杂的评估是递归的优势,因此采用了这种方法。


使用 O(log2(length)) 堆栈深度使用来查找最大值及其频率:

#include <stddef.h>

typedef struct {
  int value;
  size_t frequency;  // `size_t` better to use that `int` for large arrays.
} value_freq;

value_freq findMax(const int *a, size_t length) {
  value_freq vf;

  if (length <= 1) {
    if (length == 0) {
      vf.value = INT_MIN;  // Degenerate value if the array was size 0.
      vf.frequency = 0;
    } else {
      vf.value = *a;
      vf.frequency = 1;
    }
  } else {
    size_t length1sthalf = length / 2;
    vf = findMax(a, length1sthalf);
    value_freq vf1 = findMax(&a[length1sthalf], length - length1sthalf);
    if (vf1.value > vf.value)
      return vf1;
    if (vf.value == vf1.value)
      vf.frequency += vf1.frequency;
  }
  return vf;
}

【讨论】:

    【解决方案2】:

    你不是很远。

    为了保存频率和最大值,您可以保留一个指向结构的指针,然后只需将指针传递给数组的开头、要经过的长度以及指向该结构的指针。 请记住,您应该在limits.h 中使用INT_MIN 作为初始最大值(请参阅下面代码中的reset(maxfreq *)),因为int 可以携带负值。

    以下代码递归地完成这项工作:

    #include <limits.h>
    
    typedef struct {
        int max;
        int freq;
    } maxfreq;
    
    void reset(maxfreq *mfreq){
        mfreq->max = INT_MIN;
        mfreq->freq = 0;
    }
    
    void findMax(int* a, int length, maxfreq *mfreq){
    
        if(length>0){
            if(*a == mfreq->max)
                mfreq->freq++;
            else if(*a > mfreq->max){
                mfreq->freq = 1;
                mfreq->max = *a;
            }
    
            findMax(a+1, length - 1, mfreq);
        }
    }
    

    findMax 的调用将调用自己的初始长度加一的次数,每次递增提供的指针并处理相应的元素,所以这基本上只是遍历a 中的所有元素一次,并且没有奇怪的分裂。

    【讨论】:

    • 当然,初始最小值也可以设置为数组中的第一个值...
    • 好吧,那会搞砸频率计数,不是吗?
    • 另外,这意味着修改/复制传递的数组,并进行额外的传递。另外,我知道这是一个 C 问题,但是 reset 函数可以用于 C++ 中的一个不错的 maxfreq 构造函数:)
    • 虽然这使用递归,但它使用 O(length) 堆栈深度。
    【解决方案3】:

    这对我很有效:

    #include <stdio.h>
    #include <string.h>
    
    // define a struct that contains the (max, freq) information
    struct arrInfo
    {
        int max;
        int count;
    };
    
    struct arrInfo maxArr(int * arr, int max, int size, int count)
    {
    
        int maxF;
        struct arrInfo myArr;
    
        if(size == 0)   // to return from recursion we check the size left
        {
            myArr.max = max;    // prepare the struct to output
            myArr.count = count;
            return(myArr);
        }
    
        if(*arr > max)   // new maximum found
        {
            maxF = *arr;  // update the max
            count = 1;    // initialize the frequency
        }
        else if (*arr == max) // same max encountered another time
        {
            maxF = max;     // keep track of same max
            count ++;       // increase frequency
        }
        else             // nothing changes
            maxF = max;  // keep track of max
    
    
        arr++;      // move the pointer to next element
        size --;    // decrease size by 1
    
        return(maxArr(arr, maxF, size, count)); // recursion
    
    }
    
    int main()
    {
        struct arrInfo info; // return of the recursive function
    
        // define an array
        int arr[] = {8, 4, 8, 3, 7};
    
        info = maxArr(arr, 0, 5, 1); // call with max=0 size=5 freq=1
    
    
        printf("max = %d  count = %d\n", info.max, info.count);
        return 0;
    }
    

    运行时,输出:

    max = 8  count = 3
    

    通知
    在我的代码示例中,我假设数字为正数(将 max 初始化为 0),我不知道您的要求,但您可以详细说明。

    【讨论】:

    • 只需将 max 初始化为 INT_MIN(在 limits.h 中定义),这样可以避免负整数的任何问题 :)
    • 如果初始 max 值最终成为最大值,则使用 freq=1 初始化是一个问题。结果相差 1。最好使用freq=0 进行初始化。
    • @chux: 你是对的,非常安全freq 最好初始化为0,但是如果用户使用initial max 作为@ 调用函数,那将是非常无意义的行为987654332@!但我在所有情况下都承认你的建议
    【解决方案4】:

    你的作业中的要求至少是有问题的。仅供参考,以下是如何在实际代码中完成此操作(要解决您的作业,请参阅其他答案):

    int findMax(int length, int* array, int* maxCount) {
        int trash;
        if(!maxCount) maxCount = &trash;    //make sure we ignore it when a NULL pointer is passed in
    
        *maxCount = 0;
        int result = INT_MIN;
        for(int i = 0; i < length; i++) {
            if(array[i] > result) {
                *maxCount = 1;
                result = array[i];
            } else if(array[i] == result) {
                (*maxCount)++;
            }
        }
        return result;
    }
    

    做事总是尽可能直截了当。

    【讨论】:

    • @chouaib 它不应该在那里。在这种情况下使用递归不符合KISS,我明确表示这不是OP分配的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-27
    • 1970-01-01
    • 2021-01-23
    • 1970-01-01
    • 2016-02-24
    • 2012-07-29
    相关资源
    最近更新 更多