Why does recursive function count downwards after peak? - c

with fear that I may overstep another question of mine (although this is a new problem alltogether) I still ask this question.
I have this code:
int blob_count(int y, int x, int gridCopy[][5], int sum){
//Local vars
int posX, posY;
//Find the position 1 behind and 1 above the starting point, and start the loop there
for(posX = -1;posX <=1; posX++){
for(posY = -1; posY <= 1; posY++){
if((y + posY) >= 0 && (x + posX) >= 0){
if((y + posY) <= 5 && (x + posX) <= 5){
if(gridCopy[posY+y][posX+x] == 1){
//Set the starting point to 0 (so it wont get calculated again)
gridCopy[posY+y][posX+x] = 0;
y = posY+y;
x = posX+x;
sum++;
blob_count(y, x, gridCopy, sum);
}
}
}
}
}
return sum;
}
The issue is that sum, which counts up 1, for each recursive run, returns the wrong value. By doing a print for each recursive run it gives the result:
sum = 1
sum = 2
sum = ...
sum = n
Which is great, however, by setting printing out the sum outside the for loop (right before return sum;) the opposite happens when it has peaked, so it does this:
sum = n
sum = ...
sum = 2
sum = 1
return sum; // = 1
Which is obviously wrong, as I want the total count, not the lowest. Have I got the return value the wrong place? I've tried putting it in right after the recursive call (inside the loop), to no avail.

Okay let's get rid of the extra bits and simplify your problem down to the essentials.
You have:
int blob_count(int sum)
{
sum++;
if (sum < 10)
blob_count(sum);
return sum;
}
If you add printf("sum==%d\n", sum) right before the return then it will be called first at the innermost recursion (where sum == 10), then it will return to the next level out where sum == 9, print that, return to sum == 8 and so on.
If you put it before the recursive call to blob_count(sum) then you'll print the values before you recurse down, so they start with sum==0, sum == 1 and so on.
If you want sumto be the deepest level your recursion got to, then you could either pass it back via the return value like this:
int blob_count(int sum)
{
sum++;
if (sum < 10)
sum = blob_count(sum);
return sum;
}
or you could pass it via a pointer so that the original variable gets modified:
void blob_count(int* sum)
{
*sum++;
if (*sum < 10)
blob_count(sum);
return;
}
The first one is probably the solution you are looking for.

What pmg said. For each recursive call, the current value of sum is copied and the copy is passed to the recursive call. If you want to modify objects in functions, you must pass a pointer to these objects instead of the object itself.

Related

Finding proper divisors in c

I'm trying to write a function that finds the number of divisors of a number n, which are smaller or equal to a number k using recursion (in C programming language).
For example, (9,3) should return 2 since the only positive divisors of 9 that are less than or equal to 3 are 1 and 3.
Here's what I've tried but can't figure out why it's not working:
int divisors(int n,int k){
int sum = 0;
if (k==0){
return 0;
}
else if (n%k==0){
return sum++ + divisors(n,k-1);
}
return sum;
}
If anyone is able to help I'd appreciate it.
You are almost there. I made a few fixes:
k == 1 as a break condition is faster, although k == 0 works fine.
The integer sum is useless.
When not counting, your thinking was almost correct. You should return 0 but for this specific case while keeping the function calculating the next ints (recursion). Therefore you should return 0 + divisors(n, k-1)
int divisors(int n,int k){
if (k == 1) return 1;
if (n % k == 0) return 1 + divisors(n, k-1);
return divisors(n, k-1);
}
You are not handling the resolution of the recursion properly
There is no need for a sum variable, instead you want to return the function call (or 0) in any case.
If you find a number so that n%k==0 holds true, you want to return 1 + the results of the next case. However, if you then find a number that is neither 0, nor a match it will stop, instead of checking all numbers down to 0. Therefore adjusting your code in the following way will solve the problem:
int divisors(int n,int k){
if (k==0)
return 0;
else if (n%k==0)
return divisors(n,k-1) + 1;
else
return divisors(n,k-1);
}

why is my variable storing value from previous recursion runs?

