0

So I have a task in my training that sounds like this: Write a subprogram that will recursively find the maximum element from an array and also write the main function to call it. What I failed to fully understand is what recursion is. I wanted to ask you guys if my code is recursive or not. And if not what changes should I make/ what recursion really means?

#include <stdio.h>

int find_maximum(int[], int); 

int main() {
  int c, array[100], size, location, maximum;

  printf("Input number of elements in array\n");
  scanf("%d", &size);

  printf("Enter %d integers\n", size);

  for (c = 0; c < size; c++)
    scanf("%d", &array[c]);

  location = find_maximum(array, size);
  maximum  = array[location];

  printf("Maximum element location = %d and value = %d.\n", location + 1, maximum);
  return 0;
}

int find_maximum(int a[], int n) {
  int c, max, index;

  max = a[0];
  index = 0;

  for (c = 1; c < n; c++) {
    if (a[c] > max) {
       index = c;
       max = a[c];
    }
  }

  return index;
}

Thank you all for your time!

Alphonse
  • 661
  • 1
  • 12
  • 29
  • When you googled for a definition of "recursive", what were the dirst three results? – n. m. could be an AI Jul 09 '17 at 10:28
  • Your description of your assignment is ambiguous. Do you have to find the maximum value (but you don't care about the position), or do you have to find the position that holds the maximum value. Both are valid requirements, but they're different. The code shown finds the position. – Jonathan Leffler Jul 09 '17 at 15:15

7 Answers7

1

No, your code does not use recursion. Recursion is when a function calls itself, or calls another function which leads to a call to itself again.

You can change your code like this to have a recursive, stateless function that can determine the maximum value of the array.

int find_maximum(int a[], int n) {
   return find_maximum_r(a, 0, n);
} 

int find_maximum_r(int a[], int index, int n) {
  if (index + 1 == n) {
    return a[index];
  }

  int maxRight = find_maximum_r(a, index + 1, n);
  return a[index] > maxRight ? a[index] : maxRight;
}
idmean
  • 14,540
  • 9
  • 54
  • 83
  • Thank you @idmean . But in the main function everything is ok, right? – Alphonse Jul 09 '17 at 10:03
  • 1
    Everything looks ok. Please just note that my example function returns the maximum value and not the index of the maximum. – idmean Jul 09 '17 at 10:05
1

Think of calculating the maximum number in an array as the number which will be maximum of the first element and the maximum of the remaining elements of the array. Something like: max(first_elem, max(remaining_elems)).

The actual recursive function: find_max quite simple, if there is just a single element in the array, that element is returned. Otherwise, we get the maximum of the first element and the remaining elements of the array.

#include <stdio.h>

// function to find the max of 2 numbers
int max(int x, int y)
{
    return (x > y) ? x : y;
}

// the recursive function
int find_max(int *p, int n)
{
    if (n == 1) return *p;

    return max(*p, find_max(p + 1, n - 1));
}

int main(void)
{
    int arr[] = {23, 3, 11, -98, 99, 45};
    printf("max: %d\n", find_max(arr, sizeof arr / sizeof arr[0]));
}
babon
  • 3,615
  • 2
  • 20
  • 20
  • Note that this code finds the maximum value but does not record the position (a position) where the maximum is found. The code in the question is iterative but finds the position holding the maximum value. – Jonathan Leffler Jul 09 '17 at 15:17
1

Problems that are well-suited to recursion can be broken down into smaller, simpler subproblems. This is one of the things that gives recursion its power. When trying to use recursion to solve a problem, it usually seems best to try to break the problem down into simpler subproblems in finding your way to a solution.

You might notice that in finding the maximum value stored in an array, it is either the value of the first element, or the maximum value of the remaining elements. This breaks the problem into two parts: if the first element is larger than any remaining elements, you are done; otherwise, you must continue and see if the next element is larger than the remaining elements. In code, this might look like:

int max_in(size_t rest_sz, int *rest)
{
    int curr_val = rest[0];
    if (rest_sz == 1) {
        return curr_val;
    }

    int max_in_rest = max_in(rest_sz-1, rest+1);

    return curr_val > max_in_rest ? curr_val : max_in_rest;
}

Here, there is a base case: if rest_sz is 1, there is no need to look further; the value of first element (curr_val = rest[0]) is the maximum, and that value is returned. If the base case is not satisfied, execution of the function continues. max_in_rest is the result from the recursive function call max_in(rest_sz-1, rest+1). Here rest_sz-1 indicates the number of elements remaining in the portion of the array indicated by rest+1. In the new function call, the base case is met again, and eventually this case will be true since rest_sz is decremented with each recursive call. When that happens, the value of curr_val in the current stack frame will be returned; note that this value is the value of the last element in the array. Then, when the function returns to its caller, max_in_rest in that frame will get the returned value, after which the larger of curr_val or max_in_rest is returned to the previous caller, and so on, until finally control is returned to main().

Using pencil and paper to diagram each function call, the values of its variables, and what is returned would help to understand exactly how this recursion works.

You can apply the same method to solving the problem of finding the index of the maximum value of an array. In this case, if the value of the first element is greater than the value of any remaining elements, then the index of the maximum element is the index of the first element; otherwise the index of the maximum element is the index of the maximum value of the remaining elements. In code, this might look like:

size_t find_max_r(int arr[], int *rest, size_t rest_sz, size_t curr_ndx)
{
    if (rest_sz == 1) {
        return curr_ndx;
    }

    int curr_val = arr[curr_ndx];
    size_t max_in_rest_ndx = find_max_r(arr, rest+1, rest_sz-1, curr_ndx+1);
    int max_in_rest = arr[max_in_rest_ndx];

    return curr_val >= max_in_rest ? curr_ndx : max_in_rest_ndx;
}

There is just a little more information to keep track of this time. Here, if the base case is satisfied, and rest_sz is 1, then there is no reason to look further, the current index curr_ndx is the index of the maximum value. Otherwise, find_max_r() is recursively called, with rest incremented to point to the remaining elements of the array, and rest_sz suitably decremented. This time, curr_ndx is keeping track of the current index with respect to the original array, and this value is passed into each function call; also, a pointer to the first element of the original array, arr, is passed into each function call so the index value curr_ndx can access the values from the original array.

Again, when the base case is reached, the current position in the array will be the end of the array, so the first elements to be compared in the return statement will be towards the end of the array, moving towards the front of the array. Note that >= is used here, instead of > so that the index of the first maximum value is returned; if you instead want the index of the last maximum value, simply change this to >.

Here is a complete program. Note the use of the helper function find_max() to call the recursive function find_max_r(), which allows the caller to use a function with the same signature that the posted code uses (except for the use of size_t types, which is really the correct type for array indices):

#include <stdio.h>

int max_in(size_t sz, int *rest);
size_t find_max(size_t sz, int arr[]);
size_t find_max_r(int arr[], int *rest, size_t rest_sz, size_t curr_ndx);

int main(void)
{
    int array[] = { 2, 7, 1, 8, 2, 5, 1, 8 };
    size_t array_sz = sizeof array / sizeof array[0];

    int max_val = max_in(array_sz, array);
    printf("Maximum value is: %d\n", max_val);

    size_t max_ndx = find_max(array_sz, array);
    printf("Maximum value index: %zu\n", max_ndx);

    return 0;
}

int max_in(size_t rest_sz, int *rest)
{
    int curr_val = rest[0];
    if (rest_sz == 1) {
        return curr_val;
    }

    int max_in_rest = max_in(rest_sz-1, rest+1);

    return curr_val > max_in_rest ? curr_val : max_in_rest;
}

size_t find_max(size_t sz, int arr[])
{
    int *rest = arr;
    return find_max_r(arr, rest, sz, 0);
}

size_t find_max_r(int arr[], int *rest, size_t rest_sz, size_t curr_ndx)
{
    if (rest_sz == 1) {
        return curr_ndx;
    }

    int curr_val = arr[curr_ndx];
    size_t max_in_rest_ndx = find_max_r(arr, rest+1, rest_sz-1, curr_ndx+1);
    int max_in_rest = arr[max_in_rest_ndx];

    return curr_val >= max_in_rest ? curr_ndx : max_in_rest_ndx;
}

Program output:

Maximum value is: 8
Maximum value index: 3
ad absurdum
  • 19,498
  • 5
  • 37
  • 60
0

No, your code is recursive only if you call the function find_maximum from itself directly or indirectly.

As your function is trying to get not only the maximum value, but also the position in the array, I have modified slightly the interface to return the reference (that is, a pointer to the value) so we can infer the position of the array element directly from the subtraction of element pointers. This way, I can pass to the function the array pointer directly and the array size, and then divide the array in two halves, and applying the same function to the two halves (it can be demonstrated that if some element is the maximum value of the array, it has to be greater than or equal to each half's maximum) For the same reason, I have modified some of the variables defined in your main() function, to allow for references to be used:

max.c

#include <stdio.h>
#include <assert.h>

int *find_maximum(int a[], int n); /* return a reference pointer to the maximum value */

int main() {
  int c, array[100], size, *location, /* location must be a pointer */
  maximum;

  printf("Input number of elements in array\n");
  scanf("%d", &size);
  assert(size >= 1);

  printf("Enter %d integers\n", size);

  for (c = 0; c < size; c++)
    scanf("%d", &array[c]);

  location = find_maximum(array, size);
  maximum  = *location; /* access to the value is granted by pointer dereference */
  printf("Maximum element location = %td and value = %d.\n", 
         location - array, /* pointer difference gives the array position */ 
         maximum);
  return 0;
} /* main */

/* somewhat efficient recursive way of a divide and conquer method 
 * to get the maximum element reference. */
int *find_maximum(int a[], int n)
{
    if (n == 1) return a; /* array of 1 element */
    int *left  = find_maximum(a,       n/2), /* left half begins at a
                                              * and has n/2 elements */
        *right = find_maximum(a + n/2, (n+1)/2); /* right half begins 
                                                  * at a + n/2, and
                                                  * has (n+1)/2 
                                                  * elements */
    return *left > *right 
           ? left 
           : right;
} /* find_maximum */

As you see, I have to divide by two, but as I have arrays of any length, I have to be careful not to leave out any element in the next step. This is the reason for using an array of (n+1)/2 elements in the right half of the recursive call to the function. I include n/2 elements in the first half (rounding down), I have to include (n+1)/2 elements (rounding up) in the right half, to be sure that I include all the array elements in the two halves.

Community
  • 1
  • 1
Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • Be cautious about using the term 'reference' in reference to C code — pun intended. There are some people who are rather zealous about the use of the term because it has a separate meaning in C++ and it often isn't clear whether people recognize the difference. You can also use `n - n/2` to get the number of elements in the upper half of the array (instead of `(n + 1) / 2`). There's no practical difference — and the computation cost is the same (one addition or subtraction; one division). – Jonathan Leffler Jul 11 '17 at 05:38
  • Hi @JonathanLeffler, I know that. I follow you, as a good reference for C/C++ and I perfectly understand your intention, but reference is used in this context right as it represents exactly what the function is assumed to return. In C++ the return type should be an `int &` indeed, and many of the asterisks used to dereference it should be avoided.... but we are talking about C, not C++ (I took the precaution of double checking the question tag before following this way). Thanks anyway! (and thanks for your edition, as I'm not a natural english writer either) – Luis Colorado Jul 11 '17 at 08:01
  • @JonathanLeffler, about the `n - n/2` approach, I'll agree with you that it is the same indeed (and more clarifying, indeed). It simply didn't came to mind when I wrote, so I found it somewhat obscure, and that was the reason to explain it in the comments. – Luis Colorado Jul 11 '17 at 08:08
  • Note that `location - array` has type `ptrdiff_t`, so the `%td` conversion specifier should be used instead of `%d` to print this value while avoiding UB. Also, I don't see that the "divide and conquer" approach used here is any more efficient than my approach; on an input array of 6 elements, your version needs 11 recursive calls, while mine needs 6. – ad absurdum Jul 11 '17 at 08:53
  • @DavidBowling, well, this is not a competition, so no penalty if my approach is not more efficient than yours. I've nevertheless said such a thing. Anyway, you're right in the assert about the format string, but I'm trained on the ancient times of K&R and have not got the time to study them (feel free to edit the answer to correct it if you want). The efficiency gain comes from the fact that this is a divide by two approach, and so, it deservers log(n) stack resources, than a linear approach like the head/tail approach. On a large array, this is better, at least in stack consumption. – Luis Colorado Jul 11 '17 at 13:00
  • @DavidBowling, also, in a multithreaded environment, my aproach is subject to parallel implementation, and yours has to calculate the recursive call before comparing the result with the head element, so it's more difficult to parallelize. – Luis Colorado Jul 11 '17 at 13:03
  • Not trying to start a competition, and I was not focused on efficiency from the start, but on clarity for OP's understanding; only commenting on your comment: "somewhat efficient recursive way...." – ad absurdum Jul 11 '17 at 13:08
0

First of all, recursion means - function calling itself.

enter image description here

And what you've written is not recursive function. I'll post the most simple way to find biggest or largest element in an array, using recursion.

#include<stdio.h>  
  
#define N 5  
  
int biggest(int num[], int n, int big)  
{  
    if(n < 0)  
        return big;  
    else  
    {  
        if(big < num[n])  
            big = num[n];  
  
        return biggest(num, --n, big);  
    }  
}  
  
int main()  
{  
    int a[N], i;  
  
    printf("Enter %d integer number\n", N);  
    for(i = 0; i < N; i++)  
        scanf("%d", &a[i]);  
  
    printf("Biggest Element in the array: %d\n", biggest(a, N - 1, a[0]));  
  
    return 0;  
} 

enter image description here

Source: C Program To Find Biggest Element of An Array using Recursion

Satish
  • 173
  • 1
  • 9
-1

NO it is not recursive function

to know about recursion this link is very useful https://www.khanacademy.org/computing/computer-science/algorithms/recursive-algorithms/a/recursion/

to make a recursion function to solve your problem try this

you can try this pseudo code declare your array global and a max=0 global and size global

int find_maximum(int i)
{
if (i == size )
    return max;
else if ( max < array[i])
    max =array [i];
return find_maximum(i+1);
}

where i is the array index

  • Using global variables to pass data to functions like this is a bad idea. Given the array `int array[] = { -4, -7, -19, -24, -3, -9 };`, your code would incorrectly return 0 as the maximum value. I'm also far from convinced by the [link](https://www.khanacademy.org/computing/computer-science/algorithms/recursive-algorithms/a/recursion/) you give — matryoshka dolls are fun but hardly a clear exposition on recursion. – Jonathan Leffler Jul 09 '17 at 15:01
-1

No, your program is certainly not recursive. As the definition, recursive function must call itself with a terminating condition.

Please read TutorialsPoint about recursion in C.

Update on @JonathanLeffler's comment: Please note that the output in the reference will overflow.

Harsh Shankar
  • 506
  • 5
  • 16
  • A recursive function definitely doesn’t have to have a terminating condition. – idmean Jul 09 '17 at 10:03
  • @idmean: will it not fall under infinite recursion which results stack-overflow on runtime? – Harsh Shankar Jul 09 '17 at 10:15
  • It would. But technically speaking it's still recursion (hence the name "infinite recursion"). – idmean Jul 09 '17 at 10:16
  • Well, sure agreed. Though, When ever I need to tell about recursion to anyone, I surely mention to have that break case. Newbies mostly miss the break conditions otherwise. { Personal experience ;) } – Harsh Shankar Jul 09 '17 at 10:23
  • 1
    "I surely mention to have that break case"-- usually called a [base case](https://en.wikipedia.org/wiki/Recursion), though. – ad absurdum Jul 09 '17 at 10:37
  • 2
    Note that the TutorialsPoint web site linked to for a discussion of [Recursion](https://www.tutorialspoint.com/cprogramming/c_recursion.htm) includes an example for 'factorial()' and the statement that _'Factorial of 15 is 2004310016'_. The correct answer is 1307674368000, which is too big to fit into a 32-bit integer. (1307674368000 modulo 2^31 == 2004310016). The example has run into integer overflow. That does not bode well for those trying to learn from the site. Please find a better reference site and update your answer. – Jonathan Leffler Jul 09 '17 at 15:13
  • @JonathanLeffler: That reference from TutorialPoint was only about the Recursion. I personally hadn't checked those outputs. Alternatively, you may refer [this](http://www.w3schools.in/c-program/find-factorial-of-the-given-number/) – Harsh Shankar Jul 09 '17 at 16:31
  • 2
    The trouble is, once a site posts an egregiously wrong answer and doesn't note overflow, then everything the site says becomes suspect. Your alternative produces valid output — but doesn't protect against overflow. It gets messy. My automatic choice would probably be Wikipedia, but each to their own. It's a good idea to check what you reference, to be reasonably sure it is sound. Maybe your experience with TutorialsPoint is more positive than mine. – Jonathan Leffler Jul 09 '17 at 16:36
  • @JonathanLeffler: Updated – Harsh Shankar Jul 09 '17 at 17:03