GIDForums  

Go Back   GIDForums > Computer Programming Forums > C++ Forum
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 05-Jun-2006, 23:55
earachefl earachefl is offline
Member
 
Join Date: Feb 2006
Posts: 178
earachefl is on a distinguished road

Unwinding a recursive bool function?


Hi,

My assignment:

Quote:
Write a program which, given a list of up to 10 integer numbers and a sum, will find a subset of the numbers whose total is that sum if one exists or indicate that none exists otherwise. For example, for the list: 5, 13, 23, 9, 3, 3 and sum = 28, your program should find: 13, 9, 3, 3.

I implemented the function as returning a bool value. Using the numbers provided in the example, my function is finding the correct subset (and I can force it to show the subset) , but when the function returns, it always returns a value of false. I can't figure out what it is about the way the recursion unwinds... it gets to the stopping case, sets the value to true, and should be returning that value all the way to the end - yet when the function returns to main, main reports that the value is false.

CPP / C++ / C Code:
#include <iostream>
#include <vector>
using namespace std;

bool s (const int[], vector<int>&, const int, int, int, const int, int, bool);

int main () {

    bool isTrue = false;
    int target = 28;
    int size = 6;
    int set[] = {5, 13, 23, 9, 3, 3};
    vector<int> subset;
    isTrue = s(set, subset, target, 0, 0, size, 0, isTrue);
    cout << "Function s returns value of " << isTrue << endl;
    if (isTrue) {
        cout << "Subset ";
        for (int i = 0; i < subset.size(); i++) 
            cout << subset.at(i) << " ";
        cout << endl;
    }
    else
        cout << "Subset not found" << endl;
    return 0;
}

bool s (const int set[], vector<int>& subset, const int target, int x, int y, const int size, int sum, bool isTrue)
{
    //stopping case
    if (sum == target) {
        cout << "sum " << sum << " equals target " << target << endl;
        isTrue = true;
        cout << "returning from terminating condition with value " << isTrue << endl;
        return isTrue;
    }

    //if function has reached last subscript without finding a match
    //resets subset and sum and starts over from x + 1 subscript
    else if (y == size) {
        subset.resize(0);
        sum = 0;
        cout << "Sum " << sum << " - resetting subset vector " << endl;
        s(set, subset, target, x + 1, x + 1, size, sum, isTrue);
        return isTrue; 
    }
    
    //else if sum is less than target, add value of set[y] to sum, add set[y] to back of subset,
    //call s with y incremented
    else if (sum < target) {
        sum += set[y];
        subset.push_back(set[y]);
        cout << "Sum " << sum << endl;
        s(set, subset, target, x, y + 1, size, sum, isTrue);
        return isTrue;  
    }
    
    //else if sum is greater than target, remove last value added from sum and subset
    //add value of set[y] to sum, add set[y] to back of subset, call s with y incremented
    else {
        sum -= set[y - 1];
        sum += set[y];
        subset.pop_back();
        subset.push_back(set[y]);
        cout << "Sum " << sum << endl;
        s(set, subset, target, x, y + 1, size, sum, isTrue); 
        return isTrue;      
    }
}
log shows:
Quote:
Sum 5
Sum 18
Sum 41
Sum 27
Sum 30
Sum 30
Sum 0 - resetting subset vector
Sum 13
Sum 36
Sum 22
Sum 25
Sum 28
sum 28 equals target 28
returning from terminating condition with value 1
Function s returns value of 0
Subset not found

I know I could implement the function as void, returning the bool value by reference, but would rather figure out what the hell is going on!
  #2  
Old 06-Jun-2006, 01:53
WaltP's Avatar
WaltP WaltP is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Midwest US
Posts: 3,281
WaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to all

Re: Unwinding a recursive bool function?


First thing I'd do is remove isTrue from the parameter list. Set it to false when you enter s().

Then when you call s() within s(), store the return value in isTrue:
CPP / C++ / C Code:
isTrue = s(set, subset, target, x, y + 1, size, sum);
That's what you forgot.
__________________

Got a cough? Go home tonight and eat a whole box of Ex-Lax. Tomorrow, you'll be afraid to cough.
-- Pearl Williams
  #3  
Old 06-Jun-2006, 03:41
earachefl earachefl is offline
Member
 
Join Date: Feb 2006
Posts: 178
earachefl is on a distinguished road

Re: Unwinding a recursive bool function?


Ah, thanks! I could also just return the results of s:

CPP / C++ / C Code:
return s(set, subset, target, x + 1, x + 1, size, sum);

or for the stopping case

CPP / C++ / C Code:
return true;

which would negate needing variable
CPP / C++ / C Code:
bool isTrue = false;
in the called function, correct?

Is that better, do you think?
  #4  
