I am really stucked on this problem, my C code has worked very well using multidimensional arrays but i need to do the same using pointers but i'll describe the problem first.
Having the following matrix, i will get a number which will be the number of permutations (the number of swapping of columns that will move to the right and the last column will move to the first column).
For example
The number of column's permutations: 5
| 1 2 3 | -----> | 2 3 1 |
| 3 1 2 | -----> | 1 2 3 |
| 2 3 1 | -----> | 3 1 2 |
I wrote the following code using pointers, as you can see i build the matrix with multidimensional array and assign all of it into a pointer:
short elementMatrix[3][3] = {{1, 2, 3},
{3, 1, 2},
{2, 3, 1}};
short *element_matrix;
element_matrix = *elementMatrix;
int counter = 1;
while (counter <= 5)
{
for (int i = 0; i < 3; i++)
{
int temp = elementMatrix[i][PR.elem_mat_size - 1];
*outElementMatrix = *outElementMatrix + i * PR.elem_mat_size + PR.elem_mat_size - 1;
for (int j = 3 - 1; j >= 0; j--)
{
*(outElementMatrix + i * PR.elem_mat_size + j) = *(outElementMatrix + i * PR.elem_mat_size + j - 1);
if (j == 0)
{
*(outElementMatrix + i * PR.elem_mat_size + j) = *outElementMatrix;
}
}
}
counter++;
}
Since you want to swap out columns, it makes sense to have the pointers represent the columns. That way, you can swap a pointer to swap a column. So let's have an array of 3 pointers to a column.
short* col[3];
Each column consists of 3 shorts, so allocate that much memory.
for (int i = 0; i < 3; i++) {
col[i] = (short*)malloc(3 * sizeof(short));
}
Now to initialize the Matrix. This is a bit verbose, so if anyone knows a better way, edit away. :)
col[0][0] = 1; col[1][0] = 2; col[2][0] = 3;
col[0][1] = 3; col[1][1] = 1; col[2][1] = 2;
col[0][2] = 2; col[1][2] = 3; col[2][2] = 1;
Now we do the swap. Note how you need a temp variable, like Rishikesh Raje suggested. Also note that three swaps bring it back to the original, so instead of swapping n times, you only have to swap n % 3 times. Of course it's going to be pretty much instant with 5 or 2 swaps, but if you have to do like a billion, the difference should be noticeable.
for (int i = 0; i < 5; i++) {
short* temp = col[2];
col[2] = col[1];
col[1] = col[0];
col[0] = temp;
}
We assure that the result is correct by printing it:
for (int i = 0; i < 3; i++) {
printf("%d %d %d\n", col[0][i], col[1][i], col[2][i]);
}
You can consider the permutations as a rotation of each row in the matrix and, unless you have to somehow use the matrix after each step, calculate only the final result.
I'll use an extra buffer to help with the swaps.
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
// rotate the values of an array using a buffer to ease the swappings
void rotate_(size_t n, void *arr, void *tmp, size_t offset)
{
assert(n && arr && tmp && offset <= n);
// casting to perform pointer arithmetic
memcpy(tmp, (char *)arr + (n - offset), offset);
memmove((char *)arr + offset, arr, n - offset);
memcpy(arr, tmp, offset);
}
void rotate_columns_short(size_t r, size_t c, short mat[r][c], short *buf, int n)
{
// clamp the value of the offset to the number of columns
size_t offset = (n >= 0
? n % c
: c - -n % c) * sizeof(short);
// transform each row
for (short *row = &mat[0][0], *row_end = row + r * c;
row != row_end;
row += c)
{
rotate_(c * sizeof(short), row, buf, offset);
}
}
void print_matrix_short(size_t r, size_t c, short mat[r][c])
{
for (size_t i = 0; i < r; ++i)
{
for (size_t j = 0; j < c; ++j)
{
printf(" %hd", mat[i][j]);
}
puts("");
}
}
#define ROWS 3
#define COLS 3
int main(void)
{
short matrix[ROWS][COLS] = {{1, 2, 3},
{3, 1, 2},
{2, 3, 1}};
short buf[COLS];
print_matrix_short(ROWS, COLS, matrix);
puts("");
rotate_columns_short(ROWS, COLS, matrix, buf, 5);
print_matrix_short(ROWS, COLS, matrix);
}
The output beeing:
1 2 3
3 1 2
2 3 1
2 3 1
1 2 3
3 1 2
Related
This is the task I have got:
I need to write a function (not recursive) which has two parameters.
An array of integers.
An integer representing the size of the array.
The function will move the duplicates to an end of the array.
And will give the size of the different digits.
Example:
5 , 2 , 4 , 5 , 6 , 7 , 2, n = 7
we will get back 5 , 2 , 4 , 6 , 7 , 5 , 2 and 5
We must keep the original sort as it is (which means like in example 5 must)
It does not matter how we sort the duplicates ones but just keep the sort for the original array as it is)
The function has to print the number of different digits (like in example 5)
The the input range of numbers in array [-n,n]
I can only use 1 additional array for help.
It has to be O(n)
I tried it so many times and feel like am missing something. Would appreciate any advice/suggestions.
int moveDup(int* arr, int n)
{
int* C = (int*)calloc(n * 2 + 1, sizeof(int));
assert(C);
/*int* count = C + n;*/
int *D = arr[0];
int value = 0, count = 0;
for (int i = 0; i < n; i++)
{
value = arr[i];
if (C[value + n] == 0)
{
*D = arr[i];
D++;
count++;
}
C[value + n] = C[value + n] + 1;
}
while (1 < C[value + n])
{
*D = i;
D++;
C[value + n]--;
}
free(C);
return count;
}
This algorithm will produce the required results in O(n) arithmetic complexity:
Input is an array A with n elements indexed from A0 to An−1 inclusive. For each Ai, −n ≤ Ai ≤ n.
Create an array C that can be indexed from C−n to C+n, inclusive. Initialize C to all zeros.
Define a pointer D. Initialize D to point to A0.
For 0 ≤ i < n:
If CAi=0, copy Ai to where D points and advance D one element.
Increment CAi.
Set r to the number of elements D has been advanced from A0.
For −n ≤ i ≤ +n:
While 1 < CAi:
Copy i to where D points and advance D one element.
Decrement CAi.
Release C.
Return r. A contains the required values.
A sample implementation is:
#include <stdio.h>
#include <stdlib.h>
#define NumberOf(a) (sizeof (a) / sizeof *(a))
int moveDuplicates(int Array[], int n)
{
int *memory = calloc(2*n+1, sizeof *Array);
if (!memory)
{
fprintf(stderr, "Error, unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
int *count = memory + n;
int *destination = Array;
for (int i = 0; i < n; ++i)
// Count each element. If it is unique, move it to the front.
if (!count[Array[i]]++)
*destination++ = Array[i];
// Record how many unique elements were found.
int result = destination - Array;
// Append duplicates to back.
for (int i = -n; i <= n; ++i)
while (0 < --count[i])
*destination++ = i;
free(memory);
return result;
}
int main(void)
{
int Array[] = { 5, 2, 4, 5, 6, 7, 2 };
printf("There are %d different numbers.\n",
moveDuplicates(Array, NumberOf(Array)));
for (int i = 0; i < NumberOf(Array); ++i)
printf(" %d", Array[i]);
printf("\n");
}
here is the right answer, figured it out by myself.
int moveDup(int* arr, int n)
{
int* seen_before = (int*)calloc(n * 2 + 1, sizeof(int));
assert(seen_before);
int val = 0, count = 0, flag = 1;
int j = 0;
for (int i = 0; i < n; i++)
{
val = arr[i];
if (seen_before[arr[i] + n] == 0)
{
seen_before[arr[i] + n]++;
count++;
continue;
}
else if (flag)
{
j = i + 1;
flag = 0;
}
while (j < n)
{
if (seen_before[arr[j] + n] == 0)
{
count++;
seen_before[arr[j] + n]++;
swap(&arr[i], &arr[j]);
j++;
if (j == n)
{
free(seen_before);
return count;
}
break;
}
/*break;*/
j++;
if (j == n)
{
free(seen_before);
return count;
}
}
}
}
second right answer
int* mem = (int*)calloc(2 * n + 1, sizeof * arr);
assert(mem);
int* count = mem + n;
int* dest = arr;
for (i = 0; i < n; ++i)
{
if (count[arr[i]]++ == 0)
{
*dest = arr[i];
*dest++;
}
}
res = dest - arr;
for (i = -n; i <= n; ++i)
{
while (0 < --count[i])
{
*dest++ = i;
}
}
free(mem);
return res;
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> //malloc library
void ft_putchar(char c)
{
write(1, &c, 1);
}
int main(void)
{
int r;
int c;
int num;
int *map;
int i;
r = 4;
c = 4;
i = 0;
map = malloc((r * c) * (sizeof(int)));
num = 1;
while (map[i] < r * c)
{
ft_putchar(num + '0');
ft_putchar(' ');
num++;
if (num == 5)
{
ft_putchar('\n');
num = 1;
}
i++;
}
free(map);
return (0);
}
I got the code to output
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
in a 4x4 format but I need help to make it
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
in a 4x4 format.
I'm sorry if this looks silly but I'm really new to coding, any help is appreciated!
Basically, you need to rotate elements in an array left one position at a time, and then do that n-1 times for n being the length of the array.
--------------v
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
<-- <-- <--
This individual rotation broken out into a very straightforward function.
void rotate_left1(int *arr, size_t n) {
int first = arr[0];
for (size_t i = 1; i < n; ++i) {
arr[i-1] = arr[i];
}
arr[n-1] = first;
}
In your code, please note that C does allow for variable length arrays, and your map lives in main so there is no need to dynamically allocate it unless you scale it to a point where it will not be able to live on the stack.
I have modified your code to avoid the undefined behaviour in the loop condition you are not asking about in order that it will in fact run in my test:
This will rotate the sequence 1 2 3 4 on each output line.
int r = 4;
int c = 4;
int* map = malloc((r * c) * (sizeof(*map)));
int start = 0 ;
int num = start ;
for( int i = 0; i < r * c; i++ )
{
ft_putchar( num + '1');
ft_putchar(' ');
num = (num + 1) % 4 ;
if( num == start)
{
ft_putchar('\n');
start = (start + 1) % 4 ;
num = start ;
}
}
free(map);
I have removed the separate instantiation/initialisation nonsense you had - don't do that.
The solution increments the start value on each iteration and uses modulo-4 arithmetic to wrap from 3 to zero. The output is + '1' rather then + '0' because arithmetically it is easier to use 0 to 3 rather then 1 to 4 (it allows the use of the % modulo operator).
The original code wasn't making use of the map array so I modified it to first populate map then just print what's in the array.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> //malloc library
void ft_putchar(char c)
{
write(1, &c, 1);
}
int main(void)
{
int rows = 4;
int cols = 4;
char *map;
map = malloc((rows * cols) * (sizeof(char)));
for(int r = 0 ; r < rows ; ++r)
for(int c = 0 ; c < cols ; ++c)
map[(r * cols) + c] = '0' + ((r + c) % cols) + 1;
for(int i = 0 ; i < (rows * cols) ; ++i)
{
ft_putchar(map[i]);
if(i % cols == (cols - 1))
ft_putchar('\n');
}
free(map);
return 0;
}
Of course, there really isn't a need for map, and getting rid of it makes the code that much simpler:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> //malloc library
void ft_putchar(char c)
{
write(1, &c, 1);
}
int main(void)
{
int rows = 4;
int cols = 4;
for(int r = 0 ; r < rows ; ++r)
for(int c = 0 ; c < cols ; ++c)
{
ft_putchar('0' + ((r + c) % cols) + 1);
if(((r * cols) + c) % cols == (cols - 1))
ft_putchar('\n');
}
return 0;
}
p = (int *)malloc(m * n * sizeof(int));
If I use p as a two-dimensional dynamic array, how do I access the elements inside?
If you can rely on your C implementation to support variable-length arrays (an optional feature), then a pretty good way would be to declare p as a pointer to (variable-length) array instead of a pointer to int:
int (*p)[n] = malloc(m * sizeof(*p)); // m rows, n columns
Then you access elements using ordinary double indexes, just as if you had declared an ordinary 2D array:
p[0][0] = 1;
p[m-1][n-1] = 42;
int q = p[2][1];
Most widely used C implementations do support VLAs, but Microsoft's is a notable exception.
I'd personally prefer using wohlstad's method, but you could also variably-modified types, which are an optional feature of C11, but will probably be mandated in C2x:
int (*p)[m] = malloc(n * sizeof *p);
This can now be used just like a normal 2d array with automatic storage duration.
int n = 12, m = 9;
int (*p)[m] = malloc(n * sizeof *p);
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
p[i][j] = i * m + j;
printf("%d\n", p[4][2]);
free(p);
I'll assume m is the number of columns, and n the number of rows (you can use n instead of m in my answer if it's the opposite).
In order to access the 2D array, you need 2 indices - let's call them x and y:
x index will be in the range 0 .. m-1, and
y index will be in the range 0 .. n-1
You can calculate the index for your p array in the following way:
int p_idx = y * m + x
Then you can access your arrays element e.g. this way:
p[p_idx] = 111; // set an element value
int a = p[p_idx]; // get an element value
You can't use p as a two-dimensional array. It's a single integer pointer. Two-dimensional (dynamically allocated) implies nested pointers. However, you can represent a two-dimensional array in a "flattened" form. Here's some code that might offer a helpful explanation:
#include <stdio.h>
#include <stdlib.h>
int main(){
// Populating a 10x5 matrix
int m = 10;
int n = 5;
int* p = (int*) malloc(m*n*sizeof(int));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// Each row has n elements; to get the
// "flattened" index, treating the MxN
// matrix as row-major ordered (reading
// left-to-right, and THEN down the rows):
int flattened_index = (i * n) + j;
// E.g., populate with multiplication table data
p[flattened_index] = (i + 1) * (j + 1);
printf("%d\t", p[flattened_index]);
}
printf("\n");
}
// Inversely, to convert a flattened index to a
// row and column, you have to use modulus
// arithmetic
int flattened_index = 21;
int row = flattened_index / n; // Rounded-down integer division
int column = flattened_index % n; // Remainder after division
printf("%d * %d = %d\n", row + 1, column + 1, p[flattened_index]);
return 0;
}
This outputs:
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
6 12 18 24 30
7 14 21 28 35
8 16 24 32 40
9 18 27 36 45
10 20 30 40 50
5 * 2 = 10
You are actually creating a single-dimensional array. But still, we can use it to hold a matrix considering the fact in C a multidimensional array, e.g int mat[m][n], is stored in contiguous memory itself.
#include <iostream>
int main()
{
int m, n;
std::cin >> m >> n;
int* mat_ptr = (int*)malloc(m * n * sizeof(int));
if (mat_ptr)
{
for (int row = 0; row < m; ++row)
{
for (int col = 0; col < n; ++col)
{
*(mat_ptr + ((row * n) + col)) = (row * n) + col;
}
}
for (int row = 0; row < m; ++row)
{
for (int col = 0; col < n; ++col)
{
std::cout << *(mat_ptr + ((row * n) + col)) << " ";
}
std::cout << std::endl;
}
}
return 0;
}
What I want to achieve is to create a merged array of two sorted arrays, such as [0, 1, 2, 3, 4] + [2, 4, 6, 8, 10] => [0, 1, 2, 2, 3, 4, 4, 8, 10], by comparing the two elements in each array
And I am trying to apply such algorithm to dynamically allocated arrays and throwing pointer arguments to custom-made merge() function. Please refer to the following excerpt
int* merge(int*, int*);
int main(int argc, const char * argv[]) {
int* arrayA;
int* arrayB;
int* mergedArray;
int index;
arrayA = (int*) malloc(sizeof(int) * 5);
arrayB = (int*) malloc(sizeof(int) * 5);
//filling out the array A with number elements like [0, 1, 2, 3, 4]
for(index = 0; index < 5; index++){
*(arrayA + sizeof(int) * index) = index;
printf("%d", *(arrayA + sizeof(int) * index));
}
//filling out the array A with number elements like [2, 4, 6, 8, 10]
for(index = 0; index < 5; index++){
*(arrayB + sizeof(int) * index) = (index + 1) * 2;
printf("%d", *(arrayB + sizeof(int) * index));
}
printf("\n");
mergedArray = (int *) merge(arrayA, arrayB);
for(index = 0; index < 10; index++){
printf("%d", *(mergedArray + sizeof(int) * index));
}
return 0;
}
The merge functions is as follows
//My take on merge() function
int *merge(int *arrayA, int *arrayB) {
int *mergedArray;
int i = 0, j = 0, k = 0; // i for arrayA / j for arrayB / k for mergedArray
int arrayALength;
int arrayBLength;
mergedArray = (int *)malloc(sizeof(int) * 10);
arrayALength = 5;
arrayBLength = 5;
while (i < arrayALength && j < arrayBLength) {
printf("%d / %d\n", *(arrayA + (i) * sizeof(int)), *(arrayB + (j) * sizeof(int)));
if (*(arrayA + (sizeof(int) * i)) < *(arrayB + (sizeof(int) * j))) {
*(mergedArray + (k++ * sizeof(int))) = *(arrayA + (i++ * sizeof(int)));
printf("%d", *(mergedArray + (k - 1) * sizeof(int)));
} else {
*(mergedArray + (k++ * sizeof(int))) = *(arrayB + (j++ * sizeof(int)));
printf("%d", *(mergedArray + (k - 1) * sizeof(int)));
}
printf("\n");
}
for (; i < arrayALength; i++) {
*(mergedArray + (k++ * sizeof(int))) = *(arrayA + (i * sizeof(int)));
}
for (; j < arrayBLength; j++) {
*(mergedArray + (k++ * sizeof(int))) = *(arrayB + (j * sizeof(int)));
}
return mergedArray;
}
The result is...
01234
246810
0 / 2
0
1 / 2
1
2 / 2
2
2 / 4
2
4 / 4
4
4 / 0
0
4 / 1
1
4 / 2
2
0122401240Program ended with exit code: 0
If you take a look at the first line "01234" in the result, I am pretty confident that [0, 1, 2, 3, 4] is stored inside the memory where arrayA is pointing at, yet inside the merge() function if I print the corresponding element, it shows [0, 1, 2, 4], leaving out the element '3' in the middle.
Not only that the program's final result "0122401240" does show that there is logic fallacy in my code, which I could not find.
If you could see the logical error, please do not hesitate to point out one, and could you tell me why there was difference in elements in allocated memory?
Your code is really complex, you could simplify it a lot
A way to solve your issue is to make these two arrays contiguous so that you can handle it like a single array as shown in the code below
#include <stdlib.h>
#include <stdio.h>
int mysort(const void* a, const void* b){
return (*(int*)a-*(int*)b);
}
int main(){
int sz1= 5, sz2=5;
int* arr1 = malloc((sz1+sz2)*sizeof(int)); // Allocate for both arrays
int* arr2 = &arr1[sz1]; // Go to the 2nd array
my_fill(arr1); // Setup your arrays as you wish
my_fill(arr2);
qsort(arr1, sz1+sz2, sizeof(int), mysort); // Sort both arrays using the standard qsort.
}
Obviously, if you want to use a custom sorting algorithm such as merge sort, this is possible. You can replace qsort with your custom algorithm.
Your code should benefit from the fact that the input arrays are already sorted. Simply take the smallest value and copy it to the output array. For each input array maintain an index that tells you where the next unused element is.
Like:
#include <stdio.h>
#include <stdlib.h>
int* mergeSortedArraysToSingleSortedArray(int* arrA, size_t szA, int* arrB, size_t szB)
{
int* res = malloc((szA + szB) * sizeof *arrA);
if (res == NULL) return NULL;
size_t iA = 0;
size_t iB = 0;
size_t i = 0;
// Merge from A and B
while (iA < szA && iB < szB)
{
if (arrA[iA] <= arrB[iB])
{
res[i] = arrA[iA];
++iA;
}
else
{
res[i] = arrB[iB];
++iB;
}
++i;
}
// Take rest of A (if any)
while (iA < szA)
{
res[i] = arrA[iA];
++iA;
++i;
}
// Take rest of B (if any)
while (iB < szB)
{
res[i] = arrB[iB];
++iB;
++i;
}
return res;
}
int main(void)
{
int arrA[] = {0, 1, 2, 3, 4};
int arrB[] = {2, 4, 6, 8, 10};
size_t szA = sizeof(arrA)/sizeof(*arrA);
size_t szB = sizeof(arrB)/sizeof(*arrB);
int* arrMerged = mergeSortedArraysToSingleSortedArray(arrA, szA, arrB, szB);
if (arrMerged)
{
for (size_t i = 0; i < szA + szB; ++i)
{
printf("%d ", arrMerged[i]);
}
printf("\n");
}
return 0;
}
Output:
0 1 2 2 3 4 4 6 8 10
I basically need the equivalent result of the following Python itertools command in C:
a = itertools.permutations(range(4),2))
Currently my process involves first "choosing" 5 elements from 10 then generating permutations for those 5 elements as shown here
The issue with this approach is the order of the outputs. I need it to be (a), while what i get is (b), shown below.
a = itertools.permutations(range(4),2)
for i in a:
print(i)
(0, 1)
(0, 2)
(0, 3)
(1, 0)
(1, 2)
(1, 3)
(2, 0)
(2, 1)
(2, 3)
(3, 0)
(3, 1)
(3, 2)
b = itertools.combinations(range(4),2)
for i in b:
c = itertools.permutations(i)
for j in c:
print(j)
(0, 1)
(1, 0)
(0, 2)
(2, 0)
(0, 3)
(3, 0)
(1, 2)
(2, 1)
(1, 3)
(3, 1)
(2, 3)
(3, 2)
An alternate approach which I am using is as follows
void perm(int n, int k)
{
bool valid = true;
int h = 0, i = 0, j = 0, limit = 1;
int id = 0;
int perm[10] = { 0,0,0,0,0,0,0,0,0,0 };
for (i = 0; i < k; i++)
limit *= n;
for (i = 0; i < limit; i++)
{
id = i;
valid = true;
for (j = 0; j < k; j++)
{
perms[j] = id % n;
id /= n;
for (h = j - 1; h >= 0; h--)
if (perms[j] == perms[h])
{
valid = false; break;
}
if (!valid) break;
}
if (valid)
{
for (h = k - 1; h > 0; h--)
printf("%d,", perms[h]);
printf("%d\n", perms[h]);
count++;
}
}
}
Memory is my constraint, so I cannot store the permutations indefinitely. Performance needs to be better than the algorithm above, as when n is 50 and k is 10, I end up iterating through more invalid combinations(60+%)
I am aware of Heap's algorithm for generating permutations in place but again it generates for entire array not k of n like I need.
Questions.
Is there a better way to do this than iterate n^k times?
Can I make a lazy iterator which moves to next permutation given current permutation?
EDIT this is not a duplicate of std::next_permutation implementation as that will permute and entire range of the input.
I have clearly mentioned i need k of n permutation .ie if my range is 10 I want all permutations of a length (k) say 5, std::next_permutation works when length or permutation is same as length of input range
UPDATE
Here is an ugly recursive NextPerm solution which is about 4 times faster than my older solution and gives the incremental nextPerm like a Python lazy iterator.
int nextPerm(int perm[], int k, int n)
{
bool invalid = true;
int subject,i;
if (k == 1)
{
if (perm[0] == n - 1)
return 0;
else { perm[0]=perm[0]+1; return 1; }
}
subject = perm[k - 1]+1;
while (invalid)
{
if (subject == n)
{
subject = 0;
if (!nextPerm(perm, k - 1, n))
return 0;
}
for (i = 0; i < k-1; i++)
{
if (perm[i] != subject)
invalid = false;
else
{
invalid = true;subject++; break;
}
}
}
perm[k - 1] = subject;
return 1;
}
int main()
{
int a, k =3 ,n = 10;
int perm2[3] = { 0,1,2}; //starting permutation
unsigned long long count = 0;
int depth = 0;
do
{
for (a = 0; a < k - 1; a++)
printf("%d,", perm2[a]);
printf("%d\n", perm2[k - 1]);
count++;
}
while (nextPerm(perm2,k,n));
printf("\n%llu", count);
getchar();
return 0;
}
There are simple modification to the standard permutation algorithms which will produce k-permutations.
Lexicographically-ordered permutations (aka std::next_permutation)
In C++, k-permutations can be generated by the simple expedient using std::next_permutation, and just reversing the n-k-suffix of the permutation before each call to std::next_permutation.
It's reasonably clear how that works: the algorithm generates permutations in order, so the first permutation starting with a given prefix has the remaining suffix in increasing order, and the last permutation with the same prefix has its suffix in decreasing order. Decreasing order is simply the reverse of increasing order, so a single call to std::reverse is sufficient.
The lexicographical order next-permutation algorithm is very simple:
Search backwards from the end for an element which could be increased by swapping it with some later element.
Once the rightmost such element is found, find the smallest following element with which it could be swapped, and swap them.
Sort the new suffix into increasing order (by reversing it, since it was previously in decreasing order).
An advantage of the lexicographical algorithm is that it transparently handles arrays with repeated elements. As long as the number of repetitions of any given element is O(1), next-permutation is amortized O(1) (per call), and in the worst case it is O(n). When generating k-permutations, the extra flip causes the cost of next_k_permutation to be O(n-k), which is effectively O(n) if k is fixed. That's still reasonably fast, but not as fast as non-iterative algorithms which can maintain state instead of doing the search in step 1 to figure out which element to move.
The following C implementation is equivalent to std::reverse(); std::next_permutation(); (except that it swaps before reversing):
#include <stddef.h>
/* Helper functions */
static void swap(int* elements, size_t a, size_t b) {
int tmp = elements[a]; elements[a] = elements[b]; elements[b] = tmp;
}
static void flip(int* elements, size_t lo, size_t hi) {
for (; lo + 1 < hi; ++lo, --hi) swap(elements, lo, hi - 1);
}
/* Given an array of n elements, finds the next permutation in
* lexicographical order with a different k-prefix; in effect, it
* generates all k-permutations of the array.
* It is required that the suffix be sorted in ascending order. This
* invariant will be maintained by the function.
* Before the first call, the array must be sorted in ascending order.
* Returns true unless the input is the last k-permutation.
*/
int next_k_permutation(int* elements, size_t n, size_t k) {
// Find the rightmost element which is strictly less than some element to its
// right.
int tailmax = elements[n - 1];
size_t tail = k;
while (tail && elements[tail - 1] >= tailmax)
tailmax = elements[--tail];
// If no pivot was found, the given permutation is the last one.
if (tail) {
size_t swap_in;
int pivot = elements[tail - 1];
// Find the smallest element strictly greater than the pivot, either
// by searching forward from the pivot or backwards from the end.
if (pivot >= elements[n - 1]) {
for (swap_in = tail; swap_in + 1 < k && elements[swap_in + 1] > pivot; ++swap_in) {}
} else {
for (swap_in = n - 1; swap_in > k && elements[swap_in - 1] > pivot; --swap_in) {}
}
// Swap the pivots
elements[tail - 1] = elements[swap_in];
elements[swap_in] = pivot;
// Flip the tail.
flip(elements, k, n);
flip(elements, tail, n);
}
return tail;
}
Here's a simple driver and a sample run:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int intcmp(const void* a, const void* b) {
return *(int*)a < *(int*)b ? -1 :
*(int*)a > *(int*)b ? 1 :
0 ;
}
int main(int argc, char** argv) {
size_t k = (argc > 1) ? atoi(argv[1]) : 0;
if (argc < k + 2) {
fprintf(stderr, "Usage: %s K element...\n"
" where K <= number of elements\n",
argv[0]);
return 1;
}
size_t n = argc - 2;
int elements[n];
for (int i = 0; i < n; ++i) elements[i] = atoi(argv[i + 2]);
qsort(elements, n, sizeof *elements, intcmp);
do {
const char* delimiter = "";
for (size_t i = 0; i < k; ++i) {
printf("%s%2d ", delimiter, elements[i]);
delimiter = " ";
}
putchar('\n');
} while (next_k_permutation(elements, n, k));
return 0;
}
Sample run (with repeated element):
$ ./k_next_permutation 2 7 3 4 4 5
3 4
3 5
3 7
4 3
4 4
4 5
4 7
5 3
5 4
5 7
7 3
7 4
7 5
Modified Heap's algorithm
As an example of an algorithm which maintains state, Heap's algorithm can be easily modified to produce k-permutations. The only change is that when the algorithm recurses down to position n - k, the k-suffix is reported as the k-permutation and the (n-k)-prefix is transformed the way the Heap algorithm would transform it if it were run to conclusion: the prefix reversed if its length is odd and rotated one to the left if its length is even. (That's a big hint about how Heap's algorithm works, by the way.)
Using the recursive algorithm is a bit annoying because it doesn't really allow incremental permutations. However, it's simple to follow. Here, I've just passed a functor into the recursive procedure which is called with each permutation in turn.
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
/* Helper functions */
static void swap(int* elements, size_t a, size_t b) {
int tmp = elements[a]; elements[a] = elements[b]; elements[b] = tmp;
}
static void flip(int* elements, size_t lo, size_t hi) {
for (; lo + 1 < hi; ++lo, --hi) swap(elements, lo, hi - 1);
}
static void rotate_left(int* elements, size_t lo, size_t hi) {
if (hi > lo) {
int tmp = elements[lo];
for (size_t i = lo + 1; i < hi; ++i) elements[i - 1] = elements[i];
elements[hi - 1] = tmp;
}
}
/* Recursive function; the main function will fill in the extra parameters */
/* Requires hi >= lo and hi >= k. Array must have size (at least) lo + k */
static bool helper(int* array, size_t lo, size_t k, size_t hi,
bool(*process)(void*, int*, size_t), void* baton) {
if (hi == lo) {
if (!process(baton, array + lo, k)) return false;
if (lo % 2)
flip(array, 0, lo);
else
rotate_left(array, 0, lo);
}
else {
for (size_t i = 0; i < hi - 1; ++i) {
if (!helper(array, lo, k, hi - 1, process, baton))
return false;
swap(array, hi % 2 ? 0 : i, hi - 1);
}
if (!helper(array, lo, k, hi - 1, process, baton))
return false;
}
return true;
}
/* Generate all k-permutations of the given array of size n.
* The process function is called with each permutation; if it returns false,
* generation of permutations is terminated.
*/
bool k_heap_permute(int* array, size_t n, size_t k,
bool(*process)(void*, int*, size_t), void* baton) {
assert(k <= n);
return helper(array, n - k, k, n, process, baton);
}
Here's an example of its use:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
bool print_array(void* vf, int* elements, size_t n) {
FILE* f = vf;
const char* delim = "";
for (size_t i = 0; i < n; ++i) {
fprintf(f, "%s%2d", delim, elements[i]);
delim = " ";
}
putc('\n', f);
return true;
}
int main(int argc, char** argv) {
size_t k = (argc > 1) ? atoi(argv[1]) : 0;
if (argc < k + 2) {
fprintf(stderr, "Usage: %s K element...\n"
" where K <= number of elements\n",
argv[0]);
return 1;
}
size_t n = argc - 2;
int elements[n];
for (int i = 0; i < n; ++i)
elements[i] = atoi(argv[i + 2]);
k_heap_permute(elements, n, k, print_array, stdout);
return 0;
}
Sample run:
$ ./permut 2 1 5 9 7 3
7 3
9 3
5 3
1 3
1 5
7 5
9 5
3 5
3 9
1 9
7 9
5 9
5 7
3 7
1 7
9 7
9 1
5 1
3 1
7 1