I understand there are a lot of questions around even recursion here, but I don't know in C wether its my logic or my syntax that's wrong (or presumably both) because from what I know I may need pointers. Especially when I'm using function in C, so I can harldy find any question that I can understand as a freshman in cs undergrads.
So my assignment was to simply create an array with even numbers in range determined in input, if input n = 10, then the array needs to contain [0, 2, 4, 6, 8, 10], if n = 9 then the array would simply be [0, 2, 4, 6, 8]. But I have to do it with recursion and I don't know what's wrong with my code since the output is somewhat weird.
#include <stdio.h>
int even(int x, int arrEven[]) {
if (x == 0) {
arrEven[0] = 0;
return 0;
}
else if (x > 0) {
arrEven[x - 1] = even(x - 2, arrEven) + 1;
return arrEven[x - 1];
}
}
int main(void) {
printf("n = ");
int n;
scanf("%d", &n);
n = (n / 2) + 1;
int arrEven[n];
even(n, arrEven);
for (int i = 0; i < (n - 1); i++) {
printf("%d, ", arrEven[i]);
}
printf("%d", arrEven[n - 1]);
}
When I input 10 the output was
0, 1, -731908444, 2, 781232032, 3
instead of
0, 2, 4, 6, 8, 10
Your recursive function only initializes half the destination array because in arrEven[x - 1] = even(x - 2, arrEven) + 1; you decrement x by 2 instead of incrementing the value by 2. You can fix your code this way:
int even(int x, int arrEven[]) {
if (x == 0) {
arrEven[0] = 0;
return 0;
} else
if (x > 0) {
arrEven[x - 1] = even(x - 1, arrEven) + 2;
return arrEven[x - 1];
}
}
Note however that the above code does not use tail recursion and will require a stack depth proportional to x. Here is an alternative where the recursion only happens just before returning from the function:
void even(int n, int arrEven[]) {
if (n > 0) {
errEven[n - 1] = 2 * (n - 1);
even(n - 1, arrEven);
}
}
The above function should compile to similar executable code as the equivalent iterative version:
void even(int n, int arrEven[]) {
while (n > 0) {
n = n - 1;
errEven[n] = 2 * n;
}
}
You mix the usage of one variable for two purposes.
In your code, n is used as index in the array and as value to be put into the array at the same time.
There are tons of options to do this. One could looke like this:
#include <stdio.h>
void even(int *arrEven, int value, int limit) {
*arrEven = value;
if (value < limit) {
even(arrEven+1, value+2, limit);
}
}
int main (void) {
int limit;
int count;
printf("n = ");
scanf("%d", &limit);
// TODO: Check return value.
if (limit < 0)
{
fprintf(stderr, "Only non-negative limits are allowed.\n");
exit(-1);
}
count = (limit / 2) + 1;
int arrEven[count];
even(arrEven, 0, limit);
for (int i = 0; i < count-1; i++){
printf("%d, ", arrEven[i]);
}
printf("%d\n", arrEven[count-1]);
}
I think what you want is something like this:
int even(int x, int arrEven[])
{
if (x == 0)
return 0;
arrEven[x - 1] = even(x - 1, arrEven);
return arrEven[x - 1] + 2;
}
Here x is purely the array index, and the fact that only even values go into the array is handled by the fact that 2 is added to the value returned by even along with the terminal condition returning 0.
Related
I have tried to solve this problem with pointers, but I couldn’t.
The requirement was writing a function in which you see if the array is
sorted increase (return 1)
sorted decrease (return -1)
not sorted at all (return 0)
Here is what I wrote:
int *test(int l,int *T)
{
int i,A[l],sign;
int *t=&A[0];
for (i=0; i<l; i++)
{
if(A[i]>A[i+1]){
t++;
sign =-1;
}
if (A[i]<A[i+1]){
t++;
sign =1;
}
if (A[i]!=A[i+1]){
t++;
sign =0;
}
}
return sign;
}
The compiler is giving
returning ‘int’ from a function with return type ‘int *’ makes pointer from integer without a cast [-Wint-conversion]
61 | return sign;
error: ld returned 1 exit status
A few things to notice,
The 'T' parameter wasn't used, so removed.
The 't' variable wasn't used, so removed.
The function return type shouldn't be a pointer to integer, it should be just an integer, from your requirements.
Your code is testing against an array declared in the function scope, and since it is an automatic variable, it is not initialized and may contain garbage values.
Your code is testing against an out of bounds index when using 'i < len' as the loop condition (ex.: considering that the array length is 3, when i == 2, comparing a[i] with a[i + 1] would access a[3], which is not within array boundaries that goes from index 0 to index 2.
With that in mind, a possible implementation with some tests is provided below, from what I can see from the requirements list, but bear in mind that I made some assumptions, since there was no restriction about them.
#include <assert.h>
#define SORTED_ASC 1
#define SORTED_DES -1
#define UNSORTED 0
int is_sorted(int *arr, int len)
{
int sorted = 0;
// I am assuming that this approach is reasonable, check your requirements.
if (len <= 1)
return UNSORTED;
for (int i = 0; i < len - 1; i++)
{
// Previous iteration detected order as 'descending', but current
// is 'ascending'.
if (sorted == SORTED_DES && arr[i] < arr[i + 1])
return UNSORTED;
// Previous iteration detected order as 'ascending', but current
// is 'descending'.
if (sorted == SORTED_ASC && arr[i] > arr[i + 1])
return UNSORTED;
// I am assuming that arrays with repeated values should remain classified
// as 'unsorted' until a different value appears, check your requirements.
if (arr[i] > arr[i + 1])
sorted = SORTED_DES;
else if (arr[i] < arr[i + 1])
sorted = SORTED_ASC;
}
return sorted;
}
void test_unsorted()
{
int arr[4][3] = {
{ 1, 3, 2 },
{ 2, 1, 3 },
{ 2, 3, 1 },
{ 3, 1, 2 }
};
for (int row = 0 ; row < 4 ; row++)
{
int res = is_sorted(arr[row], 3);
assert(res == UNSORTED);
}
}
void test_sorted_ascending()
{
int arr[] = { 1, 2, 3 };
int res = is_sorted(arr, 3);
assert(res == SORTED_ASC);
}
void test_sorted_descending()
{
int arr[] = { 3, 2, 1 };
int res = is_sorted(arr, 3);
assert(res == SORTED_DES);
}
void test_with_repeated_values()
{
int sorted_asc[] = { 1, 1, 2 };
int sorted_asc_res = is_sorted(sorted_asc, 3);
assert(sorted_asc_res == SORTED_ASC);
int sorted_des[] = { 3, 3, 2 };
int sorted_des_res = is_sorted(sorted_des, 3);
assert(sorted_des_res == SORTED_DES);
int unsorted[] = { 1, 1, 1 };
int unsorted_res = is_sorted(unsorted, 3);
assert(unsorted_res == UNSORTED);
}
int main(void)
{
test_unsorted();
test_sorted_ascending();
test_sorted_descending();
test_with_repeated_values();
}
The problem is to find the number i<=n, n<=500000 for which the longest collatz series exists.
Collatz series for a number n terminates at 1, and the conditions are
if n is even, next term = n/2
if n is odd, next term = 3*n + 1
Well as a matter of fact, the collatz series always terminates at 1 for all numbers.
Hence any number won't repeat in its collatz series. Using this fact, I have written the following code
LOGIC:
I start a while loop, that goes till n and for each iteration, I store the length of the series for that i.
If i occurs in the series of some n >= r > i, then i terminate the loop and add the length of i to r.
For example, say series of 3 is 3, 10, 5, 16, 8, 4, 2, 1. Now the length corresponding to 2 will already be stored in the series_length array, so I use that value.
Then the for loop next to that, finds the longest series and displays the answer.
The code works fine for n <= 1818 to be precise, but shows segmentation fault onwards (dunno why :(). Please help
CODE :
#include <stdio.h>
int length = 0, series_length[500000], maxlength = 0;
void store_length(int n) {
while(n > 1 && series_length[n] == 0) {
length++;
if(n%2 == 0) {
n = n/2;
}
else {
n = 3*n + 1;
}
}
length += series_length[n];
}
int main() {
int n, i = 1, result;
scanf("%d", &n);
series_length[1] = 1;//redundant statement
while(i <= n) {
store_length(i);
series_length[i] = length;
length = 0;
i++;
}
for(int i = 1;i <= n; i++) {
if(maxlength <= series_length[i]) {
maxlength = series_length[i];
result = i;
}
}
printf("%d %d\n", result, maxlength);
return 0;
}
INPUT-
10
OUTPUT-
9 20 (AS Expected)
INPUT-
100000
OUTPUT-
Segmentation Fault
Expected-
77031 351
Your value for n goes outside the range.
You have a line n = 3*n + 1; in the function store_length
Running this with the gdb with input as 100000 gives
Thread 1 received signal SIGSEGV, Segmentation fault.
0x0000000000401545 in store_length (n=532060) at 29_01.c:6
6 while(n > 1 && series_length[n] == 0) {
(gdb) p n
$1 = 532060
only store it if it fits
... and use it if it already has been computed
avoid global variables
prefer unsigned values
[use descriptive variable names]
#include <stdio.h>
#define THE_SIZE 500000
unsigned series_length[THE_SIZE]= {0,};
unsigned get_length(unsigned val) {
unsigned steps;
for (steps=0; val > 1 ; steps++) {
if (val < THE_SIZE && series_length[val]) { steps += series_length[val]; break; }
if(val %2 ) val = 3*val + 1;
else val /= 2;
}
return steps;
}
int main( int argc, char **argv) {
unsigned top, val , result;
unsigned best,maxlength ;
sscanf(argv[1], "%u", &top);
series_length[1] = 1;//redundant statement
best = maxlength = 0;
for(val=1;val <= top; val++) {
result = get_length(val);
// store it if it fits;
if(val<THE_SIZE) series_length[val] = result;
if (result < maxlength) continue;
best = val; maxlength = result;
}
printf("%u %u\n", best, maxlength);
return 0;
}
Finally, just for fun, make the array smaller
#define THE_SIZE 500
, and the program should give the same result for a given value. (it does)
You get the maximum value 24,648,077,896 with n = 487039.
You must thus use the type long long int for n and you should use an array of 24,648,077,896 integers to avoid a segmentation fault. Unfortunately I never succeeded in allocating a block of 100GB. Your optimization is thus not viable.
Without the array optimization I can scan all 500000 n values in 265ms.
Here is my code:
#include <stdio.h>
int collatz_length(int n) {
int length = 0;
long long int v = (long long int)n;
while (v > 1) {
if ((v&1) == 0)
v = v / 2;
else
v = v*3 + 1;
length++;
}
return length;
}
int main() {
int max_i, max_l = 0;
for (int i = 500000; i > 0; i--) {
int l = collatz_length(i);
if (l > max_l){
max_l = l;
max_i = i;
}
}
printf("i: %d l: %d\n", max_i, max_l);
return 0;
}
Given two arrays containing integers, figure out whether or not three consecutive integers are present in both arrays.
For example: A = [1, 4, 5, 7, 2] and B = [3, 1, 4, 5, 9] will result in "true" / 1 because [1, 4, 5] is present in both arrays.
My solution to this task is present below, but I feel like there must be a more optimized solution than this.
int consecutiveInts(int *a, int sizeA, int *b, int sizeB){
int i, j;
// Iterate over every integer in array b for every integer in array a.
for (i = 0 ; i < sizeA - 2 ; i++){
for (j = 0 ; j < sizeB - 2 ; j++){
if (a[i] == b[j] && a[i + 1] == b[j + 1] && a[i + 2] == b[j + 2])
return 1;
}
}
return 0;
}
For small arrays, OP approach is OK. For array lengths m,n it has O(m*n) run time.
An alternate makes 2 value arrays, sorts them and then looks for a common element. It has O(m*log2(m) + n*log2(n)) run time. Certainly faster with large arrays than OP's code.
typedef struct {
int i[3];
} int3;
void Init3(int3 *i3, const int *i, size_t n) {
while (n--) {
i3[n].i[0] = i[n];
i3[n].i[1] = i[n + 1];
i3[n].i[2] = i[n + 2];
}
}
int fcmp(const void *a, const void *b) {
return memcmp(a, b, sizeof (int3));
}
bool Pattern3(const int *a, size_t size_a, const int *b, size_t size_b) {
if (size_a < 3 || size_b < 3) return false;
int3 a3[size_a - 2];
Init3(a3, a, size_a - 2);
qsort(a3, size_a - 2, sizeof *a3, fcmp);
int3 b3[size_b - 2];
Init3(b3, b, size_b - 2);
qsort(b3, size_b - 2, sizeof *b3, fcmp);
while (size_a && size_b) {
int cmp = fcmp(&a[size_a - 1], &b[size_b - 1]);
if (cmp == 0) return true;
if (cmp > 0) size_a--;
else size_b--;
}
return false;
}
int main() {
int A[] = { 1, 4, 5, 7, 2 };
int B[] = { 3, 1, 4, 5, 9 };
printf("%d\n", Pattern3(A, sizeof A / sizeof *A, B, sizeof B / sizeof *B));
}
An alternative would use a bsearch() rather than form the 2nd int3 b3[]/qsort().
I think I cannot be wrong by sayin that declaring i and j outside of the loop is useless and not optimized.
Something like :
for (unsigned i = 0; i < sizeA - 2; i++) // i will only exist inside the loop
Would be a little better.
I use unsigned type because it is a habit I have taken when using an iterating variable. I think this is a matter which, if you are interested and not already informed, you could learn from by reading this topic.
Not sure it optimizes running speed, but I notice that in case there are repeated numbers you don't need to check them over and over again.
For example three sequential elements in the first array are all 1. After checking a[i] and seeing it's a mismatch you can skip directly to a[i + 3] without comparing a[i + 1] or a[i + 2] (they are also a mismatch).
The management of this condition, particularly if it's a short sequence of repeats, may not improve running time. You have to measure.
With code changes that do not affect the order of complexity, any candidate improvements need profiling (tests that measure the performance) to verify.
The following is still a O(n*m), yet with reduced coefficient as it can step through b[] faster if a[] has repeated values that also exist in b[]. This speeds the inner b[] loop where the majority of time is consumed.
Look at the a[] pattern for distinct values to so j may be advanced faster.
Example:
#define x 0
bool Pattern3(const int *a, size_t size_a, const int *b, size_t size_b) {
static const unsigned char deltas[2][2][2][2] = { //
// What type of pattern is a[0], a[1], a[2]?
{ { { 1, 1 }, // X Y Z
{ 1, 1 } }, // X Y Y
{ { 1, 2 }, // X Y X
{ x, x } } }, // not possible
{ { { 2, 1 }, // X X Y
{ x, x } }, // not possible
{ { x, x }, // not possible
{ 2, 3 } } } }; // X X X
for (unsigned i = 0; i + 2 < size_a; i++) {
const unsigned char *delta23 = deltas[a[0] == a[1]][a[0] == a[2]][a[1] == a[2]];
for (unsigned j = 0; j + 2 < size_b;) {
if (a[0] != b[j]) {
j++;
} else if (a[0 + 1] != b[j + 1]) {
j += delta23[0];
} else if (a[0 + 2] != b[j + 2]) {
j += delta23[1];
} else {
return true;
}
}
a++;
}
return false;
}
Other minor changes which may help.
In the above, swap a,b when size_a > size_b.
Use const as lesser compilers can optimized on that.
// int consecutiveInts(int *a, int sizeA, int *b, int sizeB){
int consecutiveInts(const int *a, int sizeA, const int *b, int sizeB){
Iterate from 2. Adjust indexing accordingly.
for (i = 2 ; i < sizeA ; i++){
...
try using the following loop
for(int i=0;i<A.length;i++)
{
for(int j=0;j<A.length;j++)
{
if(A[i]==B[j])
{
count=count+1; //It checks how many times equal elements have been found
//ensure to declare and initialize int count=0;
}
}
}
if(count>=3)
System.out.println("true");
I was having some problem when trying to do a recursive in C programming. Here is the expected output:
Enter a number: 1234567
Enter the digit position: 3
rDigitValue1(): 5
rDigitvalue2(): 5
And here is my code:
int rdigitValue1(int num, int k)
{
int count = 0, output;
if (count != k) {
rdigitValue1(num / 10, k);
count++;
}
else {
output = (num % 10);
}
return output;
}
The parameter num is the number whereas the parameter k is the position. With these code, when I try to run the program, it just crashed without prompting any error message. Any idea?
Modified
void rdigitValue2(int num, int k, int *result)
{
if (k != 1) {
rdigitValue2(num / 10, k - 1, result);
*result = num;
}
else {
*result = num % 10;
}
}
You are getting a stack overflow! You are never decrementing digit position and keep looping. Your current code can be simplified to:
int rdigitValue1(int num, int k)
{
if (k != 0) {
rdigitValue1(num / 10, k);
}
}
You should use k - 1 for your recursive call, you keep testing if k == 0 and of course it never is since you keep using the same value for k. You also need to store the value returned from the recursive call so that you can return it:
output = rdigitValue1(num / 10, k - 1);
Expected output :
rDigitvalue2(): 5
Current output :
rDigitvalue2(): 1234567
The function you wrote is :
void rdigitValue2(int num, int k, int *result)
{
if (k != 1) {
rdigitValue2(num / 10, k - 1, result);
*result = num;
}
else {
*result = num % 10;
}
}
The above function works well in my g++ compiler. The value for *result in the end is 1234567 for your function because your recursive call ends in the line *result = num.
You need to remove this line and modify your function to :
void rdigitValue2(int num, int k, int *result)
{
if (k != 1) {
rdigitValue2(num / 10, k - 1, result);
}
else {
*result = num % 10;
}
}
Output : rDigitvalue2(): 5
I have an array with 5 elements (1024,1025,1026,1027,1028).How can I check these elements are in sequential or not.I could do the same if array has even number of elements.
Loop through the array and ensure the previous member (if it exists) is equal to the current minus 1.
for (int i = 1; i < 5; i++) {
if (arr[i - 1] != arr[i] - 1) {
// It's not sequential.
break;
}
}
Simply iterate through the array:
bool is_sequence(int *arr, int size)
{
int i;
for(i = 0; i < (size - 1); i++)
{
if((arr[i] + 1) != arr[i])
/* array is not sequential */
return false;
}
/* array is sequential */
return true;
}
<...>
if(is_sequence(my_array, 5))
printf("sequential!"
else
printf("not sequential");
You should compare the two neighboring numbers and you have to do the same thing for many times. So, a loop is necessary. An easy programme is as followed.
#include<stdio.h>
int main()
{
int a[5]={1024,1025,1026,1027,1028};
int i,s;
for(i=0;i<4;i=i+1)
{
if(a[i]+1 != a[i+1])
{ s=-1; break; }
else
{ s=0; }
}
if(s=0)
{ printf("sequential."); }
else
{ printf("not sequential."); }
}
I hope that my answer could help you. Thank you.
I would suggest this solution (if by saying sequential you mean just ordered):
#include <stdio.h>
int isArraySequential(int * array, int size) {
int isAscendingFirst;
int isAscendingCurrent;
int isChangeFound = 0;
int i;
// arrays of length 0/1/2 are assumed to be sequential
if (size < 3)
return 1;
for (i=1; i < size; i++) {
// in case there is a change
if (array[i] != array[i-1]) {
isAscendingCurrent = (array[i] > array[i-1]);
// on first change
if (!isChangeFound) {
isChangeFound = 1;
isAscendingFirst = isAscendingCurrent;
}
// on subsequent changes
else {
if (isAscendingFirst != isAscendingCurrent)
return 0;
}
}
}
return 1;
}
int main(){
int array1[4] = {1, 1, 0, -1};
int array2[4] = {2, 2, 2, 2};
int array3[4] = {1, 2, 4, 3};
printf("Is array1 sequential ? %d\n", isArraySequential(array1, 4));
printf("Is array2 sequential ? %d\n", isArraySequential(array2, 4));
printf("Is array3 sequential ? %d\n", isArraySequential(array3, 4));
return 0;
}
because in general sequential array can be in ascending OR descending order and this must be taken into account. Also there are corner cases - arrays of length 0/1/2 are always sequential (i am not sure about length 0).
EDIT: I've fixed code for situation when first array elements are with same values. Now it should work OK.