Find longest sub-array with no repetitions - c

The task is to find the longest contiguous sub-array with all elements distinct.
Example Input {4, 3, 1, 3, 2, 1, 0} Output {3, 2, 1, 0}
Algorithm
Extract first sub Array (here 431)
Extract second sub Array (here 31)
Compare number of elements and keep the array with the biggest number (keep 431)
Return to 2
Problem The output is incorrect
/* Free old array and replace it by the new array
* If we only want to free old array and replace it by a new array
* Function will free old array and replace it by a new array with size equal to maximum size it can have
* Maximum size is the size of the input array
*/
int* newArray(int* oldArray,int* newArray, int sizeArray, int sizeFArray)
{
if (newArray == NULL) {
int* temp = malloc(sizeFArray * sizeof(int));
if (temp == NULL)
exit(1);
return temp;
} else {
memcpy(oldArray, newArray, sizeArray);
return oldArray;
}
printf("Error");
exit(1);
}
//int isAvailable(int* array , int size, int number) checks if number is available in array (return 0 if true, 1 if false)
//printArray(int* array, int size) is a simple function to print an array
void subArray(int* inputArray, int sizeInputArray)
{
int* candidate = malloc(sizeInputArray * sizeof(int));
if (candidate == NULL)
exit(1);
int sizeCandidate = 0;
int* newCandidate = malloc(sizeInputArray * sizeof(int));
if (newCandidate == NULL)
exit(1);
int sizeNewCandidate = 0;
//We will first fill the candidate
while (sizeCandidate < sizeInputArray && isAvailable(candidate, sizeCandidate, *(inputArray + sizeCandidate)) != 0) {
*(candidate + sizeCandidate) = *(inputArray + sizeCandidate);
sizeCandidate++;
}
int index = 1;
//Check all potential new candidates
//If new candidate holds more elements than the current candidate
//Current candidate will be replaced by new candidate
//Else we will redo the process and check using the next candidate if availble
for (int i = 1; i < sizeInputArray; i++) {
if(isAvailable(newCandidate, sizeNewCandidate, *(inputArray + i)) == 0) {
if (sizeNewCandidate > sizeCandidate) {
candidate = newArray(candidate, newCandidate, sizeNewCandidate, sizeInputArray);
newCandidate = newArray(newCandidate, NULL, 0, 0);
sizeCandidate = sizeNewCandidate;
sizeNewCandidate = 0;
i = ++index;
} else {
newCandidate = newArray(newCandidate, NULL, 0, sizeInputArray);
sizeNewCandidate = 0;
i = ++index;
}
} else {
*(newCandidate + sizeNewCandidate) = *(inputArray + i);
sizeNewCandidate++;
}
}
printArray(candidate, sizeCandidate);
}

I hope this code looks more compact and has clear comments:
#include <stdio.h>
int a[] = { 4, 3, 1, 3, 2, 1, 0 };
int check(int a[], int i, int j)
{
for (int k = i; k < j; k++)
for (int l = k + 1; l < j; l++)
if (a[k] == a[l])
return 0;
return 1;
}
int main()
{
int s = 0; // start position of the best candidate
int m = 1; // length of the best candidate
int n = sizeof(a) / sizeof(0); // length of the array
for (int i = 0; i < n; i++) { // for every start position
for (int j = i + m + 1; j <= n; j++) { // for every lengh if it more than the best one
if (check(a, i, j)) { // check if it contains repetitions
if (j - i > m) { // if no repetions
s = i; // update the candidate
m = j - i; // and length
}
}
else
break;
}
}
printf("{%d", a[s]);
for(int i = s + 1; i < s + m; ++i)
printf(", %d", a[i]);
printf("}\n");
return 0;
}
This works and gives the correct output.

I don't understand the complexity of the code.
#include <stdio.h>
int main()
{
// int x[] = { 4, 3, 1, 3, 2, 1, 0 };
int x[] = { 4, 3, 1, 3, 2, 5, 0 };
int offset;
int cur_offset = 0;
int max = 0;
int max_offset = 0;
for (int i = 1; i < sizeof(x) / sizeof(int); i++) {
for (int j = i-1; j >= cur_offset; j--) {
if (x[i] == x[j]) {
if (max <= i - j) {
max = i - j;
max_offset = j + 1;
} else if (max_offset == cur_offset) {
max = i - max_offset;
}
cur_offset = j + 1;
break;
}
}
}
if (max < sizeof(x) / sizeof(int) - cur_offset) {
max_offset = cur_offset;
max = sizeof(x) / sizeof(int) - max_offset;
}
printf("%d", x[max_offset]);
for (int i = max_offset + 1; i < max_offset + max; i++)
printf(", %d", x[i]);
printf("\n");
}

