Is this a good compromise between readability and verbosity? Are there any bugs, additional error checking, or extraneous code as well?
// Generate permutations of array of n..n+x
// n must have no repetitions, sorted smallest to largest
// Steinhaus-Johnson-Trotter algorithm
// Results are not in lexicographical order
// Switch to using a generator when n! becomes too large. ~12 or 13 probably.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum directions { LEFT, RIGHT };
int **permute(int array[], int n);
bool mobile(int array[], int dir[], int count, int n);
void swap(int array[], int a, int b);
void printArray(int *array, int n, char c);
long long factorial(int n);
int **permute(int array[], int n) {
if (n < 1) {
return NULL;
}
int bigInd; // index of largest mobile num
int bigNum; // largest mobile num
bool ismobile; // If there is still a mobile number
int counter = 0;
int fact = factorial(n);
int *dir;
int **res;
if ((dir = malloc(n * sizeof(int))) == NULL) {
fprintf(stderr, "Error allocating memory\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < n; i++) {
dir[i] = LEFT;
}
if ((res = malloc(fact * sizeof(int *))) == NULL) {
fprintf(stderr, "Error allocating memory\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < fact; i++) {
if ((res[i] = malloc(n * sizeof(int))) == NULL) {
fprintf(stderr, "Error allocating memory\n");
exit(EXIT_FAILURE);
}
}
while (1) {
memcpy(res[counter], array, n * sizeof(int));
counter++;
bigInd = 0;
bigNum = 0;
ismobile = false;
for (int i = 0; i < n; i++) {
if (mobile(array, dir, n, i)) {
ismobile = true;
if (array[i] > bigNum) {
bigInd = i;
bigNum = array[i];
}
}
}
if (!ismobile) {
break;
}
if (dir[bigInd] == LEFT) {
swap(array, bigInd, bigInd - 1);
swap(dir, bigInd, bigInd - 1);
} else {
swap(array, bigInd, bigInd + 1);
swap(dir, bigInd, bigInd + 1);
}
for (int i = 0; i < n; i++) {
if (array[i] > bigNum) {
dir[i] = !(dir[i]);
}
}
}
free(dir);
return res;
}
void swap(int array[], int a, int b) {
int temp = array[a];
array[a] = array[b];
array[b] = temp;
}
bool mobile(int array[], int dir[], int count, int n) {
if ((n == 0 && dir[n] == LEFT) || (n + 1 == count && dir[n] == RIGHT) ||
(dir[n] == RIGHT && array[n + 1] > array[n]) ||
(dir[n] == LEFT && array[n - 1] > array[n])) {
return false;
}
return true;
}
void printArray(int array[], int n, char c) {
if (!array || n < 1) {
return;
}
for (int i = 0; i < n; i++) {
printf("%d", array[i]);
}
printf("%c", c);
}
long long factorial(int n) {
long long result = 1;
for (long long i = n; i > 1; i--) {
result *= i;
}
return result;
}
int main(void) {
int a[] = {1, 2, 3, 4, 5};
int length = sizeof(a) / sizeof(a[0]);
int fact = factorial(length);
int **r = permute(a, length);
for (long long i = 0; i < fact; i++) {
printf("%*lld: ", 3, i + 1);
printArray(r[i], length, '\n');
}
for (long long i = 0; i < fact; i++) {
free(r[i]);
}
free(r);
}