I'm trying to optimize a function that, given an array of N int, return the minimum difference between an element and the previous one. Obviously the function is just for array with a dimension >=2.
For example, given the array {2,5,1}, function returns -4 .
I tried to write my code, but I think it is really intricate.
#include <stdio.h>
#define N 4
/*Function for the difference, works because in the main I already gives one difference*/
int minimodiff(int *a, int n, int diff) {
if (n==1) {
return diff;
}
if (diff>(*(a+1) - *a))
return minimodiff(a+1, n-1, *(a+1)-*a);
else return minimodiff(a+1, n-1, diff);
}
int main() {
int a[N]= {1,8,4,3};
printf("%d", minimodiff(a+1, N-1, *(a+1)-*a));
}
I wonder if there is a way to avoid to pass the first difference in main, but doing everything in the recursive function.
I can use as header file stdio.h / stdlib.h / string.h / math.h . Thanks a lot for the help, I hope that this can give me a better understanding of the recursive functions.
minimodiff(a+1, N-1, *(a+1)-*a) is a weak approach to use recursion for it uses a recursion depths of N which can easily overwhelm system resources depth limit. In such a case, a simple loop would suffice.
A good recursive approach would halve the problem at each call, finding the minimum of the left half and the right half. It may not run faster, but the maximum depth of recursion would be log2(N).
// n is the number of array elements
int minimodiff2(const int *a, size_t n) {
if (n == 2) {
return a[1] - a[0];
} else if (n <= 1) {
return INT_MAX;
}
int left = minimodiff2(a, n/2 + 1); // +1 to include a[n/2] in both halves
int right = minimodiff2(a + n/2, n - n/2);
return (left < right) ? left : right;
}
int main() {
int a[]= {1,8,4,3};
printf("%d", minimodiff2(a, sizeof a/ sizeof a[0]));
}
When doing a min calculation, recursive or otherwise, it makes the initial condition simpler if you set the min to the highest possible value. If you were using floating point numbers it would be Infinity. Since you're using integers, it's INT_MAX from limits.h which is defined as the highest possible integer. It is guaranteed to be greater than or equal to all other integers.
If you were doing this iteratively, with loops, you'd initially set diff = INT_MAX. Since this is recursion, INT_MAX is what gets returned when recursion is done.
#include <limits.h>
static inline int min( const int a, const int b ) {
return a < b ? a : b;
}
int minimodiff( const int *a, const size_t size ) {
if( size <= 1 ) {
return INT_MAX;
}
int diff = a[1] - a[0];
return min( minimodiff(a+1, size-1), diff );
}
The recursive approach is a bad idea because extra memory and function calls are used.
Anyway, your question is about avoiding the first difference.
You can use a centinel.
Since the parameter diff is an int variable, it is not possible to obtain a value greater than INT_MAX.
Thus, your first call to minimodiff can be done by giving the value INT_MAX as the argument corresponding to diff.
Besides, the standard header limits.h must be #include'd at top, to make visible the INT_MAX macro.
Related
Below, the purpose of the code is to compute power of an integer.
My friend told me that the time complexity of this algorithm is O(log n).
But, in fact the number of function calls is not equal to logn.
For example, power(2, 9) calls power functions 5 times (including the calling power(2,9)), while power(2, 8) calls power function 4 times (including the calling power(2,8).
Nevertheless the number of bits needed for 8 and 9 are same, the numbers of function calls are different.
Why does this happen? Is this really O(log n) algorithm?
#include <stdio.h>
int power(int a, int n) {
if(n == 0) {
return 1;
}
if(n == 1) {
return a;
}
if (n%2 == 0) {
return power(a*a, n/2);
}else{
return a * power(a, n - 1);
}
}
int main() {
for (int i = 0; i < 15; i++)
printf("pow(%d, %d) = %d\n", 2, i, power(2, i));
return 0;
}
Your implementation is O(logN), but it could be made slightly more efficient.
Note that hereafter, a log is a log base 2.
You have log(n) calls of power(a*a,n/2), and a call to power(a, n-1) for every bit set in n.
The number of bits set in n is at most log(n) +1.
Thus, the number of calls to power is at most log(n)+log(n)+1. For instance, when n = 15, the sequence of calls is
power(15), power(14), power(7), power(6), power(3), power(2), power(1)
log(n)+log(n)+1 = 3+3+1 = 7
Here is a more efficient implementation that has only log(n)+2 calls of power.
int power(int a, int n) {
if(n == 0) {
return 1;
}
if (n&1 == 0) {
return power(a*a, n/2);
}else{
return a * power(a*a, n/2);
}
}
In this case the sequence of calls when n = 15 is
power(15), power(7), power(3), power(1), power(0)
I removed the if (n == 1) condition because we can avoid this test that would be performed log(n) time by adding one call to power.
We then have log(n)+2 calls to power which is better than 2log(n)+1.
The reason why the algorithm remains Ο(lgN) even with the extra calls for the odd number case is because the number of extra calls is bounded by a constant. In the worst case, N/2 is odd at each iteration, but this would only double the number of extra calls (the constant is 2). That is, at worst, there will be 2lgN calls to complete the algorithm.
To more easily observe that the algorithm is Ο(lgN), you can rewrite the function to always reduce the power by half at each iteration, so that at worst case, there are only lgN calls. To leverage tail recursion, you can add a function parameter to accumulate the carried multiplier from the odd N.
int power_i (int a, unsigned N, int c) {
if (N == 0) return c;
return power_i(a*a, N/2, N%2 ? a*c : c);
}
int power (int a, unsigned N) {
return power_i(a, N, 1);
}
The advantage of tail recursion is that the optimized code will be converted into a simple loop by most modern C compilers.
Try it online!
The power function has two base cases: n = 0 and n = 1.
The power function has two recursive calls. Only one of them is made in any given call.
Let's first consider the case when n is even: In that case, the recursive call is made with n / 2.
If all calls would use this case, then you half n in each call down until you reach 1. This is indeed log(n) calls (plus 1 for the base case).
The other case, when n is odd, reduces n only by one. If all calls would end up using this recursive call then the function would be called n times; clearly not logarithmic but linear thus.
But what happens to an odd number when you subtract one from it? It becomes an even number. Thus the feared linear behaviour mentioned above cannot occur.
Worst case is: n is odd, thus use second recursive call. Now n is even, thus first recursive call. Now n is odd, this use second, ... and so on down until n is one. In that case every second call reduces n to n / 2. Therefore you need 2 * log(n) calls then (plus one for the base case).
So yes, this is in O(log(n)). This algorithm is often called binary exponentiation.
Trying to figure out where I am going wrong in this code, I realize I keep getting 1 because that's what am I passing in the function but how else can I do this?
#include <stdio.h>
#include <stdlib.h>
int totalOdd();
int main(){
printf("%d\n",totalOdd(1));
}
int totalOdd(int n){
int odd = n;
if(odd >= 100){
return 0;
}
else{
totalOdd(odd+2);
}
return odd;
}
try this one
one :
#include <stdio.h>
#include <stdlib.h>
int totalOdd(int);
int main(){
printf("%d\n",totalOdd(1));
}
int totalOdd(int n)
{
int odd = n;
if(odd > 100){
return 0;
}
else{
return (n+totalOdd(odd+2));
}
}
in your code , addition was missing
#include <stdio.h>
#include <stdlib.h>
int totalOdd();
int main(){
printf("%d\n",totalOdd(1));
}
int totalOdd(int odd){
if(odd >= 100)
return 0;
return (odd + totalOdd(odd + 2));
}
Not a complete answer, because this sounds like homework, but here’s an example of how to write a very similar function, first recursively, and then a more efficient tail-recursive solution.
#include <stdio.h>
#include <stdlib.h>
unsigned long factorial1(const unsigned long n)
{
/* The naive implementation. */
if ( n <= 1U )
return 1; // 0! is the nullary product, 1.
else
return n*factorial1(n-1);
/* Notice that there is one more operation after the call to
* factorial1() above: a multiplication. Most compilers need to keep
* all the intermediate results on the stack and do all the multiplic-
* ations after factorial1(1) returns.
*/
}
static unsigned long factorial_helper( const unsigned long n,
const unsigned long accumulator )
{
/* Most compilers should be able to optimize this tail-recursive version
* into faster code.
*/
if ( n <= 1U )
return accumulator;
else
return factorial_helper( n-1, n*accumulator );
/* Notice that the return value is simply another call to the same function.
* This pattern is called tail-recursion, and is as efficient as iterative
* code (like a for loop).
*/
}
unsigned long factorial2(const unsigned long n)
{
return factorial_helper( n, 1U );
}
int main(void)
{
printf( "%lu = %lu\n", factorial1(10), factorial2(10) );
return EXIT_SUCCESS;
}
Examining the output of both gcc -O -S and clang -O -S on the above code, I see that in practice, clang 3.8.1 can compile both versions to the same optimized loop, and gcc 6.2.0 does not optimize for tail recursion on either, but there are compilers where it would make a difference.
For future reference, you wouldn’t solve this specific problem this way in the real world, but you will use this pattern for other things, especially in functional programming. There is a closed-form solution to the sum of odd numbers in a range. You can use that to get the answer in constant time. You want to look for those whenever possible! Hint: it is the sum, from i = 0 to 100, of 2 i + 1. Do you remember a closed-form formula for the sum of i from 0 to N? 0, 1, 3, 6, 10, 15, ...? The proof is often taught as an example of a proof by induction. And what happens to a sum from 0 to N when you multiply and add by constants?
As for my example, when I have had to compute a factorial function in a real program, it was for the purpose of computing a probability distribution (specifically, the Poisson distribution) for a simulation, and I needed to calculate the factorial of the same numbers repeatedly. Therefore, what I did was store a list of all the factorials I’d already calculated, and look up any number I saw again in that list. That pattern is called memoization.
As part of a programming assignment, I'm required to write a recursive function which determines the largest integer in an array. To quote the exact task:
Write a recursive function that finds the largest number in a given list of
integers.
I have come up with two solutions, the first of which makes two recursive calls:
int largest(int arr[], int length){
if(length == 0)
return 0;
else if(arr[length - 1] > largest(arr,length -1))
return arr[length];
else return largest(arr,length -1);
}
The second one makes only one, however it uses a static variable n:
int largest(int arr[], int length){
static int n = -1;
if(length == 0)
return n;
else if (arr[length - 1] > n)
n = arr[length - 1];
return largest(arr, length - 1);
}
I was wondering whether it would be considered cheating use static variables for such a task. Either way, which one is considered better form? Is there a recursive method which tops both?
I wouldn't say that it's cheating to use static variables this way - I'd say that it's incorrect. :-)
Imagine that you call this function multiple times on a number of different arrays. With the static variable introduced, the value of n never resets between calls, so you may end up returning the wrong value. Generally speaking, it's usually poor coding style to set things up like this, since it makes it really easy to get the wrong answer. Additionally, if your array contains only negative values, you may return -1 as the answer even though -1 is actually bigger than everything in the array.
I do think that the second version has one nice advantage over the first - it's much, much faster because it makes only one recursive call rather than two. Consider using the first version, but updating it so that you cache the value returned by the recursive call so that you don't make two calls. This will exponentially speed up the code; the initial version takes time Θ(2n), while the updated version would take time Θ(n).
There is nothing cheating using a static inside function, recursive or otherwise.
There can be many good reasons for why to do so, but in your case I suspect that you are coming up with a wrong solution -- in as largest will only work once in the lifetime of the program running it.
consider the following (pseudo) code;
main() {
largest([ 9, 8, 7]) // would return 9 -- OK
largest([ 1, 2, 3]) // would return 9 ?? bad
}
The reason being that your largest cannot tell the difference between the two calls, but if that is what you want then that is fine.
Edit:
In answer to your comment, something like this will have a better big-O notation than your initial code;
int largest(int arr[], int length){
int split, lower,upper;
switch (length) {
case 1: return arr[0];
case 2: if (arr[1]>arr[0]) return arr[1]; else return arr[0];
default:
if (len <= 0) throw error;
split = length/2;
lower = largest(arr,split);
upper = largest(arr+split,length-split);
if (lower > upper) return lower; else return upper;
}
}
Alternatively, the obvious solution is;
int largest(int arr[], int length){
if (length <= 0) thor error;
int max = arr[0];
for (int i=1; i<length; i++)
if (arr[i] > max) max = arr[i];
return max;
}
which has no recursion at all
It is actually a terrible design, because on the second execution of the function does not return a correct result.
I don't think you need to debate whether it is cheating, if it is wrong.
The first version is also incorrect, because you return arr[length] instead of arr[length-1]. You can eliminate the second recursive call. What can you do instead of calling the same function (with no side-effects) twice with the same arguments?
In addition to the excellent points in the three prior answers, you should practice having more of a recursion-based mind. (1) Handle the trivial case. (2) For a non-trivial case, make a trivial reduction in the task and recur on the (smaller) remaining problem.
I propose that your proper base case is a list of one item: return that item. An empty list has no largest element.
For the recursion case, check the first element against the max of the rest of the list; return the larger. In near-code form, this looks like the below. It makes only one recursive call, and has only one explicit local variable -- and that is to serve as an alias for the recursion result.
int largest(int arr[], int length){
if(length == 1)
// if only one element, return it
return arr[0];
else n = largest(arr,length-1))
// return the larger of the first element or the remaining largest.
return arr[length-1] > n ? arr[length-1] : n
}
Is there a recursive method which tops both?
Recursion gets a bad name when with N elements cause a recursion depth of N like with return largest(arr,length -1);
To avoid this, insure the length on each recursion is halved.
The maximum recursive depth is O(log2(N))
int largest(int arr[], int length) {
if (length <= 0) return INT_MIN;
int big = arr[0];
while (length > 1) {
int length_r = length / 2;
int length_l = length - length_r;
int big_r = largest(&arr[length_l], length_r);
if (big_r > big) big = big_r;
length = length_l;
}
return big;
}
A sneaky and fast method that barely uses recursion as finding the max is trivial with a loop.
int largest(int arr[], int length) {
if (length <= 0) return INT_MIN;
int max = largest(NULL, -1);
while (length) {
length--;
if (arr[length] > max) max = arr[length];
}
return max;
}
Need to find the index of a number, that may or may not be present in the array. I tried the below code:
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *lhs, const void *rhs){
return ( *(long long*)lhs - *(long long*)rhs );
}
int main(){
int size = 9;
long long a[] = {16426799,16850699,17802287,18007499,18690047,18870191,18870191,19142027,19783871};
long long x = 17802287;
long long *p = (long long *)bsearch(&x, a, size, sizeof(long long), cmp);
if (p != NULL)
printf("%lld\n", p - a);
return 0;
}
The above code works if the number, in this case 17802287 is present in the array a, but fails if the number is not present in a, e.g. doesn't give any output for x=18802288, I would like to get the index i=5 in that case 5th element onwards the elements are greater than 18802288.
Also the actual array size will have number of elements more than 4 million, would the same code work?
Thanks for the help.
From the man page for bsearch:
The bsearch() function returns a pointer to a matching member of
the array, or NULL if no match is found. If there are multiple
elements that match the key, the element returned is unspecified.
So the function will return NULL if the element in question is not found. If you want to find the first element greater than or equal to the number in question, you'll need to roll your own function to do that.
One of the possible solution can be:
int i, outcome = -1;
for( i = 0; i < size; i++ )
{
if( x == a[i] )
{
outcome = i;
break;
}
}
printf("%d\n", outcome);
You need to write a function that does approximately this:
bsearch_geq (number array low high)
if low is equal to high return high
let halfway be average of low and high
if array[halfway] is equal to number then return halfway
if array[halfway] is greater than number then
return result of "bsearch_geq number array low halfway"
else
return result of "bsearch_geq number array halfway high"
That'll get you 99% of the way, I think, but I'll leave it as an exercise to the reader to figure out the corner cases. The main one I can see is what happens when you get down to just two numbers because the naive "average" may cause infinite recursion.
If you can have multiple occurrences of the same number in the array then you'll need to drop the if array[halfway] is equal]" line.
You should ensure your solution uses tail-recursion for efficiency, but it's not too critical as 4m data-entries only amounts to about 15 recursive calls.
Please consider an Recursive function :
1) int calc(int num)
{
2) sum=sum+num;//sum is a global variable
3) num--;
4) if(num==0)
5) return sum;
6) calc(num);
}
It calculates the sum of an integer .
My teacher told me it's not recursion, but a simple function call, because you need to pass
num-- as an argument and return calc(num--) .
I was shocked, as I knew only one thing when a function call itself, its recursion.
She also gave the reason, that line no. 2 and 3 is stored extra in stack memory.
I have no idea what she was referring to.So after going through stack storage thingy:
Here, I noticed that the function arguments passed are in a recursive way, like n-- in my function.
So that they can be linked to the next function call.
For just this sake, can we term it a simple function call instead of recursion?
The teacher has something quite specific in mind even though what you presented is, technically, recursive. Another form which wouldn't depend upon the global would look something like this:
int calc(int num) // Assume this is valid for non-negative numbers
// In that case, type "unsigned int" would be more appropriate
{
if ( num < 0 )
return -1; // Consider this an error; won't happen in recursive case
if ( num == 0 )
return 0;
return num + calc(num-1);
}
You are correct, recursion is a function that calls itself. PERIOD. There are other points worth separately discussing about global variables, and other good programming practices, but whether you implement the decrement operator in the line of code where you call the function recursively or prior to that point, you are still making a recursive call.
It looks like you're trying to calculate, for a given num, the sum of 0 to num. The calc function really just needs one argument, num, and can then call a helper function calc_num which takes the current number and the running sum:
int calc( int num ) {
return calc_help( num, 0 );
}
Then, calc_help, given a current number, and the sum so far, checks whether num is less than or equal to zero. If it is, then the current running sum is the final sum and can be returned. Otherwise, a recursive call to calc_help is made. The current number for it will be one less than num (so that we're calling calc_help with successively smaller first arguments, getting closer and closer to the case where num <= 0), and the current sum will be sum plus the current number:
int calc_help ( int num, int sum ) {
return num <= 0 ? sum : calc_help( num-1, sum+num );
}
In a language (like Scheme) that performs tail call optimization, this is essentially the following loop. Some C/C++ compilers do perform tail call optimization (e.g., according to Tail recursion in gcc/g++, GCC will optimize tail calls when -O2 is specified), so this isn't entirely a moot point.
int calc( int num ) {
int sum = 0;
while ( num > 0 ) {
sum = sum+num;
num = num-1;
}
return sum;
}
or (if you want to be a bit more obscure):
int calc( int num ) {
int sum = 0;
for ( ; num <= 0; sum+=num, num-- );
return sum;
}
The more naïve recursive implementation that performs the addition of after the recursive call, i.e.,
int calc( int num ) {
return num <= 0 ? num : num + calc( num-1 );
}
can't be optimized in this way.