the first image is of the Program with regular recursion format, I am returning values for both cases but self call to the function is made only when the argument is a natural number. The result is as expected
in the second program, however, I am not returning any value for natural numbers, the only return case is when the argument is 0.
Ideally, (taking 5 as the input) recursion will happen till num value equals 0. First with
sum = 5 + add(5-1);
sum = 4 + add(4-1);
sum = 3 + add(3-1);
sum = 2 + add(2-1);
sum = 1 + add(1-1);
At this stage, the function will return 0 as flow moves to else block,and value of sum for that loop is 0.
Now, with 0 being returned we rise one step up and 0 will take place of add(1-1) in the line
sum = num + add(num-1);
it should look like
sum = 1 + 0;
the function add(num) should terminate now, after assigning 1 to variable sum.
Two main questions.
No value should rise up for sum = 2 + add(2-1), as in the previous step no value is returned. for add(1), after getting value from add(0), summation of 1 and returned value is stored in variable sum and then exits out of function body.
Every time recursion occurs new variable sum is declared and initiated to 0, so, I don't see why the computer is storing the values of the sum from previous calls to the function, when instead it should start a fresh new variable sum.
to me, after completion of code, the value of variable sum in add() should be 1.
Please someone, if you can make sense of this code. Let me know. Much appreciated
P.s: you can try this on any online C compiler as well. Here is the code:
#include <stdlib.h>
#include <stdio.h>
int add(int num);
int main(){
int number,sum;
printf("enter a number of your choice: ");
scanf("%d",&number);
sum = add(number);
printf("SUM = %d",sum);
}
int add(int num){
int sum = 0;
if(num != 0)
sum = num + add(num-1);
else
return sum;
}
sum = add(number);
Using the return value of a function that flowed off the end without explicitly returning a value is undefined behavior. UB means anything is allowed to happen, including giving you the (false) illusion that a variable is "storing value from previous recursion runs". Quoting from C11 6.9.1/12:
If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.
A function declared to return an int must always return a value (i.e. an int value). Your code doesn't.
int add(int num){
int sum = 0;
if(num != 0)
// If the execution gets in here
sum = num + add(num-1);
else
return sum;
// it will continue here (when the recursion ends).
// And here it is WITHOUT a returned value - that's bad.
}
You probably want:
int add(int num){
int sum = 0;
if(num != 0)
sum = num + add(num-1);
return sum;
}
or
int add(int num){
if(num != 0)
return num + add(num-1);
else
return sum;
}
or (more clear and secure):
int add(int num){
if(num <= 0)
{
return 0;
}
return num + add(num-1);
}

Factorial as a sum of consecutive number

I was recently solving a problem "No. of ways to express factorial of a number as sum of consecutive number"
My solution is :
int fact_as_sum(int n) { // n is the number whose factorial need to be taken
long int fact=1;
int temp=0,count=0;
for(int i=n;i>0;i--){
fact*=i;
}
printf("%d\n",fact);
for(int i=fact/2;i>0;i--) {
int j=i;
temp=fact;
while(temp>=0) {
if(temp==0) {
count++;
break;
}
else
temp-=j;
j--;
}
}
return count;
}
The solution works correct till small no. of 10!.
But my solution has high complexity.
Can anyone suggest a less complex solution ?
Thanks
Ok, so this problem tickled my brain a lot, so first of all thank you for that, I love to solve these kind of problems!
I started with a math analysis of the problem in order to find the best implementation, and I came up with this solution:
By defining n as the factorial result number, m the number of sums to be performed and x the starting number for the addition, it all breaks down to the following formula:
.
This can now be simplified, resulting in the following formula:
.
That can be also simplified, giving the following result:
.
Solving for x (the starting number for addition), results in:
.
It is now possible to iterate for all the values of m to find the wanted x value. the lower bound for m is for sure 0, it is not possible to add a negative quantity of numbers! The top bound can be found by noticing that x should be a positive number, it would have no sense to consider negative values that will be nulled by the corresponding positive part! This gives the following result:
That yields the following result:
The negative value of m is discarded as previously said.
This translates in the following C code:
#include <stdio.h>
#include <math.h>
void main() {
int fact = 8; //select the wanted factorial to compute
float n = 1;
int i;
float x;
float m;
printf("calculating %d factorial...\n", fact);
for (i = 2; i < fact + 1; i++) {
n *= (float)i;
}
printf("the factorial result is %d\n", (int)n);
printf("calculating the sum of consecutive numbers...\n");
//compute the maximum number of iterations
int maxIter = (int)((-1 + sqrt(1 + 8 * n)) / 2);
for (i = 0; i < maxIter; i++) {
m = (float)i;
//apply the formula
x = (n / (m + 1)) - (m / 2);
if (x - (float)((int)x) == 0) {
printf("found a correct sum!\n");
printf("the starting number is: %d\n", (int)x);
printf("the number of sums is: %d\n", i + 1);
}
}
}
I've tried this solution on a couple of values and wrote the code for the test, the results seem right. There is an issue with the factorial though, since the factorial reaches very high values quickly, memory needs to be managed better.
Hope I gave an interesting solution, I had fun solving it!
Please correct in case there are problems with this solution.
Sure. I may try and give a simpler solution for finding the count: replace
temp = fact;
while(temp>=0) {
if(temp==0) {
count++;
break;
}
else
temp-=j;
j--;
}
by
if ( fact % j == 0 )
count++;
. This also means you don't need temp, since you can use the remainder operator (%) to check for whether j is a divisor (that's what you tried to do in that while loop, right?).
Fist of all, your code has a bug.
1. You need to change i=fact/2 in for loop to i=(fact+1)/2;
2. You need to add j > 0 condition in while loop to prevent infinite loop. Because for example temp-(-1) will increment temp.
Fixed code:
for(long int i=(fact+1)/2; i>0; i--) {
long int j=i;
temp=fact;
while(j > 0 && temp > 0) {
temp-=j;
j--;
if(temp == 0) {
count++;
break;
}
}
}
As of your question, it can be done in O(sqrt(2*N)) time. Here are some understandable, clean answers:
long int count = 0;
for (long int L = 1; L * (L + 1) < 2 * fact; L++) {
float a = (1.0 * fact-(L * (L + 1)) / 2) / (L + 1);
if (a-(int)a == 0.0)
count++;
}
https://www.geeksforgeeks.org/count-ways-express-number-sum-consecutive-numbers/
https://math.stackexchange.com/questions/139842/in-how-many-ways-can-a-number-be-expressed-as-a-sum-of-consecutive-numbers

