I wrote a recursive version of Ackermann Function, and it worked properly:
int ackermann_r(int m, int n) {
if(m == 0) {
return n + 1;
} else if(n == 0) {
return ackermann_r(m - 1, 1);
} else {
return ackermann_r(m - 1, ackermann_r(m, n - 1));
}
}
Then I tried to rewrite the code iteratively:
(I don't know how to use 2D array using malloc, so you could feel the code is dirty...)
int ackermann_i(int m, int n) {
int* A = (int*) malloc((m+1) * (n+1) * sizeof(int));
for(int i = 0; i <= m; i++) {
for(int j = 0; j <= n; j++) {
if(i == 0) {
A[i*(n+1) + j] = j + 1;
} else if(j == 0) {
A[i*(n+1) + j] = A[(i-1)*(n+1) + 1];
} else {
A[i*(n+1) + j] = A[(i-1)*(n+1) + A[i*(n+1) + (j-1)]];
}
}
}
return A[m*(n+1) + n];
}
But the iterative version printed a wrong answer. For example:
m: 3
n: 2
recursive: 29
iterative: 3
Why my iterative code doesn't work?
Undefined behaviour
Unfortunately, your code shows undefined behaviour due to access on an uninitialized value and out-of-bounds access. The simplest test that shows this behaviour is m = 1, n = 0. This indicates only two iterations of the outer loop and one iteration of the inner loop and thus is easier to analyze:
int ackermann_i(int m, int n) {
int* A = (int*) malloc((m+1) * (n+1) * sizeof(int));
for(int i = 0; i <= m; i++) {
for(int j = 0; j <= n; j++) {
if(i == 0) {
A[i*(n+1) + j] = j + 1; // (1)
} else if(j == 0) {
A[i*(n+1) + j] = A[(i-1)*(n+1) + 1]; // (2)
} else {
A[i*(n+1) + j] = A[(i-1)*(n+1) + A[i*(n+1) + (j-1)]]; // (3)
}
}
}
return A[m*(n+1) + n];
}
So let's iterate by hand:
i = 0, j = 0. We enter (1) and set A[0 + 0] = 1.
i = 1, j = 0. We enter (2) and set A[2 + 0] = A[0 + 1].
there's always at least j == 0, so we don't care about (3).
But there's the issue: we never set A[0 + 1]. That value might be zero, it might as well be something else at random; undefined behaviour ensues. Even worse, our A is not large enough: (m+1)*(n+1) is only 2 here, so A[2] is an out-of-bound array access.
This indicate two issues:
our allocated memory isn't large enough and may never be, as the inner term in a(m, a(m-1,n)) can grow much larger than n.
if we had a solution for that, we'd need to handle the trivial cases first, e.g.
for(int j = 0; j <= (n+1); ++j) {
A[0 + j] = j + 1; // set all A[i,j] where i = 0
}
A deeper issue with the algorithm
There is however one deeper issue. Your code implies that the Ackermann function can be calculated in θ(m * n). That's however impossible. Instead, you need at least a stack or something similar that can grow in size to calculate the result. This implementation in Java provides some inspiration.
Related
I am new to C and when I do this which makes the elements in the list arranged:
#include <stdlib.h>
#include <stdio.h>
int main()
{
int list[] = {6, 4, 8, 1, 0, 9, 11, 50, 60, 10};
int i, j, aux, k;
int len = sizeof(list) / sizeof(list[0]);
for (i = 0; i < len; i++)
{
for (j = 0; j < len; j++)
{
if (list[j] > list[j + 1])
{
aux = list[j + 1];
list[j + 1] = list[j];
list[j] = aux;
}
}
}
for (k = 0; k < len; k++)
{
printf("%d ", list[k]);
}
return 0;
}
Output :
-13168 0 1 4 6 8 9 10 11 50
Why is the first value -13168?
Both your i and your j walk all the range of legal indices in the array.
But you do access list[j+1] which is one beyond the array, read there and sort the value you get from there.
As said list[j + 1] steps out of the bounds of the array, and as said using for (j = 0; j < len - 1; j++) will solve the issue.
However, as it is, the second loop will always go through the entire array and that is not needed, as the values are swapped i will be incremented and the number of needded iterations will become lesser , so you can use i iterator in the stop condition of the second loop thus optimizing it by reducing the number of iterations.
for (i = 0; i < len - 1; i++) //len - 1 is enough
{
for (j = 0; j < len - i - 1; j++) //replacing < len with < len - i - 1
{
if (list[j] > list[j + 1])
{
aux = list[j + 1];
list[j + 1] = list[j];
list[j] = aux;
}
}
}
Live demo
This is a more appropriate bubble sort.
Even for such a small array the difference in performance is noticeable, but there is still room for improvement.
When a swap no longer occurs in the loop it means that the array is sorted, so if we were to add a flag to stop ordering when this happens then you would have a very well optimized bubble sort algorithm:
int ordered = 0;
//...
for (i = 0; i < len - 1; i++)
{
ordered = 0; //reset flag
for (j = 0; j < len - i - 1; j++)
{
if (list[j] > list[j + 1])
{
aux = list[j + 1];
list[j + 1] = list[j];
list[j] = aux;
ordered = 1; //if the swap occurs, the ordering continues
}
}
if (ordered == 0) //otherwise the array is ordered and the ordering ends
break;
}
Live demo
As you can see by the testing this is a very fast bubble sort.
Benchmark results:
Your outer loop is useless. You never use i. I think you wanted:
for(i=0;i<len;i++){
for(j=0;j<i;j++){
if(list[j] > list[i]){
aux = list[i];
list[i] = list[j];
list[j] = aux;
}
}
}
When you are accessing list[j+1], you are out of bound in last iteration .
So, change inner loop to :
for(j=0;j<len-1;j++){ }
There is an error in the second loop:
for(j = 0; j < len; j++)
should be
for(j = 0; j < len - 1; j++)
I'm still a beginner when it comes to pointers and memory allocation, and I'm trying to create a function that returns the first n numbers of the Fibonacci sequence using pointers. When I try using this code, it returns random numbers but I don't know how I would fix it. Here's the code:
int* generateFibonacci(int n)
{
// make an array for n ints
int *result = malloc(n * sizeof(int));
if (result == NULL)
{
// fail
printf("I have no memory, sorry. Exiting");
exit(1);
}
result[0] = 0;
result[1] = 1;
for (int i = 0; i < n; i++)
{
result[i + 2] = result[i - 1] + result[i - 2];
}
return result;
}
If someone could point me to the right direction that would be great, thank you!
You are accessing array out of bounds in the for loop
for (int i = 0; i < n; i++)
{
result[i + 2] = result[i - 1] + result[i - 2];
}
For i = 0, i -1 and i -2 is out of bound access. Similarly, for = n-2, i+2 is accessing result[n] which is also out of bound access (array indexing goes from 0 to n-1).
You can fix this by
for (int i = 2; i < n; i++){
result[i] = result[i - 2] + result[i - 1];
}
I'm trying to create a program in C which, after every even number, will add a "0". But I have a problem. If I insert for example only even numbers (5 or more numbers) the program crashes.
Below is the program I have right now.
I would like some indications or a code sample to point out what I did wrong and how I can fix it.
void main()
{
int *a, i, n, m;
printf("dimensiune=");
scanf_s("%d", &n);
a = (int*)malloc(n*sizeof(int));
for (i = 0; i < n; i++)
{
printf("a[%d]=", i + 1);
scanf_s("%d", &a[i]);
}
for (i = 0; i < n; i++)
{
if (a[i] % 2 == 0)
{
n++;
a = (int*)realloc(a, n*sizeof(int));
for (m = n - 1; m > i;m--)
{
a[m + 1] = a[m];
}
a[i + 1] = 0;
i++;
}
}
printf("\n currently you have %d numbers in this string\n", n);
printf("your string \n");
for (i = 0; i < n; i++)
{
printf("a[%d]=%d\n", i + 1, a[i]);
}
}
Change:
for (m = n - 1; m > i;m--)
{
a[m + 1] = a[m];
}
to:
for (m = n - 1; m > i;m--)
{
a[m] = a[m-1];
}
I've just tested it, it's working for me, should work for you.
I see a problem with this loop:
for (m = n - 1; m > i;m--)
{
a[m + 1] = a[m];
}
When you start the loop, n is the number of element in the loop. During the first iteration, m is the index of the last element of the loop. So, m+1 is after the last element, creating a buffer overflow.
Thanks for all comments I solved the bug replacing void main() with int main(void) + the solution provided by Shady Programmer.
I have already designed the following algorithm that determines the binomial coefficient using a two dimensional array. For example, to calculate the binomial coefficient of n choose k, we can create a two dimensional array like so:
int[][] arr = new int[n][k];
We can populate the array in the following way:
for(int i = 0; i <= n; i++){
for(int j = 0; j <= minimum(i, k); j++){
if(j == 0 || i == j){
arr[i, j] = 1;
} else{
arr[i, j] = arr[i - 1, j - 1] + arr[i - 1, j];
}
}
}
However, I need to redesign this algorithm to use a one dimensional array from indexes 0-k. I am having a lot of trouble pinpointing how to do this. I have started in small steps, and realized some common occurrences:
If k = 0, arr[0] will be 1, and that will be returned regardless of n.
If k = 1, arr[0] will be 1, arr[1] should be n, if I'm designing it in a loop.
When I say k = 2, this is where it gets tricky, because the value of arr[2] will really depend on the previous values. I believe that as I loop (say from i = 0 to i = n), the values of arr[] will change but I can't quite grasp how. I've started with something along these lines:
for(int i = 0; i <= n; i++){
for(int j = 0; j <= minimum(i, k); j++){
if(j == 0 || i == j){
arr[j] = 1;
} else if(j == 1){
arr[j] = i;
} else{
arr[j] = ??; // I can't access previous values, because I didn't record them?
}
}
}
How should I handle this?
Here is a code which uses only one one dimensional array:
int[] coefficients = new int[k + 1];
coefficients[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = k; j >= 1; j--) {
coefficients[j] += coefficients[j - 1];
}
}
Why is it correct? To compute coefficients[j] for a fixed i, we need to know the value of coefficients[j - 1] and coefficients[j] for i - 1. If we iterate from k down to 0, we can safely record a new value for the current position because we will never need its old value.
I am trying to write a C code to generate all possible partitions (into 2 or more parts) with distinct elements of a given number. The sum of all the numbers of a given partition should be equal to the given number. For example, for input n = 6, all possible partitions having 2 or more elements with distinct elements are:
1, 5
1, 2, 3
2, 4
I think a recursive approach should work, but I am unable to take care of the added constraint of distinct elements. A pseudo code or a sample code in C/C++/Java would be greatly appreciated.
Thanks!
Edit: If it makes things easier, I can ignore the restriction of the partitions having atleast 2 elements. This will allow the number itself to be added to the list (eg, 6 itself will be a trivial but valid partition).
You don't need recursion at all. The list of numbers is essentially a stack, and by iterating in order you ensure no duplicates.
Here's a version which shows what I mean (you tagged this C, so I wrote it in C. In C++ you could use a dynamic container with push and pop, and tidy this up considerably).
#include <stdio.h>
#include <stdlib.h>
void partition(int part)
{
int *parts;
int *ptr;
int i;
int idx = 0;
int tot = 0;
int cur = 1;
int max = 1;
while((max * (max + 1)) / 2 <= part) max++;
ptr = parts = malloc(sizeof(int) * max);
for(;;) {
if((tot += *ptr++ = cur++) < part) continue;
if(tot == part) {
for(i = 0 ; i < ptr-parts ; i++) {printf("%d ",parts[i]);}
printf("\n");
}
do {
if(ptr == parts) {free(parts); return;}
tot -= cur = *--ptr;
} while(++cur + tot > part);
}
}
int main(int argc, char* argv[])
{
partition(6);
return 0;
}
What you're trying to do doesn't make a lot of sense to me but here's how I would approach it.
First, I'd create a loop that iterates i from 1 to n - 1. In the first loop, you could add the partition 1, i. Then I'd go recursive using the value in i to get all the sub-partitions that can also be added to 1.
And then continue to 2, and so on.
First, write a recursive algorithm that returns all partitions, including those that contain repeats.
Second, write an algorithm that eliminates partitions that contain duplicate elements.
EDIT:
You can avoid results with duplicates by avoiding making recursive calls for already-seen numbers. Pseudocode:
Partitions(n, alreadySeen)
1. if n = 0 then return {[]}
2. else then
3. results = {}
4. for i = 1 to n do
5. if i in alreadySeen then continue
6. else then
7. subresults = Partitions(n - i, alreadySeen UNION {i})
8. for subresult in subresults do
9. results = results UNION {[i] APPEND subresult}
10. return results
EDIT:
You can also avoid generating the same result more than once. Do this by modifying the range of the loop, so that you only add new elements in a monotonically increasing fashion:
Partitions(n, mustBeGreaterThan)
1. if n = 0 then return {[]}
2. else then
3. results = {}
4. for i = (mustBeGreaterThan + 1) to n do
5. subresults = Partitions(n - i, i)
6. for subresult in subresults do
7. results = results UNION {[i] APPEND subresult}
8. return results
I sketched this solution (it can be beautified and optimized) that shouldn't generate duplicates:
void partitions(int target, int curr, int* array, int idx)
{
if (curr + array[idx] == target)
{
for (int i=0; i <= idx; i++)
cout << array[i] << " ";
cout << endl;
return;
}
else if (curr + array[idx] > target)
{
return;
}
else
{
for(int i = array[idx]+1; i < target; i++)
{
array[idx+1] = i;
partitions(target, curr + array[idx], array, idx+1);
}
}
}
int main(){
int array[100];
int N = 6;
for(int i = 1; i < N; i++)
{
array[0] = i;
partitions(N, 0, array, 0);
}
}
It is another solution that is based on an iterative algorithm. It is much faster than #imreal's algorithm and marginally faster than #JasonD's algorithm.
Time needed to compute n = 100
$ time ./randy > /dev/null
./randy > /dev/null 0.39s user 0.00s system 99% cpu 0.393 total
$ time ./jasond > /dev/null
./jasond > /dev/null 0.43s user 0.00s system 99% cpu 0.438 total
$ time ./imreal > /dev/null
./imreal > /dev/null 3.28s user 0.13s system 99% cpu 3.435 total
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int next_partition(int *a, int* kp) {
int k = *kp;
int i, t, b;
if (k == 1) return 0;
if (a[k - 1] - a[k - 2] > 2) {
b = a[k - 2] + 1;
a[k - 2] = b;
t = a[k - 1] - 1;
i = k - 1;
while (t >= 2*b + 3) {
b += 1;
a[i] = b;
t -= b;
i += 1;
}
a[i] = t;
k = i + 1;
} else {
a[k - 2] = a[k - 2] + a[k - 1];
a[k - 1] = 0;
k = k - 1;
}
*kp = k;
return 1;
}
int main(int argc, char* argv[])
{
int n = 100;
int m = floor(0.5 * (sqrt(8*n + 1) - 1));
int i, k;
int *a;
a = malloc(m * sizeof(int));
k = m;
for (i = 0; i < m - 1; i++) {
a[i] = i + 1;
}
a[m - 1] = n - m*(m-1)/2;
for (i = 0; i < k; i++) printf("%d ", a[i]);
printf("\n");
while (next_partition(a, &k)) {
for (i = 0; i < k; i++) printf("%d ", a[i]);
printf("\n");
}
free(a);
return 0;
}