Related

dealing with dups in end of the array

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;

Memory allocation mistake on C

I am trying to split set of numbers to 2 different heaps, from their middle value. I used heap data structure to do this. i.e Input is 10 in this example. Apparently I am making some mistake while allocating memory, it gives the following output when I try to allocate dynamically:
[ 4 3 2 0 1 ]
[ 0 0 0 0 0 ]
why the second heap is always 0 ?
Because if I uncomment the static memory allocation and use it instead, it gives true output which is:
[ 4 3 2 0 1 ]
[ 9 8 7 5 6 ]
I have tested my heap and other parts well enough, I am pretty sure the problem is on memory allocation but I couldn't find out where the mistake is.
int main(int argc, char *argv[])
{
int M = atoi(argv[1]);
int pq_1_size = M / 2;
int pq_2_size = M - pq_1_size;
int *a;
int *b;
a = (int *)malloc(pq_1_size * sizeof(int));
b = (int *)malloc(pq_2_size * sizeof(int));
for (int i = 0; i < pq_1_size; i++) {
a[i] = i;
}
for (int j = pq_1_size; j < M; j++) {
b[j] = j;
}
//int a[5] = { 0, 1, 2, 3, 4 }; // if I use this section instead it works fine.
//int b[5] = { 5, 6, 7, 8, 9 }; // if I use this section instead it works fine.
Heap someHeap = { 0, {0} };
Heap *A = &someHeap;
buildHeap(A, a, pq_1_size);
//buildHeap(A, a, 5);
print(A);
printf("\n");
Heap anotherHeap = { 0, {0} };
Heap *B = &anotherHeap;
buildHeap(B, b, pq_2_size);
//buildHeap(B, b, 5);
print(B);
return 0;
}
Below is the heap code:
#define HEAPSIZE 500
#define left(i) ((i)<<1)
#define right(i) (((i)<<1)+1)
#define parent(i) ((i)>>1)
typedef struct {
int size;
int element[HEAPSIZE];
} Heap;
//Swaps the values of two ints a and b
void swap(int * a, int * b) {
int temp;
temp = * a;
* a = * b;
* b = temp;
}
//Ensures that the max heap property in heap A is satisfied at and below index i
void makeHeap(Heap * A, int i) {
int largest = A->element[i];
int position = i;
int l = left(i);
if(l <= A->size && A->element[l] > largest) {
largest = A->element[l];
position = l;
}
int r = right(i);
if(r <= A->size && A->element[r] > largest) {
largest = A->element[r];
position = r;
}
if(i != position) {
swap(&A->element[i], &A->element[position]);
makeHeap(A, position);
}
}
//Get the maximum value in the heap A
int extractMax(Heap * A) {
if(!A->size) {
puts("error: heap empty");
return 0;
}
int max = A->element[0];
swap(&A->element[0], &A->element[A->size]);
--A->size;
makeHeap(A, 0);
return max;
}
//Increase the key of the ith element in heap A to be k
void increaseKey(Heap * A, int i, int k) {
if(A->element[i] >= k) {
printf("error: %d is less than the key of %d\n", k, i);
return;
}
int position = i;
while(position != 0 && A->element[parent(position)] < k) {
A->element[position] = A->element[parent(position)];
position = parent(position);
}
A->element[position] = k;
}
//Inserts the value i into the heap A
void insert(Heap * A, int i) {
if(A->size >= HEAPSIZE) {
printf("error: heap full\n");
return;
}
A->element[A->size] = INT_MIN;
increaseKey(A, A->size, i);
++A->size;
}
//Prints the heap A as an array
void print(Heap * A) {
int i = 0;
printf("[ ");
for(i = 0; i < A->size; i++) {
printf("%d ", A->element[i]);
}
printf("]\n");
}
//Makes a heap out of an unsorted array a of n elements
void buildHeap(Heap * A, int * a, int n) {
if(n > HEAPSIZE) {
printf("error: too many elements\n");
return;
}
if(A->size) {
printf("error: heap not empty\n");
return;
}
int nbytes = n * sizeof(int);
memcpy(A->element, a, nbytes);
A->size = n;
int i = 0;
for(i = A->size/2; i >= 0; i--) {
makeHeap(A, i);
}
}
You forgot that arrays are using index values starting from 0.
int pq_1_size = M / 2;
int pq_2_size = M - pq_1_size; << This is either M/2 or M/2+1
a = (int *)malloc(pq_1_size * sizeof(int));
b = (int *)malloc(pq_2_size * sizeof(int));
for (int i = 0; i < pq_1_size; i++) {
a[i] = i;
}
for (int j = pq_1_size; j < M; j++) {
b[j] = j; << j is in range M/2 .. M-1 but must be in range 0..M/2-1
This means you are writing out of bounds for the second array which causes undefined behaviour.
You must adjust the index accordingly:
for (int j = pq_1_size; j < M; j++) {
b[j-pq_1_size] = j;
or
for (int j = 0; j < pq_2_size; j++) {
b[j] = j+pq_1_size;
Regarding your questions:
Why the second heap is always 0?
That is just by accident. Memory allocated via malloc has no determined content. It can contain any values. You cannot rely on anything. As your loop does not touch the correct elements of that memory, you get these "random" values.
Why does it work if you use an initialized array?
If you use
int b[5] = { 5, 6, 7, 8, 9 };
you have an array that contains the provided values starting from index 0.

How can I combine two arrays and output stored values as it`s written in description. May be there are some ways to do that?

Task description -> Whole task description is here
I have done part with sorting and got stuck.
How can I combine these arrays in one of already sorted pairs?
printf("\nHeight of boys in descending order\n");
for (i = (LENGTH1 - 1); i >= 0; i--)
{
printf("%d ", heightBoys[i]);
}
for (i = 0; i < LENGTH2; i++)
{
for (j = 0; j < (LENGTH2 - j - 1); j++)
{
if (heightGirls[j] > heightGirls[j+1])
{
temp = heightGirls[j];
heightGirls[j] = heightGirls[j+1];
heightGirls[j+1] = temp;
}
}
}
printf("\nHeight of girls in descending order\n");
for (j = (LENGTH2 - 1); j >= 0; j--)
{
printf("%d ", heightGirls[j]);
}
You have a sort [for the girls], but it is broken. Change:
for (j = 0; j < (LENGTH2 - j - 1); j++)
Into:
for (j = 0; j < (LENGTH2 - i - 1); j++)
To avoid [needless] replication of code, put the sorting code into a separate function.
Sort both arrays.
Take the minimum of the lengths of the two arrays (e.g. minlen).
I'm not sure what you mean [exactly] by "pairing", but the simplest is to print the pairing
Then, just loop on:
for (i = 0; i < minlen; ++i)
printf("Girl:%d Boy:%d\n",heightGirls[i],heightBoys[i]);
If you needed something more complex, you might need an array of structs like:
struct pair {
int boyheight;
int girlheight;
};
This array would need to be at least minlen in length. You could fill it in by adapting the final print loop.
But, if you're just printing, here is some sample code:
#include <stdio.h>
void
print_single(const int *height,int len,const char *sex)
{
printf("\nHeight of %s in descending order\n",sex);
for (int i = (len - 1); i >= 0; i--)
printf(" %d", height[i]);
printf("\n");
}
void
sort_height(int *height,int len)
{
for (int i = 0; i < len; i++) {
for (int j = 0; j < (len - i - 1); j++) {
if (height[j] > height[j + 1]) {
int temp = height[j];
height[j] = height[j + 1];
height[j + 1] = temp;
}
}
}
}
int
main(void)
{
int heightBoys[] = { 5, 8, 7, 9, 6 };
int heightGirls[] = { 3, 1, 2 };
int LENGTH1 = sizeof(heightBoys) / sizeof(heightBoys[0]);
int LENGTH2 = sizeof(heightGirls) / sizeof(heightGirls[0]);
sort_height(heightBoys,LENGTH1);
print_single(heightBoys,LENGTH1,"boys");
sort_height(heightGirls,LENGTH2);
print_single(heightGirls,LENGTH2,"girls");
int minlen = LENGTH1;
if (minlen > LENGTH2)
minlen = LENGTH2;
printf("\n");
printf("Pairing:\n");
for (int i = 0; i < minlen; ++i)
printf("Girl:%d Boy:%d\n",heightGirls[i],heightBoys[i]);
return 0;
}
UPDATE:
Let's say that we input heights and number of them by ourselves. If we have extra heights of boys or girls, how can we output these extra heights apart from the rest?
Two additional for loops appended to the bottom should do the trick. In order for this to work, the iteration variable of the final for loop in the previous example must be defined outside the loop. In other words, notice the definition and usage of ipair below.
If you are creating an array the type of struct that I suggested, these loops can fill it in. The array size would then need to be max(LENGTH1,LENGTH2).
And, in unpaired loops (e.g. for boy 8, the girl value in the struct could be set to 0 or -1 to indicate that the boy is unpaired)
#include <stdio.h>
void
print_single(const int *height,int len,const char *sex)
{
printf("\nHeight of %s in descending order\n",sex);
for (int i = (len - 1); i >= 0; i--)
printf(" %d", height[i]);
printf("\n");
}
void
sort_height(int *height,int len)
{
for (int i = 0; i < len; i++) {
for (int j = 0; j < (len - i - 1); j++) {
if (height[j] > height[j + 1]) {
int temp = height[j];
height[j] = height[j + 1];
height[j + 1] = temp;
}
}
}
}
int
main(void)
{
int heightBoys[] = { 5, 8, 7, 9, 6 };
int heightGirls[] = { 3, 1, 2 };
int LENGTH1 = sizeof(heightBoys) / sizeof(heightBoys[0]);
int LENGTH2 = sizeof(heightGirls) / sizeof(heightGirls[0]);
sort_height(heightBoys,LENGTH1);
print_single(heightBoys,LENGTH1,"boys");
sort_height(heightGirls,LENGTH2);
print_single(heightGirls,LENGTH2,"girls");
int minlen = LENGTH1;
if (minlen > LENGTH2)
minlen = LENGTH2;
int ipair = 0;
printf("\n");
printf("Pairing:\n");
for (; ipair < minlen; ++ipair)
printf("Girl:%d Boy:%d\n",heightGirls[ipair],heightBoys[ipair]);
if (ipair < LENGTH1) {
printf("\n");
printf("Unpaired Boys:\n");
for (int i = ipair; i < LENGTH1; ++i)
printf("Boy:%d\n",heightBoys[i]);
}
if (ipair < LENGTH2) {
printf("\n");
printf("Unpaired Girls:\n");
for (int i = ipair; i < LENGTH2; ++i)
printf("Girl:%d\n",heightGirls[i]);
}
return 0;
}

Knapsacks problem 1/0 dynamic

I want to solve the knapsack problem with dynamic programming! The item should be in the knapsack or not, I do not want to put the same item in the knapsack more then one time!
I've looked at this code but with this one you can add the same object more then just one time
#include <stdio.h>
#define MAXWEIGHT 100
int n = 3; /* The number of objects */
int c[10] = {8, 6, 4}; /* c[i] is the *COST* of the ith object; i.e. what
YOU PAY to take the object */
int v[10] = {16, 10, 7}; /* v[i] is the *VALUE* of the ith object; i.e.
what YOU GET for taking the object */
int W = 10; /* The maximum weight you can take */
void fill_sack() {
int a[MAXWEIGHT]; /* a[i] holds the maximum value that can be obtained
using at most i weight */
int last_added[MAXWEIGHT]; /* I use this to calculate which object were
added */
int i, j;
int aux;
for (i = 0; i <= W; ++i) {
a[i] = 0;
last_added[i] = -1;
}
a[0] = 0;
for (i = 1; i <= W; ++i)
for (j = 0; j < n; ++j)
if ((c[j] <= i) && (a[i] < a[i - c[j]] + v[j])) {
a[i] = a[i - c[j]] + v[j];
last_added[i] = j;
}
for (i = 0; i <= W; ++i)
if (last_added[i] != -1)
printf("Weight %d; Benefit: %d; To reach this weight I added object %d (%d$ %dKg) to weight %d.\n",
i, a[i], last_added[i] + 1, v[last_added[i]],
c[last_added[i]], i - c[last_added[i]]);
else
printf("Weight %d; Benefit: 0; Can't reach this exact weight.\n", i);
printf("---\n");
aux = W;
while ((aux > 0) && (last_added[aux] != -1)) {
printf("Added object %d (%d$ %dKg). Space left: %d\n",
last_added[aux] + 1, v[last_added[aux]],
c[last_added[aux]], aux - c[last_added[aux]]);
aux -= c[last_added[aux]];
}
printf("Total value added: %d$\n", a[W]);
}
int main(int argc, char *argv[]) {
fill_sack();
return 0;
}
and then i tried to make a array to see if the object is in the knapsack or not, but then this program did not work as it should!
#define MAXWEIGHT 101
#define MAX_ITEMS 100000
int items = 2;
int c[10] = {1, 2};
int v[10] = {1000, 2001};
int W = 100;
int taken[MAX_ITEMS];
void takenOrNot(){
int i;
for(i = 0; i < items; i++){
taken[i] = 0;
}
}
void fill_sack() {
int a[MAXWEIGHT];
int last_added[MAXWEIGHT];
int i, j;
int aux;
for (i = 0; i <= W; ++i) {
a[i] = 0;
last_added[i] = -1;
}
a[0] = 0;
for (i = 1; i <= W; ++i)
for (j = 0; j < items; ++j)
if ((c[j] <= i) && (a[i] < a[i - c[j]] + v[j]) && taken[j] == 0) {
a[i] = a[i - c[j]] + v[j];
last_added[i] = j;
taken[j] = 1;
}
for (i = 0; i <= W; ++i)
if (last_added[i] != -1)
printf("Weight %d; Benefit: %d; To reach this weight I added object %d (%d$ %dKg) to weight %d.\n",
i, a[i], last_added[i] + 1, v[last_added[i]],
c[last_added[i]], i - c[last_added[i]]);
else
printf("Weight %d; Benefit: 0; Can't reach this exact weight.\n", i);
printf("---\n");
aux = W;
while ((aux > 0) && (last_added[aux] != -1)) {
printf("Added object %d (%d$ %dKg). Space left: %d\n",
last_added[aux] + 1, v[last_added[aux]],
c[last_added[aux]], aux - c[last_added[aux]]);
aux -= c[last_added[aux]];
}
printf("Total value added: %d$\n", a[W]);
}
int main(int argc, char *argv[]) {
takenOrNot();
fill_sack();
return 0;
}
Could you guys help me please? :)
This might help...!
public class Knapsack
{
int knapsackSize;
int[] _weights;
int[] _values;
int[,] results;
public Knapsack(int[] weights, int[] values, int size)
{
_weights = weights;
_values = values;
knapsackSize = size;
}
public int CreateSolution()
{
results = new int[_weights.Length + 1, knapsackSize + 1];
for (int i = 0; i < _weights.Length; i++) // item 1 to n
{
for (int j = 1; j <= knapsackSize; j++) //weight 1 to m
{
if (_weights[i] > j)
{
//if item weight is grater than knapsack capacity
results[i + 1, j] = results[i, j];
}
else
{
if (results[i, j] > (_values[i] + results[i, j - _weights[i]]))
{
//if previously calculated value only is grater
results[i + 1, j] = results[i, j];
}
else
{
//if including current item gives more value
results[i + 1, j] = _values[i] + results[i, j - _weights[i]];
}
}
}
}
return results[_weights.Length, knapsackSize]; // index (n, m) will be max value
}
static void Main(string[] args)
{
Knapsack demo = new Knapsack(new int[] { 23, 26, 20, 18, 32, 27, 29, 26, 30, 27 }, new int[] { 505, 352, 458, 220, 354, 414, 498, 545, 473, 543 }, 67);
Console.WriteLine("Solution is: " + demo.CreateSolution());
Console.ReadLine();
}
}

Enumerating Permutations of a set of subsets

I have sets S1 = {s11,s12,s13), S2 = {s21,s22,s23) and so on till SN.I need to generate all the permutations consisting elements of S1,S2..SN.. such that there is only 1 element from each of the sets.
For eg:
S1 = {a,b,c}
S2 = {d,e,f}
S3 = {g,h,i}
My permuations would be:
{a,d,g}, {a,d,h}, {a,d,i}, {a,e,g}, {a,e,h}....
How would I go about doing it? (I could randomly go about picking up 1 from each and merging them, but that is even in my knowledge a bad idea).
For the sake of generality assume that there are 'n' elements in each set. I am looking at implementing it in C. Please note that 'N' and 'n' is not fixed.
It's just a matter of recursion. Let's assume these definitions.
const int MAXE = 1000, MAXN = 1000;
int N; // number of sets.
int num[MAXN]; // number of elements of each set.
int set[MAXN][MAXE]; // elements of each set. i-th set has elements from
// set[i][0] until set[i][num[i]-1].
int result[MAXN]; // temporary array to hold each permutation.
The function is
void permute(int i)
{
if (i == N)
{
for (int j = 0; j < N; j++)
printf("%d%c", result[j], j==N-1 ? '\n' : ' ');
}
else
{
for (int j = 0; j < num[i]; j++)
{
result[i] = set[i][j];
permute(i+1);
}
}
}
To generate the permutations, simply call permute(0);
If you know exactly how many sets there are and it's a small number one might normally do this with nested loops. If the number of sets is greater than 2 or 3, or it is variable, then a recursive algorithm starts to make sense.
And if this is homework, it's likely that implementing a recursive algorithm is the object of the entire assignment. Think about it, for each set, you can call the enumeration function recursively and have it start enumerating the next set...
If they are in a container, just iterate through each:
#include <stdio.h>
int main(void)
{
int set1[] = {1, 2, 3};
int set2[] = {4, 5, 6};
int set3[] = {7, 8, 9};
for (unsigned i = 0; i < 3; ++i)
{
for (unsigned j = 0; j < 3; ++j)
{
for (unsigned k = 0; k < 3; ++k)
{
printf("(%d, %d, %d)", set1[i], set2[j], set3[k]);
}
}
}
return 0;
}
Generic solution:
typedef struct sett
{
int* nums;
int size;
} t_set;
inline void swap(t_set *set, int a, int b)
{
int tmp = set->nums[a];
set->nums[a] = set->nums[b];
set->nums[b] = tmp;
}
void permute_set(t_set *set, int from, void func(t_set *))
{
int i;
if (from == set->size - 1) {
func(set);
return;
}
for (i = from; i < set->size; i++) {
swap(set, from, i);
permute_set(set, from + 1, func);
swap(set, i, from);
}
}
t_set* create_set(int size)
{
t_set *set = (t_set*) calloc(1, sizeof(t_set));
int i;
set->size = size;
set->nums = (int*) calloc(set->size, sizeof(int));
for(i = 0; i < set->size; i++)
set->nums[i] = i + 1;
return set;
}
void print_set(t_set *set) {
int i;
if (set) {
for (i = 0; i < set->size; i++)
printf("%d ", set->nums[i]);
printf("\n");
}
}
int main(int argc, char **argv)
{
t_set *set = create_set(4);
permute_set(set, 0, print_set);
}
This is a fairly simple iterative implementation which you should be able to adapt as necessary:
#define SETSIZE 3
#define NSETS 4
void permute(void)
{
char setofsets[NSETS][SETSIZE] = {
{ 'a', 'b', 'c'},
{ 'd', 'e', 'f'},
{ 'g', 'h', 'i'},
{ 'j', 'k', 'l'}};
char result[NSETS + 1];
int i[NSETS]; /* loop indexes, one for each set */
int j;
/* intialise loop indexes */
for (j = 0; j < NSETS; j++)
i[j] = 0;
do {
/* Construct permutation as string */
for (j = 0; j < NSETS; j++)
result[j] = setofsets[j][i[j]];
result[NSETS] = '\0';
printf("%s\n", result);
/* Increment indexes, starting from last set */
j = NSETS;
do {
j--;
i[j] = (i[j] + 1) % SETSIZE;
} while (i[j] == 0 && j > 0);
} while (j > 0 || i[j] != 0);
}
You may think about the elements of a set as values of a cycle counter. 3 sets means 3 for cycles (as in GMan answare), N sets means N (emulated) cycles:
#include <stdlib.h>
#include <stdio.h>
int set[3][2] = { {1,2}, {3,4}, {5,6} };
void print_set( int *ndx, int num_rows ){
for( int i=0; i<num_rows; i++ ) printf("%i ", set[i][ndx[i]] );
puts("");
}
int main(){
int num_cols = sizeof(set[0])/sizeof(set[0][0]);
int num_rows = sizeof(set)/sizeof(set[0]);
int *ndx = malloc( num_rows * sizeof(*ndx) );
int i=0; ndx[i] = -1;
do{
ndx[i]++; while( ++i<num_rows ) ndx[i]=0;
print_set( ndx, num_rows );
while( --i>=0 && ndx[i]>=num_cols-1 );
}while( i>=0 );
}
The most efficient method I could come up with (in C#):
string[] sets = new string[] { "abc", "def", "gh" };
int count = 1;
foreach (string set in sets)
{
count *= set.Length;
}
for (int i = 0; i < count; ++i)
{
var prev = count;
foreach (string set in sets)
{
prev = prev / set.Length;
Console.Write(set[(i / prev) % set.Length]);
Console.Write(" ");
}
Console.WriteLine();
}

Resources