the sum of divisor (other than itself)

Write a program that reads integer from the keyboard and, on the output, writes the sum of the divisors of n (other than itself).
I've created a method that finds the sum of divisor. Using the while statement I can have up to 10 integers entered by the user until EOF. In the while statement I had sum = the output of sum_divisor and print out sum.
If I enter 0 0 0 4 5 6 12 then the output should be 0 0 0 3 1 6 16.
The output I get is 0 0 0 3 4 10 26. How can I make it so that it doesn't add the sum_divisor to the previous sum?
#include <stdio.h>
int sum_divisor(int x);
int main()
{
int x;
int sum;
printf("Enter up to 10 positive integer ending with EOF:\n");
while((scanf("%d",&x)) != EOF){
sum = sum_divisor(x);
printf("%d ", sum);
}
return 0;
}
int sum_divisor(int x){
int i;
int sum;
if(x<= 0){
sum = 0;
}
else{
for(i=1;i<x;++i)
{
if(x%i==0)
sum += i;
}
}
return sum;
}
You should initialise sum to zero within your function. Otherwise, it will be set to some arbitrary value and the else block will have an arbitrary result.
In other words, change:
int sum;
into:
int sum = 0;
Of course, once you've done that, there's no need to explicitly do anything for the case where x is less than one. In addition, the initial if is superfluous since the for body won't execute when x is less than one, so you could get away with something like:
int sumDivisors (int x) {
int i, sum = 0;
for (i = 1 ; i < x; i++) {
if ((x % i) == 0) {
sum += i;
}
}
return sum;
}
As an aside, the values you're actually seeing without the initialisation are accumulating:
0 -> 0
0 -> 0
0 -> 0
3 -> 3
1 -> 4
6 -> 10
16 -> 26
This is almost certainly because each call to the function is reusing the same memory for the stack frame, including the variable sum, so sum is simply being added to each time (that the passed-in parameter is greater than one).
However, that's simply an artifact of the implementation, it's not guaranteed by the standard, which states quite clearly in C11 6.7.9 Initialization /10:
If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.
In other words, don't rely on this.
And, as yet another aside, it's a mathematical given that, if a number n divides evenly by a, it also divides evenly by n/a. You can use this to your advantage to possibly make the code a little more efficient (though, as with all optimisations, you should measure, not guess).
Since you're discounting the number itself as a divisor, you have to treat the divisor 1 as a special case. You also have to treat perfect squares as a special case so that you don't add the square root twice.
The following code would be a good starting point for that:
int sumDivisors (int x) {
int i, sum;
// Always return zero for -inf..1 inclusive.
if (x < 2)
return 0;
// Otherwise, 1 is factor, search for others
// up to but NOT including sqrt(x).
for (i = 2, sum = 1 ; i * i < x; i++) {
if ((x % i) == 0) {
sum += i;
sum += x / i;
}
}
// Add in sqrt(x) ONCE for a perfect square.
if (i * i == x)
sum += i;
return sum;
}
When you call sum_divisor inside the while statement the same block of stack is being allocated, and therefore the sum variable is allocated in the same position on every call. At the first call the value is 0,(but not necessarily), the next time the value will be the one you calculated on the previous call.
int sum = 0; should fix it.
int sum_divisor(int x){
if(x <= 0) { // you do not need to even alocate space for i an sum if x < 1.
return 0;
}
int i = 1;
int sum = 0;
for(i=1;i<x;++i)
{
if(x%i==0)
sum += i;
}
return sum;
}

