简体   繁体   中英

I'm trying to sum up the numbers in a given array, using recursion , tried this code but it isn't working. Why?

#include <iostream>

   using namespace std;

   int sumByRecursion( int arr[]) {
        int sum = 0;
        int n = sizeof(arr)/sizeof(arr[0]);
        //n is the size of the array
        if (n == 0) {
            return sum;
        } else {
            n -= 1;
            for (int i=0;i=n;++i){
                arr[i]=arr[i+1];
            }
            return (sum + arr[0] + sumByRecursion( arr));
        }
    }

   int main() {
        int arr[]={2, 4, 6};
        sumByRecursion( arr);

        return 0;
    }
    

sumByRecursion working based on this idea: 1-if the size of the array is 0 "empty array", return the sum. 2-if size isn't 0 "array isn't empty", sum up the first element on sum, then call the function, reduce the array's size by 1, sumByRecursion on the new array.

You need to pass in the size of the array to the sumByRecursion routine.

The reason you need to pass the size of the array is because the array does not track its own size.

Alternatives like std::array and std::vector provide the capability of querying them for their size, but C-style arrays do not carry along that information.

The std::size function queries the type (which is a C-style array in that context) to figure out the size. Once passed as an int arr[] parameter, that arr type is int* which no longer can produce the size information.

The int arr[] parameter is a way of writing int* arr , but suggests to the reader that the arr parameter is a C-style array. Could be considered self-documenting code, when done correctly -- but many programs would express the parameter as int* arr so, alas, it is not a widespread idiom.

#include <cstddef>
#include <iterator>
#include <iostream>

using std::cout;
using std::size;
using std::size_t;

namespace {

int sumByRecursion(int arr[], size_t n) {
    if (n == 0) {
        return 0;
    } else {
        // Many C++ compilers do not perform tail recursion optimization.
        // But for those that do, this will thwart tail recursion optimization.
        return arr[0] + sumByRecursion(arr+1, n-1);
    }
}

} // anon

int main() {
    int arr[] = {2, 4, 6};
    auto arr_size = size(arr);
    auto sum = sumByRecursion(arr, arr_size);
    cout << sum << "\n";
}

A (sadly) common mistake:

int sumByRecursion( int arr[] )
{ // What do you think  ^^^^^  this is?

    int n = sizeof(arr)/sizeof(arr[0]);
    //      ^^^^^^^^^^^ Sorry, too late.
    // ...
}

As already noted in the comment section

Inside the function the parameter arr has decayed to type int* and knows nothing about the number of elements in the array. ( Richard Critten )

In short: int sumByRecursion( int arr[]) is exactly the same as int sumByRecursion( int *arr) . That [] syntax in the parameter list is nothing more than syntax sugar. ( PaulMcKenzie )

The solution is to pass the size alongside the pointer, either explicitly as a separate function argument or inside an object like std::span or std::ranges::range .

An alternative, of course, is to pass the couple of iterators returned by std::cbegin() and std::cend() .


The code used to "reduce the array's size by 1" is probably a result of the same misunderstanding:

int sum = 0;
// ...
if (n == 0) {              // Ok...
    return sum;
} else {
    n -= 1;                // Okayish...
   
    for (int i=0;i=n;++i){ // 
        arr[i]=arr[i+1];   // <-- There's NO need to do all those copies!
    }                      // 

    return (sum + arr[0] + sumByRecursion( arr));
    //                                    ^^^^ This does NOT pass an array
}

Eljay 's answer shows how to correctly implement OP's algorithm.

Just for fun (1) , a stack-friendlier implementation

#include <iostream>

int sumByRecursion(size_t n, int const* arr)
{
    // Stop the bloody recursion
    if ( n == 0 )
        return 0;
    if ( n == 1 )
        return arr[0];
    
    // Divide et impera
    size_t middle = n / 2;
    return sumByRecursion(middle, arr)
         + sumByRecursion(n - middle, arr + middle);
}

int main()
{
    int arr[] {2, 4, 6};

    std::cout << sumByRecursion(std::size(arr), arr) << '\n';
}

(1) Seriously, do NOT use this. It's utterly inefficient and uselessly convoluted. Use the right algorithm instead.

I can offer the solution of your problem, using the algorithm Depth first search .

#include <iostream>
#include <vector>
using namespace std;
const int maximumSize=10;
vector<int> visited(maximumSize, 0);
int dfs(int current, int previous, vector<int>& input)
{
    if(visited[current]==1)
    {
        return 0;
    }
    visited[current]=1;
    int summarize=0;
    for(int next=(current+1); next<input.size(); ++next)
    {
        if(next==previous)
        {
            continue;
        }
        summarize+=dfs(next, current, input);
    }
    summarize+=input[current];
    return summarize;
}
void solve()
{
    vector<int> inputVector={2, 4, 6};
    cout<<dfs(0, -1, inputVector);
    return;
}
int main()
{
    solve();
    return 0;
}

Here is the result:

12

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM