Related
Given a number N and a sorted array A, design an algorithm - using the Divide and Conquer approach - to check if there exist index i and index j such that A[i]*A[j] == N (return 1 if present, 0 if not).
I'm having a hard time proceeding in the required (recursive) way. I think I figured out only a part of one possible solution, but even there I'm not a 100% sure if it's correct: I thought that if the product between the first element and the central element of the array is greater than N, then the numbers I'm looking for (if present) are certainly in the first half of the array, so I can recursively call the function on that part, like so (I'm using C):
int productN(int A[], int i, int j, int N){
// missing base case
int m = (i+j)/2;
if(A[i]*A[m] > N){
return productN(A, i, m, N);
} else{
// do something else
}
}
int main(){
int A[]={1, 2, 3, 4, 5};
printf("%d\n", productN(A, 0, 4, 15)); // initial value for i and j are the first and last index of the array
return 0;
}
Apart from that, I'm stuck, I can't even think of a base case, so any help will be greatly appreciated, thanks.
Edit:
Based on your very helpful answers, using binary search, I think I got it:
int productN(int A[], int i, int j, int N){
int m = (i+j)/2; // central element of the current array
int x;
for(x=i; x<=m; x++){
if(N%A[x]==0 && binarySearch(A, m, j, N/A[x]))
return 1;
}
if(i!=j){
if(productN(A, i, m, N) || productN(A, m+1, j, N))
return 1;
}
return 0;
}
Is it good? Can it be better?
Edit: it's been a while now since I asked this question, but I wrote another solution, simplier to read. I'll leave it here in case anyone is interested.
int productN(int A[], int i, int j, int N, int size){
if(i==j){ // base case
if(N%A[i]==0)
return binarySearch(A, 0, size-1, N/A[i]);
else
return 0;
}
int m = (i+j)/2;
if((N%A[m])==0){
if(binarySearch(A, 0, size-1, N/A[i]))
return 1;
}
return productN(A, i, m, N, size) || productN(A, m+1, j, N, size);
}
Using Divide and Conquer, you can use an approach similar to merge sort algorithm. As the comments suggest, there are easier approaches. But if Divide and Conquer is a must, this should suffice.
(I'm not proficient in C, so I'll just write the algorithm)
def productN(arr):
x = len(arr)
left_half = arr[0:x/2]
right_half = arr[x/2:]
if productN(left_half) or productN(right_half):
return True
for i in left_half:
if N%i==0 and binary_search(right_half, N/i):
return True
return False
So I have a task in my training that sounds like this:
Write a subprogram that will recursively find the maximum element from an array and also write the main function to call it.
What I failed to fully understand is what recursion is. I wanted to ask you guys if my code is recursive or not. And if not what changes should I make/ what recursion really means?
#include <stdio.h>
int find_maximum(int[], int);
int main() {
int c, array[100], size, location, maximum;
printf("Input number of elements in array\n");
scanf("%d", &size);
printf("Enter %d integers\n", size);
for (c = 0; c < size; c++)
scanf("%d", &array[c]);
location = find_maximum(array, size);
maximum = array[location];
printf("Maximum element location = %d and value = %d.\n", location + 1, maximum);
return 0;
}
int find_maximum(int a[], int n) {
int c, max, index;
max = a[0];
index = 0;
for (c = 1; c < n; c++) {
if (a[c] > max) {
index = c;
max = a[c];
}
}
return index;
}
Thank you all for your time!
Problems that are well-suited to recursion can be broken down into smaller, simpler subproblems. This is one of the things that gives recursion its power. When trying to use recursion to solve a problem, it usually seems best to try to break the problem down into simpler subproblems in finding your way to a solution.
You might notice that in finding the maximum value stored in an array, it is either the value of the first element, or the maximum value of the remaining elements. This breaks the problem into two parts: if the first element is larger than any remaining elements, you are done; otherwise, you must continue and see if the next element is larger than the remaining elements. In code, this might look like:
int max_in(size_t rest_sz, int *rest)
{
int curr_val = rest[0];
if (rest_sz == 1) {
return curr_val;
}
int max_in_rest = max_in(rest_sz-1, rest+1);
return curr_val > max_in_rest ? curr_val : max_in_rest;
}
Here, there is a base case: if rest_sz is 1, there is no need to look further; the value of first element (curr_val = rest[0]) is the maximum, and that value is returned. If the base case is not satisfied, execution of the function continues. max_in_rest is the result from the recursive function call max_in(rest_sz-1, rest+1). Here rest_sz-1 indicates the number of elements remaining in the portion of the array indicated by rest+1. In the new function call, the base case is met again, and eventually this case will be true since rest_sz is decremented with each recursive call. When that happens, the value of curr_val in the current stack frame will be returned; note that this value is the value of the last element in the array. Then, when the function returns to its caller, max_in_rest in that frame will get the returned value, after which the larger of curr_val or max_in_rest is returned to the previous caller, and so on, until finally control is returned to main().
Using pencil and paper to diagram each function call, the values of its variables, and what is returned would help to understand exactly how this recursion works.
You can apply the same method to solving the problem of finding the index of the maximum value of an array. In this case, if the value of the first element is greater than the value of any remaining elements, then the index of the maximum element is the index of the first element; otherwise the index of the maximum element is the index of the maximum value of the remaining elements. In code, this might look like:
size_t find_max_r(int arr[], int *rest, size_t rest_sz, size_t curr_ndx)
{
if (rest_sz == 1) {
return curr_ndx;
}
int curr_val = arr[curr_ndx];
size_t max_in_rest_ndx = find_max_r(arr, rest+1, rest_sz-1, curr_ndx+1);
int max_in_rest = arr[max_in_rest_ndx];
return curr_val >= max_in_rest ? curr_ndx : max_in_rest_ndx;
}
There is just a little more information to keep track of this time. Here, if the base case is satisfied, and rest_sz is 1, then there is no reason to look further, the current index curr_ndx is the index of the maximum value. Otherwise, find_max_r() is recursively called, with rest incremented to point to the remaining elements of the array, and rest_sz suitably decremented. This time, curr_ndx is keeping track of the current index with respect to the original array, and this value is passed into each function call; also, a pointer to the first element of the original array, arr, is passed into each function call so the index value curr_ndx can access the values from the original array.
Again, when the base case is reached, the current position in the array will be the end of the array, so the first elements to be compared in the return statement will be towards the end of the array, moving towards the front of the array. Note that >= is used here, instead of > so that the index of the first maximum value is returned; if you instead want the index of the last maximum value, simply change this to >.
Here is a complete program. Note the use of the helper function find_max() to call the recursive function find_max_r(), which allows the caller to use a function with the same signature that the posted code uses (except for the use of size_t types, which is really the correct type for array indices):
#include <stdio.h>
int max_in(size_t sz, int *rest);
size_t find_max(size_t sz, int arr[]);
size_t find_max_r(int arr[], int *rest, size_t rest_sz, size_t curr_ndx);
int main(void)
{
int array[] = { 2, 7, 1, 8, 2, 5, 1, 8 };
size_t array_sz = sizeof array / sizeof array[0];
int max_val = max_in(array_sz, array);
printf("Maximum value is: %d\n", max_val);
size_t max_ndx = find_max(array_sz, array);
printf("Maximum value index: %zu\n", max_ndx);
return 0;
}
int max_in(size_t rest_sz, int *rest)
{
int curr_val = rest[0];
if (rest_sz == 1) {
return curr_val;
}
int max_in_rest = max_in(rest_sz-1, rest+1);
return curr_val > max_in_rest ? curr_val : max_in_rest;
}
size_t find_max(size_t sz, int arr[])
{
int *rest = arr;
return find_max_r(arr, rest, sz, 0);
}
size_t find_max_r(int arr[], int *rest, size_t rest_sz, size_t curr_ndx)
{
if (rest_sz == 1) {
return curr_ndx;
}
int curr_val = arr[curr_ndx];
size_t max_in_rest_ndx = find_max_r(arr, rest+1, rest_sz-1, curr_ndx+1);
int max_in_rest = arr[max_in_rest_ndx];
return curr_val >= max_in_rest ? curr_ndx : max_in_rest_ndx;
}
Program output:
Maximum value is: 8
Maximum value index: 3
Think of calculating the maximum number in an array as the number which will be maximum of the first element and the maximum of the remaining elements of the array. Something like: max(first_elem, max(remaining_elems)).
The actual recursive function: find_max quite simple, if there is just a single element in the array, that element is returned. Otherwise, we get the maximum of the first element and the remaining elements of the array.
#include <stdio.h>
// function to find the max of 2 numbers
int max(int x, int y)
{
return (x > y) ? x : y;
}
// the recursive function
int find_max(int *p, int n)
{
if (n == 1) return *p;
return max(*p, find_max(p + 1, n - 1));
}
int main(void)
{
int arr[] = {23, 3, 11, -98, 99, 45};
printf("max: %d\n", find_max(arr, sizeof arr / sizeof arr[0]));
}
No, your code does not use recursion. Recursion is when a function calls itself, or calls another function which leads to a call to itself again.
You can change your code like this to have a recursive, stateless function that can determine the maximum value of the array.
int find_maximum(int a[], int n) {
return find_maximum_r(a, 0, n);
}
int find_maximum_r(int a[], int index, int n) {
if (index + 1 == n) {
return a[index];
}
int maxRight = find_maximum_r(a, index + 1, n);
return a[index] > maxRight ? a[index] : maxRight;
}
No, your code is recursive only if you call the function find_maximum from itself directly or indirectly.
As your function is trying to get not only the maximum value, but also the position in the array, I have modified slightly the interface to return the reference (that is, a pointer to the value) so we can infer the position of the array element directly from the subtraction of element pointers. This way, I can pass to the function the array pointer directly and the array size, and then divide the array in two halves, and applying the same function to the two halves (it can be demonstrated that if some element is the maximum value of the array, it has to be greater than or equal to each half's maximum) For the same reason, I have modified some of the variables defined in your main() function, to allow for references to be used:
max.c
#include <stdio.h>
#include <assert.h>
int *find_maximum(int a[], int n); /* return a reference pointer to the maximum value */
int main() {
int c, array[100], size, *location, /* location must be a pointer */
maximum;
printf("Input number of elements in array\n");
scanf("%d", &size);
assert(size >= 1);
printf("Enter %d integers\n", size);
for (c = 0; c < size; c++)
scanf("%d", &array[c]);
location = find_maximum(array, size);
maximum = *location; /* access to the value is granted by pointer dereference */
printf("Maximum element location = %td and value = %d.\n",
location - array, /* pointer difference gives the array position */
maximum);
return 0;
} /* main */
/* somewhat efficient recursive way of a divide and conquer method
* to get the maximum element reference. */
int *find_maximum(int a[], int n)
{
if (n == 1) return a; /* array of 1 element */
int *left = find_maximum(a, n/2), /* left half begins at a
* and has n/2 elements */
*right = find_maximum(a + n/2, (n+1)/2); /* right half begins
* at a + n/2, and
* has (n+1)/2
* elements */
return *left > *right
? left
: right;
} /* find_maximum */
As you see, I have to divide by two, but as I have arrays of any length, I have to be careful not to leave out any element in the next step. This is the reason for using an array of (n+1)/2 elements in the right half of the recursive call to the function. I include n/2 elements in the first half (rounding down), I have to include (n+1)/2 elements (rounding up) in the right half, to be sure that I include all the array elements in the two halves.
First of all, recursion means - function calling itself.
And what you've written is not recursive function. I'll post the most simple way to find biggest or largest element in an array, using recursion.
#include<stdio.h>
#define N 5
int biggest(int num[], int n, int big)
{
if(n < 0)
return big;
else
{
if(big < num[n])
big = num[n];
return biggest(num, --n, big);
}
}
int main()
{
int a[N], i;
printf("Enter %d integer number\n", N);
for(i = 0; i < N; i++)
scanf("%d", &a[i]);
printf("Biggest Element in the array: %d\n", biggest(a, N - 1, a[0]));
return 0;
}
Source: C Program To Find Biggest Element of An Array using Recursion
NO it is not recursive function
to know about recursion this link is very useful https://www.khanacademy.org/computing/computer-science/algorithms/recursive-algorithms/a/recursion/
to make a recursion function to solve your problem try this
you can try this pseudo code declare your array global and a max=0 global and size global
int find_maximum(int i)
{
if (i == size )
return max;
else if ( max < array[i])
max =array [i];
return find_maximum(i+1);
}
where i is the array index
No, your program is certainly not recursive. As the definition, recursive function must call itself with a terminating condition.
Please read TutorialsPoint about recursion in C.
Update on #JonathanLeffler's comment:
Please note that the output in the reference will overflow.
I tried to write a function that performs binary search. the code I wrote is as follows:
int binarySearch (int num[], int value, int left, int right)
{
if (left > right)
return -1;
else
{
int middle = (left+right)/2;
if (num[middle] = value)
return middle;
else
{
if (value < num[middle])
return binarySearch(num, value, left, middle-1);
else
return binarySearch(num, value, middle+1, right);
}
}
return 0;
}
void main()
{
int num[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int result;
result = binarySearch(num,6,0,15);
printf("The result is: %d", result);
}
While trying to debug it I found out the num[] array doesn't being send into the function. When I look at the array outside of the function it contains 16 numbers. when I jump into the function with F11 the array that arr[] receives contains only 0. Nothing I try seems to solve it. Does someone understands what goes wrong?
Thank you very much,
Robert
In binarySearch function num acts as pointer. So, when you debug, it shows only first value (0) pointed by num.
If you want to pass a single-dimension array as an argument in a function, you would have to declare a formal parameter in one of following three ways and all three declaration methods produce similar results because each tells the compiler that an integer pointer is going to be received.
int func(int arr[], ...){
.
.
.
}
int func(int arr[SIZE], ...){
.
.
.
}
int func(int* arr, ...){
.
.
.
}
However, by mistake you did an assignment instead of comparison, in if (arr[middle] = value).
Thanks !!!
Arrays cannot be sent as function arguments in C. Arguments declared as array are converted to pointers that point at the element of array, according to N1570 6.7.6.3.
Arrays used in expressions are automatically converted to pointers pointing the first element of the array except for some exceptions such as operands of unary & operator and sizeof operator, according to N1570 6.3.2.1.
Therefore, the acutual type of arr is int* and it seems that the debugger recognized only the elemente pointed at directly by the pointer.
There are a few syntax errors that are stopping your code from working. (e.g. while loop has a ";" ignoring the loop content).
The biggest issue with your code is that you calculated the middle index incorrectly.
Incorrect:
middle = (left + right) / 2;
Correct:
middle = ((right - left) / 2) + left;
You need to subtract to get the actual distance between left and right, then divide by 2 to get the middle. Then add back to the smaller value to reach the middle between the left and right sides.
Here is your code with syntax fixed and a mid function to make things easier. Enjoy.
int mid(int min, int max) {
return ((max - min) / 2) + min;
}
int binarySearch(int value, int arr[], int left, int right)
{
int middle = mid(left,right);
while (left < right)
{
if (arr[middle] == value)
return middle;
if (value < arr[middle])
middle = mid(left, middle);
else
middle = mid(middle, right);
}
return -1;
}
You should just use the int * syntax in your function signature. C will handle this by passing a pointer to the first element of the array. In C, arrays are not passed like they are in Java or other high-level languages.
Note that you can still use the [] operator on a pointer, similarly to an array. In your example, you can refer to the 2nd element of the array by using this syntax:
int x = num[1]; /* get the second element of the num array */
This would be the updated function (copied "as is" from the original), with only changes made specific to the array usage:
int binarySearch (int *num, int value, int left, int right)
{
if (left > right)
return -1;
else
{
int middle = (left+right)/2;
if (num[middle] = value)
return middle;
else
{
if (value < num[middle])
return binarySearch(num, value, left, middle-1);
else
return binarySearch(num, value, middle+1, right);
}
}
return 0;
}
void main()
{
int num[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int result;
result = binarySearch(num,6,0,15);
printf("The result is: %d", result);
}
One additional thing that you typically need to do is pass the length of the array as a separate argument. This is so that the function can know how many elements are in the array. C does not automatically pass the array length the pointer to the first array element, so you have to take care of it manually.
The OP's code does not use the length of the array, so length is not added to that function signature. However, requiring access to the length of a C array and passing it to a function is so common that it bears an clear example. Consider this example function to sum the values of an array:
int summation_function(int * array, size_t length)
{
int sum = 0;
size_t i = 0;
for (; i < length; ++i) {
sum += array[i];
}
return sum;
}
To call summation_function, you can do something like this:
int values[] = {1,2,4,8,16,32};
int sum = summation_function(values, sizeof(values)/sizeof(int));
printf("Summation of the values [1,2,4,8,16,32] is %d\n", sum);
Note the use of this code in this example:
sizeof(num)/sizeof(int)
What this does is find the allocated number of bytes in the array (the sizeof(num)) and divide by the number of bytes in an int (the sizeof(int)). The result is the exact number of elements in the array. With this, you can avoid hard-coding array lengths. This code is idiomatic of C array handling, so it becomes second nature to understand it after the first few uses.
I'm having trouble solving this problem. I'm supposed to sort then search an array (through binary search) but I'm having trouble in how to get the size of an array I think.
int binarySearch( int Arr[], int value)
{
int low = 0;
int high =sizeof(Arr)/sizeof(int);
int mid = (low+high)/2;
printf("%d\n",high);
while (low <= high && Arr[mid] != value)
{
if( Arr[mid] < value)
{
low = mid+1;
}
else
{
high = mid-1;
}
mid = (low+high)/2;
}
if (low > high)
{
mid= -1;
}
return mid;
}
int main()
{
BubbleSort( Array, 10);
int pos = binarySearch(Array, 3);
printf("The sorted array is: ");
PrintArray( Array, 10);
printf("\n");
printf("Now lets look for number 3\n");
printf("The number was located in space %d\n", pos);
PrintArray( Array, 10);
}
But all I keep getting is:
./search
2 \\This is where I wanted to see what I was getting as the size of my array, 2???
The sorted array is: 0 1 2 3 4 5 6 7 8 9
Now lets look for number 3
The number was located in space -1
0 1 2 3 4 5 6 7 8 9
Using sizeof on an array which is a parameter to a function won't work as you expect.
When an array is passed to a function, it decays to a pointer to the first element of the array.
So this:
int binarySearch( int Arr[], int value)
Is the same as this:
int binarySearch( int *Arr, int value)
And sizeof(Arr) is the same as calling sizeof(int *).
You need to pass the size of the array as a separate parameter to your function.
What others have said about sizeof is correct... but there's even more information binarySearch needs to do its job:
int binarySearch( int Arr[], int low, int high, int value)
{
int mid = (low+high)/2;
...
initially called as
binarySearch (Array, 0, 9, 3);
or better yet
binarySearch (Array, 0, SIZE-1, 3);
This is because binary search doesn't always start at 0 and doesn't always end at the end of the array.
Also note that last, the location of the last item, isn't the size of the array, but one less, because of C++'s 0-based counting.
For another look at how to do this, see this page, scroll down to the C++ section (which in this case has code that compiles fine as C): http://www.algolist.net/Algorithms/Binary_search
I find this Quicksort partitioning approach confusing and wrong, yet it seems to work. I am referring to this pseudocode. Note: they also have a C implementation at the end of the article, but it's very different from their pseudocode, so I don't care about that.
I have also written it in C like this, trying to stay true to the pseudocode as much as possible, even if that means doing some weird C stuff:
#include <stdio.h>
int partition(int a[], int p, int r)
{
int x = a[p];
int i = p - 1;
int j = r + 1;
while (1)
{
do
j = j - 1;
while (!(a[j] <= x));
do
i = i + 1;
while (!(a[i] >= x));
if (i < j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
else
{
for (i = 1; i <= a[0]; ++i)
printf("%d ", a[i]);
printf("- %d\n", j);
return j;
}
}
}
int main()
{
int a[100] = //{8, 6,10,13,15,8,3,2,12};
{7, 7, 6, 2, 3, 8, 4, 1};
partition(a, 1, a[0]);
return 0;
}
If you run this, you'll get the following output:
1 6 2 3 4 8 7 - 5
However, this is wrong, isn't it? Clearly a[5] does not have all the values before it lower than it, since a[2] = 6 > a[5] = 4. Not to mention that 7 is supposed to be the pivot (the initial a[p]) and yet its position is both incorrect and lost.
The following partition algorithm is taken from wikipedia:
int partition2(int a[], int p, int r)
{
int x = a[r];
int store = p;
for (int i = p; i < r; ++i)
{
if (a[i] <= x)
{
int t = a[i];
a[i] = a[store];
a[store] = t;
++store;
}
}
int t = a[r];
a[r] = a[store];
a[store] = t;
for (int i = 1; i <= a[0]; ++i)
printf("%d ", a[i]);
printf("- %d\n", store);
return store;
}
And produces this output:
1 6 2 3 8 4 7 - 1
Which is a correct result in my opinion: the pivot (a[r] = a[7]) has reached its final position.
However, if I use the initial partitioning function in the following algorithm:
void Quicksort(int a[], int p, int r)
{
if (p < r)
{
int q = partition(a, p, r); // initial partitioning function
Quicksort(a, p, q);
Quicksort(a, q + 1, r); // I'm pretty sure q + r was a typo, it doesn't work with q + r.
}
}
... it seems to be a correct sorting algorithm. I tested it out on a lot of random inputs, including all 0-1 arrays of length 20.
I have also tried using this partition function for a selection algorithm, in which it failed to produce correct results. It seems to work and it's even very fast as part of the quicksort algorithm however.
So my questions are:
Can anyone post an example on which the algorithm DOESN'T work?
If not, why does it work, since the partitioning part seems to be wrong? Is this another partitioning approach that I don't know about?
I think the partitioning is correct. 7 is the pivot. The original array is partitioned into a sub array of length 5 containing elements less than or equal to 7 and a sub array of length 2, containing elements greater or equal to 7.
Extending on from above here is what it should look like
void swap(int *a, int *b)
{
int x;
x = *a;
*a = *b;
*b = x;
}
int partition(int s[], int l, int h)
{
int i;
int p;/* pivot element index */
int firsthigh;/* divider position for pivot element */
p = h;
firsthigh = l;
for (i = l; i < h; i++)
if(s[i] < s[p]) {
swap(&s[i], &s[firsthigh]);
firsthigh++;
}
swap(&s[p], &s[firsthigh]);
return(firsthigh);
}
void quicksort(int s[], int l, int h)
{
int p;/* index of partition */
if ((h - l) > 0) {
p = partition(s, l, h);
quicksort(s, l, p - 1);
quicksort(s, p + 1, h);
}
}
int main()
{
int a[100] = //{8, 6,10,13,15,8,3,2,12};
{7, 7, 6, 2, 3, 8, 4, 1};
quicksort(a, 0, 7);
return 0;
}
From Wikipedia (I've emphasized the part that I think addresses your question directly):
This is the in-place partition
algorithm. It partitions the portion
of the array between indexes left and
right, inclusively, by moving all
elements less than or equal to
array[pivotIndex] to the beginning of
the subarray, leaving all the greater
elements following them. In the
process it also finds the final
position for the pivot element, which
it returns. It temporarily moves the
pivot element to the end of the
subarray, so that it doesn't get in
the way. Because it only uses
exchanges, the final list has the same
elements as the original list. Notice
that an element may be exchanged
multiple times before reaching its
final place. It should also be noted
that in case of pivot duplicates in
the input array, they can be spread
across left subarray, possibly in
random order. This doesn't represent a
partitioning failure, as further
sorting will reposition and finally
"glue" them together.
Could that be what you were missing?
You are getting confused between the index of the item and the iten value
Look at your header
int partition(int a[], int p, int r) ;
Now if we changed the data type on the array a to some weird data type you will see the problem
int partition( Otherdatatype a[], int p, int r) ;
You call the function from within your main with
partition(a, 1, a[0]);
See the problem a[0] is the value of the entry in a[0] not an index value.
Imagine a[0] had the value 200 in your code simply change the first item value to 200 and you will get a runtime error "attempt to access memory out of range" because if you follow
thru a[0] = 200 that is passed into partition as value r then follow what happens inside partition.
The thing to remember is this is a sort routine in your partition header the list in array a may not be of the same type as the indexes .. p and r of your header are clearly indexes referring to an index position and a is the list to be sorted.
Thus your main start to a sort is
partition(a, 0, items_in_array-1);
Do you see why? Array a runs from a[0] ... a[items_in_array-1]
So in your sample above you have preloaded 8 values into your array so your partition call from main should be
partition(a, 0, 7);