Confused in understanding recursion

I am little bit confused with the following code to find height of the tree and the code to find sum of n nos recursively, which is below this. What does the lheight and rheight store, depending on the number of recursions it makes?
int height(struct node* node)
{
if (node==NULL)
return 0;
else
{
lheight = height(node->left);
rheight = height(node->right);
if (lheight > rheight)
return(lheight+1);
else return(rheight+1);
}
}
Here is one more clarification, it prints the sum of n nos:
int findSum(int n){
int sum;
if(n <= 0) return 0;
else sum = n + findSum(n-1);
return sum;
}
if I change this to:
int findSum(int n){
int sum;
if(n <= 0) return 0;
else sum = findSum(n-1); // here
return sum;
}
It prints the output as 0. Why doesn't this return the number of recursions, if the above tree code does?
Your second recursion is equivalent to
sum = findSum(n-1) = findSum(n-2) = findSum(n-3) = ..... = findSum(0) = 0;
If you want that the second recursion return the number of recursion then use
sum = 1 + findSum(n-1);
the lheight and rheight return the tree level because in the recursion function there is incrementation with 1 for both variables:
return(lheight+1);
else return(rheight+1);
If you want your findsum() do the samething as your height() recusrsion you should return sum+1 and not sum at the end of your findsum() function:
int findSum(int n){
int sum;
if(n <= 0) return 0;
else sum = findSum(n-1);
return sum+1; //<<<<< should return sum +1 as you did in the height function
}
the return sum+1; will be evaluated only if the
findSum(n-1); findSum(n-2); findSum(n-3); ...findSum(0); are called.
when findSum(0) is called, it will return 0;
when findSum(1) is called, it will execute sum=findSum(0) (so sum
= 0) and then return sum+1 (1);
when findSum(2) is called, it will execute sum=findSum(1) (so sum
= 1) and then return sum+1 (2);
when findSum(3) is called, it will execute sum=findSum(2) (so sum
= 2) and then return sum+1 (3);
.
.
.
when findSum(n) is called, it will execute sum=findSum(n-1) (so
sum = n-1) and then return sum+1 (n);
I suggest you do this on paper. If we do it for the (unmodified) findSum function it will be like this:
Lest say you call it like
findSum(2);
This will read to the following steps:
1: sum = 2 + findSum(2 - 1);
Which will call findSum(1) which leads to
2: sum = 1 + findSum(1 - 1);
which calls findSum(0) which is
3: return 0;
Now we go back up one step to 2:
2: sum = 1 + 0;
and back up once more:
1: sum = 2 + 1
So the result of findSum(2) is 3.
lheight and rheight are nothing but the heights of left subtree and right sub tree resp at a particular level of the Tree.
This can be made easier to understand if you take up an example.
In the attached figure, we start off with root F. We check if the root is null, or not, and since it is not , we find the height of right subtree and left subtree, and whichever is more, we add one more to it and return. This is how we would do it manually.
Now while finding the height of left sub tree, we recursively go down, till we reach a null pointer, at which point we return 0. Hence the value return for A is 0, and then we check the height of right sub tree (i.e D) and for that we recursively go down till C, for which 0 is returned, and similarly 0 is returned for 0. We add one to the max of C and E (i.e 0) and return it to the upper level. Now we have value 0 for A and 1 for D, we add one to the max ( i.e. 1) and return it to the upper level. Which is the height of left subtree of the complete tree, similarly the height of right subtree is calculated.

Resources