Old 06-Jun-2006, 13:54
WaltP's Avatar
WaltP WaltP is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Midwest US
Posts: 3,281
WaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to all

Re: Unwinding a recursive bool function?


It's a style issue. I personally prefer not to return a function's return value directly, like return func(); but there's no reason why you can't. I like to keep my statements simpler. As I said, personal style.
__________________

Got a cough? Go home tonight and eat a whole box of Ex-Lax. Tomorrow, you'll be afraid to cough.
-- Pearl Williams
  #5  
Old 06-Jun-2006, 15:30
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,893
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Unwinding a recursive bool function?


Quote:
Originally Posted by earachefl
Ah, thanks! I could also just return the results of s:

CPP / C++ / C Code:
return s(set, subset, target, x + 1, x + 1, size, sum);

or for the stopping case

CPP / C++ / C Code:
return true;

which would negate needing variable
CPP / C++ / C Code:
bool isTrue = false;
in the called function, correct?

Is that better, do you think?
First of all, someone once reported that he read in a book that "recursion is often used to solve problems that would be difficult to solve otherwise, and that recursive functions often are less efficient but easier to understand."

Well, "easier" is a really subjective term, but I'll just say that for cases like this one, it's pretty "easy" for me to visualize what I want to do, and it looks like recursion. It is certainly possible to to this with loops, but let's go for the "easy" way. The trick is to keep it looking "easy" after all of the program requirements are met.

In general, and in simplest terms, a recursive function looks like this

Code:
if (stopping_condition) then return else call the function recursively end if return

Actually the "else" is redundant here, since the only way it could get to that part is if it hasn't met the stopping condition. But I like to have it as explicit as possible for my own sanity (or whatever approximation that I can pretend to possess).

