I have this function:
int max(int arr[], int size)
{
size--;
if(size > 0)
{
int max = max(arr, size);
if(arr[max] > arr[size]) return max;
}
return size;
}
And of course it works. My question is - how does this work? Could anyone explain me this step by step? It's Saturday so maybe somebody has a bit of time :D I especially mean these two lines in if block.
You code is as follows:
1 int max(int arr[], int size){
2 size--;
3 if(size > 0){
4 int max = max(arr, size);
5 if(arr[max] > arr[size]) return max;
6 }
7 return size;
8 }
You call it by passing it array and the size (or length) of that array.
The first important point the code hits is on Line 4, when it calls itself recursively. But notice that on Line 2, the size was decreased by one. Therefore, you can think of size as being an index referring to the element of the array being considered by the current call to the function.
This means that eventually, the size of the array will be down to zero and we will be looking at the first element of the array. At this point Lines 3 through 6 are skipped, and 0 is returned.
When one of the recursive calls returns, we're left back at Line 4.
For the first return, this means that int max = 0;.
Now we are comparing the zeroth element with the first element. We return the index of whichever is greater. The next comparison will be between the second element and whichever of the first two was larger.
This continues until all the recursive calls are returned, at which point the index of the greatest element is returned to the calling function.
Note then, that return size; should be replaced with return 0 to increase clarity.
Lets step through the problem for arr[] = [1,2] which means call max(arr[], 2)
size--; // 2-1 = 1
if(size > 0) //True
{
int max = max(arr, size); //Going into the recursive call
This is the recursive run :
size--; // Now 1-1 = 0
if(size > 0) //False
return size; //0 returned
Now back into the calling function :
int max = 0 //From return
if(arr[max] > arr[size]) //arr[0]>arr[1] which is false
}
return size; //Now, control reaches here and 1 is passed back to the calling scope
}
Let's take this array for example:
int arr[] = { 42, 54, 23 };
max(arr, 3);
This function work by checking the max of the current element against the max of all previous elements. Here is a representation of the stack calls:
max(arr, 3)
max(arr, 2)
max(arr, 1)
return 0
arr[0] (arr[max] = 42) <= arr[0] (arr[size] = 42) => return size (0)
arr[0] (arr[max] = 42) <= arr[1] (arr[size] = 54) => return size (1)
arr[1] (arr[max] = 54) > arr[2] (arr[size] = 23) => return max (1)
NB: It is a bad idea to name both a variable and a function with the same identifier.
Sorry for the poor formatting of the diagram
Related
i want to create a function that take the inputs of an array and its number of values. The function should look through the array and as soon as it sees a ''3 in a row''(e.g { 1 2 3 4 5 5 5 6 7 8}), in this case 5. The function should print the index of the first 5. Im new to coding so im finding it difficult how to begin. Ive made an attempt but dont know how to proceed.
int NewFunction(int array, int numValues){
int i;
int j;
for(i=0;i<numValues;i++){
for(j=i+1;j<numValues;j++){
if(
First of all, you might want to go with a more descriptive name than NewFunction. Also, the array shouldn't be of type int, you're probably looking for a pointer to an int.
Furthermore, you don't need a nested loop like that:
for(i=0;i<numValues;i++){
for(j=i+1;j<numValues;j++){
Imagine doing this by hand, getting a list of about 1000 numbers, trying to find three in a row. How often would you pass through the list? A maximum of once, right? You wouldn't go through the list a thousand times, so neither should your algorithm, therefore you don't need a nested loop here.
What you're looking for is something like this:
int threeInARow(int* array, int numValues) {
int count = 1; // how many numbers in a row were found
int current = array[0]; // the number that we're looking for
int i = 1;
for (; i < numValues; i++) {
if (array[i] == current) {
if (++count == 3) return i - 2;
}
else { // a different number is found: start over
count = 1;
current = array[i];
}
}
return -1; // return a value indicating that no result was found
}
Start with a variable: where have you first seen the last value you saw. Let's call it last, and initialise it at 0. Then iterate index from 1 to the length of the array. If the difference between index and last is 3, return last as the index of the repeating value. If not, check whether index is at length. If so, the search failed. Otherwise, if the value at the current index is different from the value at last, set last to the current index.
Another approach.
#include <stdio.h>
#define ELEMENT 14
int three_in_a_row(int arr[], int n) {
int i, index, count = 0, max = 0;
i = -1;
do {
i = i + 1;
if (arr[i] == arr[i + 1]) {
index = i-1; //because we want the first occurrence
count++;
if (count > max) max = count; // 3 elements in a row means that max must be 3-1
} else
count = 0;
} while (i < n - 2 && max != 3 - 1);
return (max == 2 ? index : -1);// -1 indicates no result
}
int main(void) {
int array[] = {1,10,1,4,4,8,8,8,7,8,8,9,9,2}, index3;
index3 = three_in_a_row(array, ELEMENT);
printf("%d\n", index3);
return (0);
}
This is the code:
char binarySearch(unsigned int target, int* primes, unsigned int size){
int* ptrToArray = primes;
unsigned int first = 0;
unsigned int last = size;
while (first <= last){
unsigned int middle = first + (last - first) / 2;
printf("first: %d, last: %d, middle: %d\n", first, last , middle);
if (ptrToArray[middle] == target){
return 1;
}
if (ptrToArray[middle] < target){
first = middle + 1;
}else{
last = middle - 1;
}
}
return 0;
}
This is the output:
I've been staring at that peace of code for more than one should and still can't figure out where is the flaw.
If middle is 0, as near the end of your debug output, the statement
last = middle - 1
causes an integer overflow; the conditions have to be reworked a bit.
You may get an out of bound when you are looking for an element not in the array, and is bigger than the array, due to allowing keep iteration when last and first equal each other in while (first <= last)
Think of what happens when you send an empty array: size == 0:
first = 0, last = 0, and thus: (first <= last) == true.
Then, middle = 0 + (0 - 0)/2 = 0, and next you access ptrToArray[0], which is out of bound.
The problem is that you define your index variables (first, last, middle) as unsigned int while in your logic, last can in fact become negative. However, in that case, since they're defined as unsigned and because of the way 2's complement representation of negative numbers works, the condition in your while loop is still true.
Take a look at the following example code for illustration:
#include <stdio.h>
int main() {
/* defining the variables as unsigned */
unsigned int first_u = 0;
unsigned int last_u = -1;
if (first_u <= last_u)
printf("less than\n");
else
printf("greater or equal\n");
/* defining the variables as signed */
int first_s = 0;
int last_s = -1;
if (first_s <= last_s)
printf("less than\n");
else
printf("greater or equal\n");
return 0;
}
Other than that, you should use either < in your while-condition or define the initial value of last as size-1. Otherwise, if you're searching for an element that is greater than the last element in your array, you will run out of bounds.
Firstly the negative value of middle is due to overflow (unsigned int).
Also I think you should have : unsigned int last = size-1 because if first becomes equal to last=size the you will use ptrToArray[middle] and middle=size so it will be out of array bounds. This will solve also the case of size =0 mentioned above .
Finally to make your code more easy to read you could write :
middle =(first+last)/2 which is the middle of [first,last] space, and equals to first+(last-first)/2 .
The following is an implementation of the problem from spoj:- http://www.spoj.com/problems/COINS/
#include <stdio.h>
#define ll long long
ll arr[100000];
ll max(ll n)
{
if(n < 49999)// Doubt
{
if(!arr[n])
return arr[n] = max(n/2) + max(n/3) + max(n/4);
else
return arr[n];
}
else
return max(n/2) + max(n/4) + max(n/3);
}
int main()
{
ll n, c = 0, i;
for(i = 0; i < 12; i++) // Also why 12 when the input can be <12
{
arr[i] = i;
}
while(scanf("%lld", &n) != EOF)
{
printf("%lld\n", max(n));
}
return 0;
}
Why does the if condition contain n<49999?
without having examined each possibility, other than the first 20+ values and the max and min values:
MY expectation is
the first 12 entries in the arr[] are pre-calculated to help reduce the depth of a recursion however the dollar value is not the same as the calculated value for those first 12 entries.
for coin values <= 49999, check to see if value already calculated, if not then break the coin into the /2 /3 /4 values and recurse each of those resulting values.
This limit value (49999) could be extended to 100000 as that is the available size of the arr[] array.
the presetting and the saving into the arr[] array are to help reduce execution time taken and the depth of the recursion.
the use of the array is so any previously calculated values (in the posted code, up to 49999) can be immediately returned by the max() function, without further recursion.
I would modify the code slightly for better documentation and robustness and faster execution as follows:
#include <stdio.h>
#include <stdint.h>
#define MAX_ARRAY_LEN (100000)
uint32_t arr[ MAX_ARRAY_LEN ] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
uint32_t max(uint32_t n)
{
if(n < MAX_ARRAY_LEN)
{ // value of 'n' within the range of the learning array arr[]
if(!arr[n] && n)
{ // then learning array arr[] not yet set
return arr[n] = max(n/2) + max(n/3) + max(n/4);
}
else
{ // else learning array arr[] already set for 'this' value of 'n'
return arr[n];
}
}
else
{ // value of 'n' is greater than the learning array arr[]
return max(n/2) + max(n/4) + max(n/3);
}
} // end function: max
int main( void )
{
uint32_t n;
int status;
while( (status = scanf("%u", &n)) == 1 && EOF != status)
{
if( 1000000000 >= n)
{
printf("%u\n", max(n) );
}
else
{
printf(" invalid value entered, must be in the range 0...1 000 000 000\n");
} // end if
} // end while
return 0;
} // end function: main
As far I understand that,
The person who write the code, somehow he found out that (manually) if
the coin less than 12 then result will be itself. so that he use 12.
(check the explanation of the input coin = 2)
And about the recursion function
as we know we can't declare array with 1,000,000,000 size so he try to
use some other value (49999 here) in which size he can create array
and later take the result for the coin in array like arr[12] = 13
(where 12 is coin and 13 is the result) so that he can get the result
without generate for the value by using that array with arr[12] (only)
for coin 12.
Hope you understand.
I currently finished my code. but for some reason my recursive call at the end isn't being triggered? Is there some sort of special code I am missing from this by chance?
int max(int arr[], int start, int end) {
int greatest = arr[start];
if(start < end)
{
if(greatest<arr[start])
{
greatest = arr[start];
}
start++;
max(arr, start, end); // Doesn't seem to be triggering since it only returns 8
}
return greatest;
}
int main()
{
int greatest;
int arr[10] = {8,1,2,3,4,5,6,7,8,9};
int start = 0;
int end = 10;
greatest=max(arr, start, end);
pintf("%d\n", greatest);
}
Only the first call to max - the one located in main - actually assigns its return value to anything. The values returned by the recursive calls are immediately lost; the work they do is meaningless to the end result. You need to assign the result of the recursive call to max to greatest.
Remember that each recursive call opens up a new scope, each with its own version of the greatest variable. The assignments within each recursive call only modify their version of the variable, not the one from the enclosing scope; this means that the version from the very first call is never set to anything after taking the value of arr[0]; and that's the version whose value is returned to main when the outermost call resumes, regardless of the work done in between by the recursive calls.
You also have an unrelated error, which is that you recurse into another call to max (and assign to greatest within that call) before checking whether you've reached the end of the array, which will overflow beyond the end of the array and overwrite the final result with whatever is found there (as Paul points out, you also assign to greatest before making the comparison against the current value, so the comparison is essentially meaningless). You need to move everything inside the checks to make sure this doesn't occur.
Your algorithm is a little messed up. For instance, greatest<arr[start] will never be true, because you just set greatest = arr[start]. Here's a commented working algorithm:
#include <stdio.h>
int max(int arr[], int start, int end)
{
if ( start >= end ) {
/* Shouldn't get here, but return 0 if we do */
return 0;
}
else if ( end - start == 1 ) {
/* Only one element, so it's the maximum by definiton */
return arr[start];
}
else {
/* Find the maximum of the rest of the list... */
int greatest = max(arr, start + 1, end);
/* ...and return the greater of it, and the first element */
return arr[start] > greatest ? arr[start] : greatest;
}
}
int main(void)
{
int arr[] = { 8, 1, 2, 3, 12, 5, 6, 7, 8, 9 };
int start = 0;
int end = 10;
int greatest = max(arr, start, end);
printf("%d\n", greatest);
}
with output:
paul#thoth:~/src/sandbox$ ./max
12
paul#thoth:~/src/sandbox$
Let's go through it with a simple list, {1, 5, 3}. Each indentation level represents one of your recursive function calls. Every time we see max(), we go up a level - every time we see return, we go back a level.
In main(), int greatest = max(list, 0, 3)
In call 1: (end - start == 1) is false
In call 1: int greatest = max(list, 1, 3)
In call 2: (end - start == 1) is false
In call 2: int greatest = max(list, 2, 3)
In call 3: (end - start == 1) is true
In call 3: return arr[2], which is 3
Back in call 2: greatest now equals 3
Back in call 2: arr[1] == 5, which is > 3, so return arr[1], which is 5
Back in call 1: greatest now equals 5
Back in call 1: arr[0] == 1, which is not > 5, so return greatest, which is 5
Back in main(), greatest now equals 5
Remember, every time you see int greatest, that's a different variable that's being created. They all have the same name, but since they're all in separate scopes, they're still all different. The int greatest in call 2, for instance, is completely separate from the int greatest in call 1, just as the int greatest in call 1 is completely separate from the int greatest in main().
EDIT: From the comments, if you want the index of the maximum value as well, this'll do it:
#include <stdio.h>
int max_index(int arr[], int start, int end)
{
if ( start >= end ) {
return 0;
}
else if ( end - start == 1 ) {
return start;
}
else {
int greatest = max_index(arr, start + 1, end);
return arr[start] > arr[greatest] ? start : greatest;
}
}
int max(int arr[], int start, int end)
{
if ( start >= end ) {
/* Shouldn't get here, but return 0 if we do */
return 0;
}
else if ( end - start == 1 ) {
/* Only one element, so it's the maximum by definiton */
return arr[start];
}
else {
/* Find the maximum of the rest of the list... */
int greatest = max(arr, start + 1, end);
/* ...and return the greater of it, and the first element */
return arr[start] > greatest ? arr[start] : greatest;
}
}
int main(void)
{
int arr[] = { 8, 1, 2, 3, 12, 5, 6, 7, 8, 9 };
int start = 0;
int end = 10;
int greatest = max(arr, start, end);
int index = max_index(arr, start, end);
printf("Greatest value is %d at index %d\n", greatest, index);
}
output:
paul#thoth:~/src/sandbox$ ./max
Greatest value is 12 at index 4
paul#thoth:~/src/sandbox$
I believe the recursive call is being triggered, but isn't doing what you want. you initialize greatest to arr[start] (in this case 8), and never assign anything else to it, so of course your function is returning 8. Instead, it seems like your function should return arr[start] if start >= end, and otherwise should return either arr[start] or max(arr, start+1, end), whichever is larger.
Consider this code, which computes the maximum element of an array.
#include <stdio.h>
int maximum(int arr[], int n)
{
if (n == 1) {
return arr[0];
} else {
int max = maximum(arr, n-1);
printf("Largest element : %d\n", max);
return 5; // return arr[n-1] > max ? arr[n-1] : max;
}
}
int main()
{
int array[5] = {5, 23, 28, 7, 1};
printf("Maximum element of the array is: %d", maximum(array, 5));
return 0;
}
Why is the else block called four (4) times?
The function is recursive, thus it will be called multiple times.
When you first start, n=5. It will take the else block (n is not 1).
Then, you call maximum again with n-1 (n=4). Again, the else block is taken.
All told, the function is called 4 times before n reaches 1, whereupon it takes the if block and returns ar[0].
As others have mentioned, the function as written will not return the maximum value of the list. Curiously, it seems to always return 5 unless the list array size is 1, in which case it returns the value of that element.
Instead, a recursive approach would typically involve splitting the list in half each time, then returning the max of each pair when the list finally broken into pairs of elements.
That is what it is coded to do...
Take a look:
from main we call maximum with 5, then in the else we call the function again with n-1.
maximum(array, 5) //first call from main, hit the else n=5, so recall with n-1
maximum(ar, 4) //second call from maximum, hit the else n=4, so recall with n-1
maximum(ar, 3) //third call from maximum, hit the else n=3, so recall with n-1
maximum(ar, 2) //fourth call from maximum, hit the else n=2, so recall with n-1
maximum(ar, 1) //fifth call from maximum, n==1 now so do the if and return 5
A possible recursive solution is to compare the previous and the current element.
#include <stddef.h>
static int max(int a, int b) {
return a > b ? a : b;
}
int max_array(int *p, size_t size)
{
if (size > 1) return max(p[size-1], max_array(p, size-1));
else return *p;
}
Actually it is called only 4 times.
The recursion rule, as you declared it is:
if n==1, return ar[0] else return the maximum of n-1 elements.
So, the else part is being called for 5, 4, 3 and 2.
However, this recursion is not good enough. As your function is called n-1 times, you only pay the overhead of recursion (stack for example) but you get no advantage over iteration.
If you really want recursion for this task, try to divide the array to 2 and pass each half to the recursive function.
simple pseudo code (not handling odd numbers correctly):
int max(int arr[], int n)
{
if (n<=1)
return arr[0];
return MAX(max(arr, n/2), max(arr+n/2, n/2));
}
int maximum(int ar[], int n)
{
int max;
if(!n)
return ar[n];
max =maximum(ar,n-1);
return ar[n]>max?ar[n]:max;
}