I was asked to write a recursive code to print an array. A friend showed me this code:
include <stdio.h>
int i=0;
void print(int A[], int n)
{
if(i<n)
{
printf("%d ", A[i]);
i++;
print(A, n);
}
}
int main()
{
int A[3]={3, 5, 2};
print(A, 3);
return 0;
}
Technically, it is recursive because the function calls itself, but I think trivially !! It does not break the problem into smaller problems or anything like that. So, it felt like cheating. Faking as if it is recursion.
Can the function in this code be consider recursive? Is this a fine way to use recursion?
What about in this form:
#include <stdio.h>
void print(int A[], int n, int i)
{
if(i<n)
{
printf("%d ", A[i]);
print(A, n, i+1);
}
}
int main()
{
int A[3]={3, 5, 2}, i=0;
print(A, 3, i);
return 0;
}
Can the function in this code be consider recursive?
Yes, recursion occurs when the function can call itself, either directly or indirectly.
Is this a fine way to use recursion?
No. Although some compilers may optimize the code, code risks incurring n levels of recursion and causing stack overflow
A better alternative is to halve the problem. This breaks the problem in 2 at each step.
void print(int A[], int n, int i) {
if (i<n) {
A += i; n -= i; // zero offset A and n
int mid = n/2;
print(A, mid, 0); // print left side of A
printf("%d ", A[mid]); // print middle of A
int right = n - mid - 1;
print(A + mid + 1, right, 0); // print right side of A
}
}
If n was 1000, the above could incur a recursion depth of log2(1000) or about 10 instead of 1000. An unbounded n is a reason recursion can be abused. Insure that the recursion depth is not excessive.
Notice that parameter i is not really needed.
void printA(int A[], size_t n) {
if (n > 0) {
size_t mid = n/2;
printA(A, mid); // print left side of A
printf("%d ", A[mid]); // print middle of A
size_t right = n - mid - 1;
printA(A + mid + 1, right); // print right side of A
}
}
Yes, this is a recursive function, since it calls itself.
Additionally, the function does break the problem to smaller problems - in this case, precisely one smaller problem: printing the array starting from index i+1 instead from index i. Since the bound is greater than i, the problem is smaller.
In other words, the recursion is well founded: the value of n-i is decreasing at each call, and the edge case of n-i==0 is handled trivially, not recursively.
Regardless of the number of lines in a function, it is recursive if it calls itself.
void print(int A[], int n) {
if(n == 0)
printf("%d", *A);
print(++A, --n);
}
Instead of using static variable you can pass the starting element address and last elements address of the array and do the same task.
void print(int *A_start, int *A_end) {
if(A_start < A_end) { /* call the function itself until A_start not reaches A_end */
printf("%d ", *A_start);
A_start++;
print(A_start,A_end);
}
}
int main() {
int A[3]={3, 5, 2};
int ele = sizeof(A)/sizeof(A[0]);
print(A,A+ele);
return 0;
}
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
I'm trying to do a program that will do a sum for an array. If i put a printf in the function, it returns right, but at the final the result is incorrect. Why?
#include <stdio.h>
int summ(int a[100],int n)
{
static int sum=0;
static int i=0;
if(i<n)
{
sum+=a[i];
++i;
return (summ(a,n)+sum);
}
}
int main()
{
int b[100];
int n,i,suma;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&b[i]);
}
suma=summ(b,n);
printf("Suma=%d",suma);
return 0;
}
Compiling your code with warnings enabled should yield the following output:
program.c:13:1: warning: control may reach end of non-void function [-Wreturn-type]
This means that your summ function lacks a base case - i.e. it does not specify what should be returned once n is reached.
Once you fix this problem, your code starts returning the correct value. However, your function would still need some fixing, because you should not be using static variables in it. Any static variable in a function makes the function non-reentrant, which is very bad. In particular, your function can be run only once; second invocation would yield an error, because neither i nor sum could be reset.
Here is a simple recursive implementation of what you are looking to build:
int summ_impl(int a[], size_t i, size_t n) {
return i != n ? a[i] + summ_impl(a, i+1, n) : 0;
}
int sum(int a[], size_t n) {
return summ_impl(a, 0, n);
}
With recursion:
int summ(int *a, int n) {
if (n-- > 0)//the n is equal to n-1 after check condition
return (summ(a,n) + a[n]);//return the n-1 sum (recursion) + current value
return (0);
}
This way, the function will call itself while it not equal to zero (so between n and 0)
So we got:
a = [1,2,3]
the function will return
3 + sum before
-> 2 + sum before
-> 1 + sum before
-> 0
When the function go back in the stack
0 + 1 + 2 + 3 -> 6
I have a modified version of quicksort in my program that is instructed to sort pairs of numbers by the sum of their squares ( for example: -4,1 > 2,2). My program works fine with positive integers, but when I use too many negative integers the program crashes (any more than one or two negative numbers will cause a crash). I think I'm trying to access or sort undefined parts of the array that is storing the integers. What is it about array storage that I am forgetting? Or is the problem elsewhere?
void swap(int *a,int *b);
int square(int num);
int abs_value(int num);
void quicksort(int arr[],int first,int last);
int main()
{
int num_of_pts;
int num1;
int num2;
printf("Enter number of points: ");//points are coordinates on the xy axis
scanf("%d", &num_of_pts); //that's why there is double
int unsorted_pts_arr[2*num_of_pts];//the amount of storage in the array
for(int i=0; i<num_of_pts; i++){
printf("Enter Point: ");
scanf(" %d",&num1);
scanf(" %d",&num2);
unsorted_pts_arr[2*i]=num1;
unsorted_pts_arr[2*i+1]=num2;
}
quicksort(unsorted_pts_arr,0,num_of_pts);
printf("Sorted Points:");
for(int j=0; j<num_of_pts; j++)
printf(" (%d,%d)",unsorted_pts_arr[2*j],unsorted_pts_arr[2*j+1]);
return 0;
}
void swap(int *a,int *b)
{
int temp;
temp = *b;
*b = *a;
*a = temp;
}
int square(int num)
{
num=abs_value(num);
num*=num;
return num;
}
int abs_value(int num)
{
if(num<0) return -num;
else return num;
}
void quicksort(int arr[],int first,int last)
{
int pivot,j,i;
if(first<last){
pivot=first;
i=first;
j=last;
while(i<j){
while((square(arr[2*i])+square(arr[2*i+1]))<=
(square(arr[pivot])+square(arr[pivot+1]))
&&i<last)
i++;
while((square(arr[2*j])+square(arr[2*j+1]))>
(square(arr[pivot])+square(arr[pivot+1])))
j--;
if(i<j){
swap(&arr[2*i],&arr[2*j]);
swap(&arr[2*i+1],&arr[2*j+1]);
}
}
swap(&arr[pivot],&arr[2*j]);
swap(&arr[pivot+1],&arr[2*j+1]);
quicksort(arr,first,2*j-1);
quicksort(arr,2*j+1,last);
}
}
Main problem
You are most likely accessing the array out of bounds by using 2*j-1 and 2*j+1 as the array indices in the recursive calls.
quicksort(arr,first,2*j-1);
quicksort(arr,2*j+1,last);
When you call quicksort from main, last is equal to num_of_pts. It makes sense that in the recursive calls, you should use j and j+1.
quicksort(arr,first,j);
quicksort(arr,j+1,last);
Suggestion for minor improvement
Implementation of square can be simpler.
int square(int num)
{
return num*num;
}
The last index is num_of_pts-1, so
quicksort(unsorted_pts_arr,0,num_of_pts);
must rather be
quicksort(unsorted_pts_arr, 0, num_of_pts-1);
pivot is used like i and j to index a pair of numbers in arr, so it must be doubled as well:
(square(arr[pivot])+square(arr[pivot+1]))
(both occurences) must be
square(arr[2*pivot])+square(arr[2*pivot+1])
quicksort is passed indexes to pairs of numbers (as in main), so the arguments of the recursive call also must not be doubled:
quicksort(arr,first,2*j-1);
quicksort(arr,2*j+1,last);
must be
quicksort(arr, first, j-1);
quicksort(arr, j+1, last);
I'm trying to build a recursive function which returns the address within a sorted array by comparing to the middle value and proceeding based on relative size. Should the value not be in the array, it is supposed to simply print NULL. Now the first part of the function works, however whenever a null is supposed to happen I get a segmentation fault. The code looks as follows:
#include <stdio.h>
int *BinSearchRec(int arr[], int size, int n){
if(n==arr[size/2]){
return &arr[size/2];
}
else if(n>arr[size/2]) {
return(BinSearchRec(arr, size+size/2, n));
}
else if(n<arr[size/2]) {
return(BinSearchRec(arr, size-size/2, n));
}
else{
return NULL;
}
}
main(){
int numb[]={2,7,8,9};
if((int)(BinSearchRec(numb, 4, 22)-numb)>=0) {
printf("Position: %d \n", (int)(BinSearchRec(numb, 4, 22)-numb)+1);
}
else{
printf("NULL \n");
}
}
Your recursive calls are wrong. In the first case you claim that the size of the array is 50% larger than originally, and you're passing the pointer wrong (you should pass the second "half" of the array).
In both cases, the size of the "array" is always half of what the function received. And in the second case, you need to pass a pointer to the second half of the array.
Something like
else if(n>arr[size/2]) {
return(BinSearchRec(arr + sizeof/2, size/2, n));
}
else if(n<arr[size/2]) {
return(BinSearchRec(arr, size/2, n));
}
You're also treating the returned value from the function wrong. It's not a value, it's a pointer to the value, you need to treat it as such. And it's okay to subtract one pointer from another (related) pointer, it's called pointer arithmetics.
In addition to what others have said about not dividing the array properly and not using the return value correctly, your function is missing a termination condition.
In your code, the las else will never be reached, because the three preceding conditions cover all possibilities: n is either smaller than, equal to or greater than arr[size/2].
You should test whether your subarray actually has elements before you access and compare them. Here's a revision of your code:
int *BinSearchRec(int arr[], int size, int n)
{
int m = size/2;
if (size == 0) return NULL;
if (n > arr[m]) return BinSearchRec(arr + m + 1, size - m - 1, n);
if (n < arr[m]) return BinSearchRec(arr, m, n);
return &arr[m];
}
And here's an example main that shows how you make use of the pointer that was returned. If the pointer is NULL, the number is not in the array and you cannot dereference the pointer.
int main()
{
int numb[] = {2, 7, 8, 9};
int n;
for (n = 0; n < 15; n++) {
int *p = BinSearchRec(numb, 4, n);
if (p) {
printf("%d: #%d\n", n, (int) (p - numb));
} else {
printf("%d: NULL\n", n);
}
}
return 0;
}
Instead of using a single size, it is easier to reason with 2 indexes (left and right) delimiting the sub-array you are exploring.
Modifying your code according to this approach gives:
#include <stdio.h>
#include <stdlib.h>
int *BinSearchRec(int arr[], int left, int right, int n){
if (left > right)
return NULL;
int mid = (left + right) / 2;
if(n == arr[mid])
return &arr[mid];
if(n > arr[mid])
return BinSearchRec(arr, mid + 1, right, n);
else
return BinSearchRec(arr, left, mid - 1, n);
}
int main(int argc, char *argv[]){
int numb[] = {2,7,8,9};
int *p = BinSearchRec(numb, 0, 3, 22);
if (p) {
printf("Position: %d \n", (int) (p - numb + 1));
} else {
printf("NULL \n");
}
return 0;
}
I made this program to sort an array. It works fine, but it won't sort! Please help me find the error in my logic. Thanks
[UPDATE] It was able to work! I just brought down the i, j, and k as suggested below.Also, from i
#include <stdio.h>
#include <stdlib.h>
void mergesort(int[], int, int);
void merge(int [], int low, int mid, int hi); //function prototype
int main()
{
int arr[]={1,4,78,92,9};
mergesort(arr,0,5);
//after mergesort
for(int i=0; i<5; i++)
{
printf("%d, ", arr[i]);
}
system("pause");
return 0;
}
void mergesort(int aptr[], int low, int hi)
{
int mid =0;
int rightmax=0;
int leftmax=0;
if(low==hi)
{
return;
}
mid=(low+hi)/2;
mergesort(aptr, low, mid);
mergesort(aptr, mid+1, hi);
merge(aptr, low, mid, hi);
}
void merge(int aptr[], int low, int mid, int hi)
{
int j, i, k;
//copy contents of aptr to auxiliary b
for(i=low; i<=hi; i++)
{
bptr[i]=aptr[i];
}
// iterate through b as if they were still two arrays, lower and higher
//copy smaller elements first
i=low;
j=mid+1;
k=low;
while(i<= mid && j<=hi)
{
if(bptr[i]<=bptr[j])//<--put smaller element first
{
aptr[k++]=bptr[i++];
}
else
{
aptr[k++]=bptr[j++];
}
}
// copy back first half just in case
while(i<=mid)
{
aptr[k++]=bptr[i++];
}
}//function
The statement i<= mid && j<=hi is never true when your program executes, hence, the while loop that depends on it is never entered and your code that actually swaps elements is never reached.
After the for loop that precedes it, i is equal to hi, which is always greater than mid. I am guessing you mean to reset i to be equal to low before you enter that while loop.
Here's a suggestion for how to start: put printf() calls into your mergesort() and merge() functions that display the parameters at the start and return of each function call. That might help you figure out what's going on. Asking other people to debug your algorithm isn't going to to help you learn how to program.
As a sundry point I'd like to mention that you've fallen victim to error of possible integer overflow:
mid=(low+hi)/2;
If low and/or hi are big enough, low + hi will overflow, giving you the wrong value for mid. Instead you should do this:
mid = low + (hi - low) / 2;