While we are at it, I note that the last "return" is redundant (at least in C aand C++), since the function returns automatically by "falling off of the end" of the code. (Note that in this simplest form there isn't any provision for a return value.)

If we do define the function to return a value, then we have to keep in mind that after some recursive calls, the function goes through a number of returns before falling off of the end of the page. I'm thinking that's what you refer to as "unwinding". As you mentioned, the unwinding part can be kind of tricky.

Keeping this in mind, the simple, "easy", pseudo code for C (or C++) functions actually might be written with fewer keystrokes something like this:

Code:
if not (stopping_condition) call the function recursively else return end if

Or, even, by removing the redundant 'else' and 'return':

Code:
if not (stopping_condition) call the function recursively

Compare any one of these schemas with your program. I'm not saying there is anything "wrong" with your efforts, but the "easier" way gets kind of messy.


First of all, I'm not too crazy about the problem statement: "...find a subset of numbers..." Does it say what you are supposed to do with it? Let's suppose for a minute that all you need to do is print out the subset when you find it, rather than returning that information, somehow, to main(). It really didn't say what to do, so I'll to the "easy" thing.

Then the pseudo code could look like the following (where I have put in a couple things specific to our present problem, and I've made the "pseudo" code look a lot like C++). I have assumed that the parameters of the function are:

set[], size, target, subset and sum, just like yours. What you called "x", I'll call "start": the current index value. The function is called from main() with start = 0 and sum = 0

Code:
void s (const int set[], const int size, const int target, int start, int sum, <int> &subset) { int i; int newsum; if (sum == target) { print out the subset and return } if (sum > target) { return (don't do anything else) } for (i = start; i < size; i++) { newsum = sum + set[i]; subset.push_back(set[i]); s(set, size, target, i+1, newsum, subset); subset.pop_back(); } }

That is, literally, the whole function (well you actually have to edit two statements and make a function to print the vector, but I hope you get the idea).

If you are one of those wild and crazy guys who like to put comments in your code to remind yourself what the heck it's doing when you come back to it at some later date, you could put the following in the function, just before the loop
CPP / C++ / C Code:
    //
    // Here's the recursion: check everything from here to the
    // end of the set
    //
    // Each time through the loop:
    // Add the current value to the sum, push the current value
    // onto the subset vector and check everything to the right
    // of this index. After checking each one, take this one out
    // of the vector so that the next time through the loop starts
    // at the same state as before.
    //

Notice, there are no issues with return values. Notice also, that without some extra effort, there's really no way to stop without going through all possible subsets. However it does meet the stated assignment of "finding a subset whose total is that sum". I know, I know...It doesn't satisfy the part about "indicate that none exists otherwise". But I'll get to that in a minute.

I would like to note, at this point, the other thing that I didn't particularly like about the problem statement: the example set that you showed actually two subsets with the desired property: {5, 23} and {13, 9, 3, 3}.

Why did the statement say that "your program should find: 13, 9, 3, 3"?

How could I possibly make a program that is guaranteed to find this subset unless I already knew what the subset was? (Well ---maybe if I wrote a program to find all subsets; then I would be guaranteed to find the one that it really wanted me to find --- yeah! That's the ticket.)

If you run a program organized along the lines that I showed above, you will see that it prints out both sequences. Try it again with different sets and different targets. It prints out every valid subset. Of course it does; that's how it is designed. Is that good or is that bad?

The problem statement isn't clear, but I really don't like being told that the program should find one particular subset without knowing why it shouldn't find another valid one.

So, here's what you could consider:

Add another parameter to the function, a vector of vector of ints (passed by reference). Every time our program finds a valid subset, then, instead of printing it out right then, push it onto the vector of vectors.

Back in the main program, use the size() member function of the vector of vectors to go through a loop that calls a function that prints the members of each valid subset.

Here's the main() program, and I'll stop pretending it's pseudo code. This is the real thing:

CPP / C++ / C Code:
//
// Illustraton of a recursive function that looks at a set and sees
// if there are any subsets whose sum is equal to a given "target" 
// value.
//

#include <iostream>
#include <vector>

using namespace std;

// Here's the recursive function:
//
// set[] is the array of ints and size is the number of elements in
//       the array.
//
// target is the sum that we are seeking.
//
// start is the index of the element of set[] where we start looking.
//
// sum is the sum so far (everything in the subset to the left of 
//       start).
//
// subsets is the vector of arrays of valid subsets resulting 
//       from all tests. (That is, this saves the successful
//       subsets for subsequent processing.)
//
// subset is the collection, so far, of everything to the left 
//       of start that's part of the current subset being tested.
//

void s (const int set[], const int size, const int target, int start, int sum, 
        vector< vector<int> > &subsets, vector <int> &subset);

void print_vInt(vector<int>);


int main () {

    int target = 28;
    int set[] = {5, 13, 23, 9, 3, 3, 4};
    int size = sizeof(set) / sizeof(set[0]);
    vector<int> subset;
    vector< vector<int> > subsets;
    //
    // Here's the deal:
    // start with sum = 0 and starting index = 0
    //
    s(set, size, target, 0, 0, subsets, subset);
    cout << "Number of subsets printed = " << subsets.size() << endl;
    for (unsigned int i = 0; i < subsets.size(); i++) {
        print_vInt(subsets[i]);
    }
    return 0;
}

The only change to the function pseudo-code is this instead of the place where we previously printed out the subset:

CPP / C++ / C Code:
    if (sum == target) {
        subsets.push_back(subset); // it's a winner: save it
        return;
    }

(You, obviously, also change the recursive function call to have the new subsets" parameter.)


My output:

Code:
Number of subsets printed = 3 vector: < 5 13 3 3 4 > vector: < 5 23 > vector: < 13 9 3 3 >

Regards,

Dave
  #6  
Old 06-Jun-2006, 15:51
earachefl earachefl is offline
Member
 
Join Date: Feb 2006
Posts: 178
earachefl is on a distinguished road

Re: Unwinding a recursive bool function?


Quote:
Originally Posted by davekw7x
First of all, someone once reported that he read in a book that "recursion is often used to solve problems that would be difficult to solve otherwise, and that recursive functions often are less efficient but easier to understand."
That someone would be me (the OP)
Quote:
Compare any one of these schemas with your program. I'm not saying there is anything "wrong" with your efforts, but the "easier" way gets kind of messy.
That's why I posted my code - in trying to find a recursive solution to these problems, it sometimes seems like the author is putting the cart before the horse - and I can often see an iterative solution quickly, while the recursive solution is not so intuitive. I'm just trying to understand as completely as possible the "best" way to do things.

Quote:
First of all, I'm not too crazy about the problem statement: "...find a subset of numbers..." Does it say what you are supposed to do with it? Let's suppose for a minute that all you need to do is print out the subset when you find it, rather than returning that information, somehow, to main(). It really didn't say what to do, so I'll to the "easy" thing.

I quoted the assignment in its entirety - no, it doesn't say what you are supposed to do with the subset. I had at first thought about just printing the subset, but it seemed to me like it would be more useful to be able to save it for use elsewhere. So that was my extrapolation.

Quote:
I would like to note, at this point, the other thing that I didn't particularly like about the problem statement: the example set that you showed actually two subsets with the desired property: {5, 23} and {13, 9, 3, 3}.

Why did the statement say that "your program should find: 13, 9, 3, 3"?

Excellent question! One I will forward to the author, along with the several dozen other errata I have already found in the book.

Quote:
If you run a program organized along the lines that I showed above, you will see that it prints out both sequences. Try it again with different sets and different targets. It prints out every valid subset. Of course it does; that's how it is designed. Is that good or is that bad?
Do you really need an answer?

Quote:
Here's the main() program, and I'll stop pretending it's pseudo code. This is the real thing:

Thanks, Dave. Your help is invaluable.
  #7  
Old 06-Jun-2006, 16:31
earachefl earachefl is offline
Member
 
Join Date: Feb 2006
Posts: 178
earachefl is on a distinguished road

Re: Unwinding a recursive bool function?


Dave, one more question. In your code the main recursive part is

CPP / C++ / C Code:
for (i = start; i < size; i++) {
        newsum = sum + set[i];
        subset.push_back(set[i]);
        s(set, size, target, i+1, newsum, subset);
        subset.pop_back();
    }

As a pedantic issue, isn't this technically a combination of an iterative and recursive function? I purposefully avoided any use of for loops in my code thinking that if this were an actual class assignment it'd be a disqualifier.
  #8  
Old 06-Jun-2006, 16:52
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,893
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Unwinding a recursive bool function?


Quote:
Originally Posted by earachefl

As a pedantic issue, isn't this technically a combination of an iterative and recursive function?


Just because I specialize in vague generalities doesn't mean that I'll admit to being an expert in pedantics. I have a hard enough time guessing at the answers; I hate it wheh I have to guess at the questions. (In other words what qualifies as recursive is a matter between you and your prof.) See footnote.

My loop is used to get from the beginning of the array to the end. I don't know any easer way. At each step it calls the function recursively. That makes it recursive as far as I am concerned. The bottom line is that it works for me and it was "easy". Your Mileage May Vary.

Regards,

Dave

I had a (very) close friend who was an Electrical Engineering instructor at a large university. The EE Department instituted a policy to require all instructors post last semester's (or last year's) final exams for student perusal. (Fraternities had always kept files of old tests for exclusive use of their members; it seemed more democratic to let everyone have access, and I thought it was a good idea.)

Other instructors worked very hard to make up new tests every semester/year. Comprehensive but all different questions. My "friend" came up with a much easier way: He kept the same questions every time but changed the answers. Problem solved.
  #9  
Old 07-Jun-2006, 18:35
earachefl earachefl is offline
Member
 
Join Date: Feb 2006
Posts: 178
earachefl is on a distinguished road

Re: Unwinding a recursive bool function?


Dave, in your main function, what is the reason for evaluating:
CPP / C++ / C Code:
    int set[] = {5, 13, 23, 9, 3, 3, 4};
    int size = sizeof(set) / sizeof(set[0]);
? Wouldn't just evaluating
CPP / C++ / C Code:
int size = sizeof(set);
give you the value you need (7 in this case)? What does dividing it by
CPP / C++ / C Code:
sizeof(set[0])
add to the picture?
  #10  
Old 07-Jun-2006, 19:08
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,893
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Unwinding a recursive bool function?


Quote:
Originally Posted by earachefl
? Wouldn't just evaluating
CPP / C++ / C Code:
int size = sizeof(set);
give you the value you need (7 in this case)? What does dividing it by

No, Why don't you try it? sizeof(set) gives the amount of memory occupied by the array (in bytes).

Dividing by sizeof(set[0]) gives the number of elements declared in the array. (And gives the correct answer for all compilers, regardless of the size of an int.)

By doing it this way I can change the number of items in the initializer list; I can change the array from int to something else; I can change lots of things without touching the line that performs the automatic calculation of the number of elements in the array. (Note that this only works in the context where the array was declared, not in some function with that has that array name as an argument, or anywhere else. The operator sizeof evaluates the expressions at compile time; the results are constants.)



CPP / C++ / C Code:
#include <iostream>

using namespace std;

int main()
{
    int set[] = {5, 13, 23, 9, 3, 3, 4};
    int num_elements = sizeof(set) / sizeof(set[0]);
    cout << "Size of the array      = " << sizeof(set) << endl;
    cout << "Size of array elements = " << sizeof(set[0]) << endl;
    cout << "Number of elements     = " << num_elements << endl;

    return 0;
}


Output on my computer:

Code:
Size of the array = 28 Size of array elements = 4 Number of elements = 7

Now, try it again for an array of shorts. Try it for an array of longs. Try it for an array of doubles.

Regards,

Dave
 
 

Recent GIDBlogToyota - 2008 November Promotion by Nihal

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
[Include] Doubly-linked List dsmith C Programming Language 6 14-Apr-2006 14:12
[Tutorial] Function Pointers aaroncohn C++ Forum 4 17-Feb-2006 12:33
Help with syntax errors PeteGallo C Programming Language 7 08-Aug-2005 21:30
Major problem with recursive function, help.. kakamuti C Programming Language 4 19-Dec-2004 08:47
Revising Script style ?????? pepee MySQL / PHP Forum 4 14-Apr-2004 05:59

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 08:58.


vBulletin, Copyright © 2000 - 2009, Jelsoft Enterprises Ltd.