I have used 3 nested loop. Now i want to convert these loops to recursive.
Also is there a general way to convert a loop into recursive?
#include <stdio.h>
#define f(x, y, z) ((x + y) * (y + z))
int main()
{
int test_case, p, q, r, i, j, k, a[100001], b[100001], c[100001], sum;
scanf("%d", &test_case);
while (test_case--) {
scanf("%d%d%d", &p, &q, &r);
sum = 0;
for (i = 0; i < p; i++) {
scanf("%d", &a[i]);
}
for (i = 0; i < q; i++) {
scanf("%d", &b[i]);
}
for (i = 0; i < p; i++) {
scanf("%d", &c[i]);
}
for (i = 0; i < q; i++) { // I have convert this to recursion.
for (j = 0; j < p; j++) {
for (k = 0; k < r; k++) {
if (b[i] >= a[j] && b[i] >= c[k]) {
sum += f(a[j], b[i], c[k]);
}
}
}
}
printf("%d\n", sum % 1000000007);
}
return 0;
}
A loop like:
for (int i=0; i<n; i++) {
func(i);
}
can be translated to recursion as:
void rec_fun(int i,int n) {
if (!(i<n)) return;
func(i);
rec_fun(i+1,n);
}
...
rec_fun(0,n);
So:
for (i = 0; i < q; i++) { // I have convert this to recursion.
for (j = 0; j < p; j++) {
for (k = 0; k < r; k++) {
if (b[i] >= a[j] && b[i] >= c[k]) {
sum += f(a[j], b[i], c[k]);
}
}
}
}
can be translated as:
void rec_k(int k,int r,int i,int j) { // k-loop
if (!(k<r)) return;
if (b[i] >= a[j] && b[i] >= c[k]) {
sum += f(a[j], b[i], c[k]);
}
rec_k(k+1,r,i,j); // recurse
}
void rec_j(int j,int p,int i,int r) { // j-loop
if (!(j<p)) return;
rec_k(0,r,i,j); // inner loop
rec_j(j+1,p,i,r); // recurse
}
void rec_i(int i,int q,int p,int r) { // i-loop
if (!(i<q)) return;
rec_j(0,p,i,r); // inner loop
rec_i(i+1,q,p,r); // recurse
}
...
rec_i(0,q,p,r);
I'm not sure this is either more readable or useful, but it meets your initial needs.
Let us assume that the intention of this code is to only calculate the sum.
You can make a function as
int recurse_sum(int i, int j, int k) {
int res = .... // Logic for calculating sum for these indices i, j, k.
k++;
if (k==r) {
k = 0;
j++;
}
if(j==p){
j=0;
i++;
}
if(i==q){
return res;
}
return res + recurse_sum(i,j,k);
}
Now you can just call with recurse_sum(0,0,0);
The rest of the parameters can either be made global or just passed along with i,j,k.
I hope this helps.
Edit:
As mentioned by #dlasalle this code can be made open to tail call recursion optimization by placing the call at the end of the function.
In that case you can have the following version.
int recurse_sum(int i, int j, int k, int sum) {
int res = .... // Logic for calculating sum for these indices i, j, k.
k++;
if (k==r) {
k = 0;
j++;
}
if(j==p){
j=0;
i++;
}
if(i==q){
return res + sum;
}
return recurse_sum(i,j,k,res+sum);
}
Here the function ends with returning the value from the inner call and hence can be easily optimized.
Ofcourse in this case it will have to be called as recurse_sum(0,0,0,0);
Thanks to #Jean-Baptiste Yunès .
I made these changes to my code to convert it to recursive.
#include<stdio.h>
#define f(x, y, z) ((x + y)*(y + z))
int sum=0;
void rec_k(int k,int r,int i,int j,int a[],int b[],int c[]) { // k-loop
if (!(k<r)) return;
if (b[i] >= a[j] && b[i] >= c[k]) {
sum += f(a[j], b[i], c[k]);
}
rec_k(k+1,r,i,j,a,b,c);
}
void rec_j(int j,int p,int i,int r,int a[],int b[],int c[]) { // j-loop
if (!(j<p)) return;
rec_k(0,r,i,j,a,b,c);
rec_j(j+1,p,i,r,a,b,c);
}
void rec_i(int i,int q,int p,int r,int a[],int b[],int c[]) { // i-loop
if (!(i<q)) return;
rec_j(0,p,i,r,a,b,c);
rec_i(i+1,q,p,r,a,b,c);
}
int main() {
int test_case, p, q, r, i, j, k, a[100001], b[100001], c[100001];
scanf("%d", &test_case);
while(test_case--) {
scanf("%d%d%d", &p, &q, &r);
sum=0;
for(i=0;i<p;i++) {
scanf("%d", &a[i]);
}
for(i=0;i<q;i++) {
scanf("%d", &b[i]);
}
for(i=0;i<p;i++) {
scanf("%d", &c[i]);
}
rec_i(0,q,p,r,a,b,c);
printf("%d\n", sum%1000000007);
}
return 0;
}
Related
I am trying this merge sort. But I am getting no output. Means it is giving no output on console screen even waited for 2 min. Anyone of you please help me with this. Where should I correct myself.
#include <stdio.h>
#include <stdlib.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
void MergeSort();
void Merging();
int main() {
int arr[100];
int i;
for (i = 0; i < 5; i++) {
scanf("%d", &arr[i]);
}
printf("Unsorted\n");
for (i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
MergeSort(arr, 0, 4);
printf("Sorted\n");
for (i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
return 0;
}
void MergeSort(int arr[], int l, int h) {
if (l < h) {
int mid = (l + h) / 2;
MergeSort(arr, l, mid);
MergeSort(arr, mid + 1, h);
Merging(arr, l, mid, h);
}
}
void Merging(int arr[], int l, int mid, int h) {
int i1 = l, i2 = mid + 1, j1 = mid, j2 = h;
int b[6];
int k = l;
while (i1 <= j1 && i2 <= j2) {
if (arr[i1] < arr[i2]) {
b[k++] = arr[i1++];
} else {
b[k++] = arr[i2++];
}
}
while (i1 <= j1) {
b[k++] = arr[i1];
}
while (i2 <= j2) {
b[k++] = arr[i2];
}
int i;
for (i = l; i <= h; i++) {
arr[i] = b[i];
}
}
I have seen in other sites using two different arrays and first storing main array values then merging two arrays. I thought of doing it different way.
You forgot about index incrementing in tail treatment in Merging.
ideone
while(i1<=j1){
b[k++] = arr[i1++];
}
while(i2<=j2){
b[k++] = arr[i2++];
The code did not execute within time limits because it encountered itself in an infinite loop.
There are a couple of changes required:
The function declaration should correctly specify the number and types of the parameters.
For the following two while loops, the value of the iterators i1 and i2 were never changed. Therefore, it caused an infinite loop and nothing was displayed on the screen.
while(i1<=j1){
b[k++] = arr[i1++];
}
while(i2<=j2){
b[k++] = arr[i2++];
}
Have a look at the following corrected code:
#include <stdio.h>
#include <stdlib.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
void MergeSort(int arr[],int l,int h);
void Merging(int arr[], int l, int mid, int h);
int main(){
int arr[100];
int i;
for(i=0;i<5;i++){
scanf("%d",&arr[i]);
}
printf("Unsorted\n");
for(i=0;i<5;i++){
printf("%d ",arr[i]);
}
printf("\n");
MergeSort(arr,0,4);
printf("Sorted\n");
for(i=0;i<5;i++){
printf("%d ",arr[i]);
}
return 0;
}
void MergeSort(int arr[],int l,int h){
if(l<h){
int mid = (l+h)/2;
MergeSort(arr,l,mid);
MergeSort(arr,mid+1,h);
Merging(arr,l,mid,h);
}
}
void Merging(int arr[], int l, int mid, int h){
int i1 = l,i2 = mid+1, j1 = mid, j2 = h;
int b[6];
int k=l;
while(i1<=j1&&i2<=j2){
if(arr[i1]<arr[i2]){
b[k++] = arr[i1++];
}else{
b[k++] = arr[i2++];
}
}
while(i1<=j1){
b[k++] = arr[i1++];
}
while(i2<=j2){
b[k++] = arr[i2++];
}
int i;
for(i=l;i<=h;i++){
arr[i] = b[i];
}
}
Testing:
Input: 5 4 -1 3 1
Output:
Unsorted
5 4 -1 3 1
Sorted
-1 1 3 4 5
You forgot to increment i1 and i2 that's why it generated an infinite loop and no output was shown on console.
while(i1<=j1){
b[k++] = arr[i1++];
}
while(i2<=j2){
b[k++] = arr[i2++];
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I made a code of mergesort algorithm that have two inputs: the number of digits, and digits
And I want to print array sorted by my mergesort function.
But only i can see is run time error.
I think my Merge() function made runtime error. but I cant find the exception of my while loop in Merge function..
How can I fix this error and run mergesort function properly?
Here is my code
#include <stdio.h>
void Merge(int *arr, int s, int e, int m);
void MergeSort(int *arr, int s, int e);
int main(void) {
int N;
scanf("%d", &N);
int arr[N];
for (int i = 0; i < N; i++) {
scanf("%d", &arr[i]);
}
MergeSort(arr, 0, N - 1);
for (int i = 0; i < N; i++) {
printf("%d", arr[i]);
}
}
void MergeSort(int *arr, int s, int e) {
printf("hi\n");
int m;
if (e - s > 0) {
m = (s + e) / 2;
MergeSort(arr, s, m);
MergeSort(arr, m + 1, e);
Merge(arr, s, e, m);
} else {
return;
}
}
void Merge(int *arr, int s, int e, int m) {
int arr_t[e - s + 1];
int i = s, j = m + 1, idx = s;
while (1) {
if (i != m && j != s) {
if (i <= m && arr[i] <= arr[j]) {
arr_t[idx] = arr[i];
i++;
idx++;
} else
if (j <= e) {
arr_t[idx] = arr[j];
j++;
idx++;
}
} else
if (i == m && j != e) {
arr_t[idx] = arr[j];
j++;
idx++;
} else
if (i != m && j == e) {
arr_t[idx] = arr[i];
i++;
idx++;
} else {
if (arr[i] <= arr[j]) {
arr_t[idx] = arr[i];
idx++;
arr_t[idx] = arr[j];
} else {
arr_t[idx] = arr[j];
idx++;
arr_t[idx] = arr[i];
}
break;
}
}
for (int k = s; k <= e; k++) {
arr[k] = arr_t[k];
}
}
The error in your part of code may be due to:
You are probably going out of bounds of one of your array as stated by #Some programmer dude
Instead of while(1) you may use while(i<=mid && j<=end) which loops until the merge runs out of one or both parts
N even instead of using so many else if in your merge function, you can use while() loop that will simplify your code.You shouldn't append two values to the temporary array in your last else clause either
Even if(i!=m && j!=s) this condition in your code looks a bit weird.
So I wrote this sample mergesort for your reference. Hope this helps!!
#include<stdio.h>
void merge(int a[],int start,int mid,int end){
int i=start,j=mid+1,k=0;
int temp[end-start+1];
while(i<=mid && j<=end){
if(a[i]<a[j]){
temp[k]=a[i];
k+=1;
i+=1;
}
else{
temp[k]=a[j];
k+=1;
j+=1;
}
}
while(i<=mid){
temp[k]=a[i];
i+=1;k+=1;
}
while(j<=end){
temp[k]=a[j];
j+=1;k+=1;
}
for(int i=end;i>=start;i--){
a[i]=temp[--k];
}
}
void mergesort(int a[],int start,int end){
if(start<end){
int mid=(start+end)/2;
mergesort(a,start,mid);
mergesort(a,mid+1,end);
merge(a,start,mid,end);
}
}
void display(int a[],int n){
for(int i=0;i<n;i++)
printf("%d ",a[i]);
}
int main()
{
int a[5]={5,4,6,2,1};
int n=sizeof(a)/sizeof(a[0]);
mergesort(a,0,n-1);
display(a,n);
}
With the worst-case time complexity being Ο(n log n)
For instance when user input 4 and 2, it means the original set have 4 elements: (1,2,3,4) and the subset should have 2 elements. I figured out a way to present these subsets in a regular form like (1,2)(1,3)(1,4)(2,3)(2,4)(3,4) using the code below, but my assignment requires binary-like form like (1,2) should be (1,1,0,0) and (2,4) should be (0,1,0,1) etc. In (1,1,0,0), first binary 1 means the first element in original set (1,2,3,4) which is 1 is contained in the subset. And the second binary 1 means the second element in original set which is 2 is contained in subset. While the third and forth number 3 and 4 is not. So for example, a subset (1,2,5) from set (1,2,3,4,5) can be presented by (1,1,0,0,1)
void subset(int n, int k, int B[], int q, int r) {
if (q == k) {
for (int i = 0; i < k; i++) {
printf("%d ", B[i]);
}
printf("\n");
} else {
for (int i = r; i < n; i++) {
B[q] = i+1;
subset(n, k, B, q+1, i+1);
}
}
}
In main (n is number of elements in original set, k is number of elements in subsets):
int B[101];
subset(n, k, B, 0, 0);
Also my assignment needs this recursive function with 4 exact arguments( i is from (1,2,3,4...i) ):
void subsets(int B[], int n, int k, int i)
I've tried so many ways and failed. I'll be really appreciated if someone can help me out, thanks.
Updates:
thanks to rajender kumar, the binary-like output problem is solved by using the code below:
void printSubsets(int B[], int n, int k, int q, int i) {
if (q == k) {
int finalArry[MAX_SIZE+1] = {0};
for (int i = 0; i < k; i++) {
finalArry[B[i]] = 1;
}
printSet(finalArry, n);
} else {
for (int j = i; j < n; j++) {
B[q] = j+1;
printSubsets(B, n, k, q+1, j+1);
}
}
}
But I still need to remove one argument from either int q or int i.
This should do the job:
void subset(int n, int k, int B[], int i) {
if (k == 0) {
for (int d = 0; d < n; d++) {
printf("%d ", B[d]);
}
printf("\n");
} else if (i >= n || k > n - i) {
return;
} else {
B[i] = 1;
subset(n, k - 1, B, i + 1);
B[i] = 0;
subset(n, k, B, i + 1);
}
}
int main(int argc, char **argv) {
int n, k;
int B[4];
memset(B, 0, sizeof(B));
n = sizeof(B) / sizeof(B[0]);
k = 2;
printf("n=%d\nk=%d\n", n, k);
subset(n, k, B, 0);
return 0;
}
Add another boolean array and put entire array like this .
void subset(int n, int k, int B[], int q, int r) {
if (q == k) {
bool finalArry[n] = {0};
for (int i = 0; i < k; i++) {
finalArry[B[i]-1] = true;
}
for (int i = 0; i < n; i++) {
if(finalArry[i]){
cout<<1<<" ";
}
else{
cout<<0<<" ";
}
}
cout<<endl;
} else {
for (int i = r; i < n; i++) {
B[q] = i+1;
subset(n, k, B, q+1, i+1);
}
}
}
My C merge code works when I initialize the array globally at the top of the program until the stack overflows. I'm trying to initialize the array with malloc, but when I do, the code will only read in two integers and stop running.
This program pulls random numbers from a file called alg.txt and then sorts them. Again, the code works (up until 500k integers) when defining z at the top of the program to the number of integers to be sorted, and declaring the array globally to be equal to arr[z]. How do I figure out what is going on?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int count = 0;
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
int L[n1], R[n2];
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
count++;
for (j = 0; j < n2; j++)
R[j] = arr[m + 1+ j];
count++;
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
count++;
}
else
{
arr[k] = R[j];
j++;
count++;
}
k++;
count++;
}
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
count++;
}
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
count++;
}
}
void mergeSort(int arr[], int l, int r)
{
if (l < r)
{
int m = l+(r-l)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
}
void printArray(int A[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", A[i]);
printf("\n");
}
int main()
{
int i;
FILE *myFile;
myFile = fopen("alg.txt", "r");
int z;
printf("Enter the size of the array: ");
scanf("%d", &z);
int *arr = (int *)malloc(z*sizeof(int));
int n = sizeof(arr)/sizeof(arr[0]);
for(i=0; i < z; i++)
{
fscanf(myFile, "%d,", &arr[i]);
}
mergeSort(arr, 0, n - 1);
printf("\nSorted array is \n");
printArray(arr, n);
printf("count is %d\n", count);
return 0;
}
You are declaring the L and R array's locally (inside the merge function). They consume stack on every function call. You should initialize them globally so that they can be stored on the heap. Also, you should declare just one array (like temp_arr in the below code) as there's no need for two separate arrays like L and R.
See Local vs Global variable storage
You can improve your merge function to this:
int temp_arr[500000]; // Global declaration
void merge(int arr[], int l, int m, int r)
{
int i=l, j=m+1, k=l;
while(i<=m && j<=r)
{
if(arr[i]<arr[j])
temp_arr[++k] = arr[++i];
else temp_arr[++k] = arr[++j];
}
while(i<=m)
temp_arr[++k] = arr[++i];
while(j<=r)
temp_arr[++k] = arr[++j];
i = l;
while(i<=r)
arr[i] = temp_arr[++i]; // Storing stored array in arr
}
This is my first semester learning C and I have trouble with one of my homeworks.
It's a program to receive the lists of homework as sets of (t,d) and to evaluate the urgency of each homework. (t means time left until deadline and d mean difficulty.) The task is to sort the list primarily by the order of remaining time and if the remaining time is equal, to sort it by difficulty.
This code works perfectly well when the input is something like
(1,0), (2, 1), (4,5) ...
But when the input is like
(1,0), (1, 4), (2, 1)...
it won't stop receiving inputs. This happens when the 'time' of the homework is the same (or so I think). I can't figure out why it's doing this.
#include <stdio.h>
#define MAX 1024
void insertionSort(int a[], int b[], int num);
void printArray(int a[], int b[], int num);
int main()
{
int a[MAX] = {0};
int b[MAX] = {0};
int i, num;
scanf("%d", &num);
for(i=0; i<num; i++){
scanf("%d", &a[i]);
scanf("%d", &b[i]);
}
insertionSort(a, b, num);
return 1;
}
void insertionSort(int a[], int b[], int num)
{
int i, j, val, val2;
for(i=1; i<num; i++)
{
val = a[i];
val2 = b[i];
j = i-1;
while((j>=0) && (a[j]>=val))
{
if(a[j] == val){
if(val2 < b[j]){
a[j+1] = a[j];
b[j+1] = b[j];
j--;
}
}
else{
a[j+1] = a[j];
b[j+1] = b[j];
j--;
}
a[j+1] = val;
b[j+1] = val2;
}
}
printArray(a, b, num);
}
void printArray(int a[], int b[], int num)
{
int i;
for(i=0; i<num; i++){
printf("%d ", a[i]);
printf("%d", b[i]);
printf("\n");
}
}
Your code is not continuously receiving inputs, instead it is stuck in an infinite loop inside the insertionSort function
You just need to add an else case and break the loop.
Here is the working code:
#include <stdio.h>
#define MAX 1024
void insertionSort(int a[], int b[], int num);
void printArray(int a[], int b[], int num);
int main()
{
int a[MAX] = {0};
int b[MAX] = {0};
int i, num;
scanf("%d", &num);
for(i=0; i<num; i++)
{
scanf("%d", &a[i]);
scanf("%d", &b[i]);
}
insertionSort(a, b, num);
return 1;
}
void insertionSort(int a[], int b[], int num)
{
int i, j, val, val2;
for(i=1; i<num; i++)
{
val = a[i];
val2 = b[i];
j = i-1;
while((j>=0) && (a[j]>=val))
{
if(a[j] == val)
{
if(val2 < b[j])
{
a[j+1] = a[j];
b[j+1] = b[j];
j--;
}
else
{
break;
}
}
else
{
a[j+1] = a[j];
b[j+1] = b[j];
j--;
}
a[j+1] = val;
b[j+1] = val2;
}
}
printArray(a, b, num);
}
void printArray(int a[], int b[], int num)
{
int i;
for(i=0; i<num; i++)
{
printf("%d ", a[i]);
printf("%d", b[i]);
printf("\n");
}
}