dealing with dups in end of the array - c

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;

Related

how to find the position of newArr[i] in Arr[] and implement this position in newArr[] - without duplicates

I hope i made my self clear enough in the title but if not i am here to explain my self
i got an array from an input ( like Arr = {, ).
we can use only 1 additional array (1 original 1 additional)
this is what i made so far :
I made a new array named newArr and assigned it all the values Arr contains.
i sorted it (because its requires time complexity of nlogn)
and then moved duplicates to the end.
now what i can't figure out :
now i need to move the original digits to their place according to the main
(all the values in the arrays are positive and they can be bigger then
n-which is the size of the array and ofc they can be also smaller then n)
i also need to return the number of original digits in the array
the original number should stay in the same position and the duplicates in the end of the array their order doesn't matter.
from here we can't use another additional array only the current arrays that we have ( which are 2)
i have been thinking about doing some kind of binary search but all of them went wrong.(like bin_search_first) and original binary and still couldn't manage it.
can some one give me an hint?
here is the code at where i am
#define _CRT_SECURE_NO_WARNINGS
/*Libraries*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
int* input_array(int);
int moveDuplicatesV2(int*, int);
void merge(int* a, int p, int q, int r);
void merge_sort(int* a, int first, int last);
void swap(int* v, int* u);
int bin_search_first(int , int* , int );
int main()
{
int arr[10] = { };
int n = 12;
int k = 0;
int first = 0;
int last = n - 1;
int mid = (first + last) / 2;
int l = n - 1;
int* D = arr + 1;
int j = 0;
size_t dupes_found = 0;
int* newArr = (int*)malloc(12 * sizeof(int));
assert(newArr);
for (int i = 0; i < n; i++)
{
newArr[i] = arr[i];
}
merge_sort(newArr, first, last);
for (size_t i = 0; i < n - 1 - dupes_found;)
{
if (newArr[i] == newArr[i + 1])
{
dupes_found++;
int temp = newArr[i];
memmove(&newArr[i], &newArr[i + 1], sizeof(int) * (n - i - 1));
newArr[n - 1] = temp;
}
else {
i++;
}
}
j = 0;
int key = 0;
first = 0;
for (int i = 0; i < n - dupes_found; i++)
{
key = newArr[i];
first = bin_search_first(key, arr,n);
swap(&newArr[i], &newArr[first]);
newArr[first] = newArr[i];
}
for (int i = 0; i < n; i++)
{
arr[i] = newArr[i];
}
for (int i = 0; i < n; i++)
{
printf("%d", arr[i]);
}
return n - dupes_found;
}
void merge(int* a, int p, int q, int r)
{
int i = p, j = q + 1, k = 0;
int* temp = (int*)malloc((r - p + 1) * sizeof(int));
assert(temp);
while ((i <= q) && (j <= r))
if (a[i] < a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
while (j <= r)
temp[k++] = a[j++];
while (i <= q)
temp[k++] = a[i++];
/* copy temp[] to a[] */
for (i = p, k = 0; i <= r; i++, k++)
a[i] = temp[k];
free(temp);
}
void merge_sort(int* a, int first, int last)
{
int middle;
if (first < last) {
middle = (first + last) / 2;
merge_sort(a, first, middle);
merge_sort(a, middle + 1, last);
merge(a, first, middle, last);
}
}
void swap(int* v, int* u)
{
int temp;
temp = *v;
*v = *u;
*u = temp;
}
int bin_search_first(int key, int* a, int n)
{
int low, high, mid;
low = 0;
high = n - 1;
while (low <= high)
{
mid = (low + high) / 2; // low + (high - low) / 2
if (key > a[mid])
low = mid + 1;
else
if (key < a[mid])
high = mid - 1;
else //key==a[mid]
if ((low == high) || (a[mid - 1] < key))
return mid;
else
high = mid - 1;
}
return -1;
}
Here is my idea:
Sort the array (nlogn)
Loop over the array and for each value, save a pointer to its first occurence (n)
Loop over the original array and insert the value into a result array if it is the values first occurrence. Whether or not it is the first occurrence can be checked using the sorted array: each element in this array has an additional flag that will be set if the value has already been seen. So, search for the element using bsearch, if seen append to back of result array (order does not matter), if not seen append to beginning of array and set seen value. (nlogn, since bsearch doesn't need to seek the first element because it was precomputed thus logn, over the array n)
Here is an example code (you can replace the qsort by mergesort to make the algorithm actually nlogn, I just used qsort because it is given):
#include <stdio.h>
#include <stdlib.h>
struct arr_value {
int value;
int seen;
struct arr_value *first;
};
int compar(const void *p1,const void *p2) {
struct arr_value *v1 = (struct arr_value *)p1;
struct arr_value *v2 = (struct arr_value *)p2;
if(v1->value < v2->value) {
return -1;
} else if(v1->value == v2->value) {
return 0;
}
return 1;
}
int main()
{
#define NumCount (12)
int arr[NumCount] = { 7, 3, 1, 2, 7, 9, 3, 2, 5, 9, 6, 2 };
int arrResult[NumCount];
int resultCount = 0;
int resultCountBack = 0;
struct arr_value arrseen[NumCount];
for(int i = 0; i < NumCount; ++i) {
arrseen[i].value = arr[i];
arrseen[i].seen = 0;
}
qsort(arrseen, NumCount, sizeof(struct arr_value), compar);
struct arr_value *firstSame = arrseen;
firstSame->first = firstSame;
for(int i = 1; i < NumCount; ++i) {
if(arrseen[i].value != firstSame->value) {
firstSame = arrseen + i;
}
arrseen[i].first = firstSame;
}
struct arr_value key;
for(int i = 0; i < NumCount; ++i) {
key.value = arr[i];
struct arr_value *found = (struct arr_value *)bsearch(&key, arrseen, NumCount, sizeof(struct arr_value), compar);
struct arr_value *first = found->first;
if(first->seen) {
// value already seen, append to back
arrResult[NumCount - 1 - resultCountBack] = first->value;
++resultCountBack;
} else {
// value is new, append
arrResult[resultCount++] = first->value;
first->seen = 1;
}
}
for(int i = 0; i < NumCount; ++i) {
printf("%d ", arrResult[i]);
}
return 0;
}
Output:
7 3 1 2 9 5 6 2 9 2 3 7
To begin with, memmove doesn't run in a constant time, so the loop
for (size_t i = 0; i < n - 1 - dupes_found;)
{
if (newArr[i] == newArr[i + 1])
{
dupes_found++;
int temp = newArr[i];
memmove(&newArr[i], &newArr[i + 1], sizeof(int) * (n - i - 1));
newArr[n - 1] = temp;
}
else {
i++;
}
}
drives the time complexity quadratic. You have to rethink the approach.
It seems that you are not using a crucial point:
all the values in the arrays are positive
It seriously hints that changing values to their negatives is a way to go.
Specifically, as you iterate over the initial array, and bin-search its elements in temp, comparing the _ absolute values_. When an element is found in temp, and it is still positive there, flip all its dupes in temp to negative. Otherwise flip it in initial.
So far, it is O(n log n).
Then perform an algorithm known as stable_partition: all positives are moved in front of negatives, retaining the order. I must not spell it here - I don't want to deprive you of a joy figuring it out yourself (still O(n log n)
And finally flip all negatives back to positives.

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.

Find longest sub-array with no repetitions

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");
}

I need help creating a k-combinations algorithm non-recursively

I've looked around online for an non-recursive k-combinations algorithm, but have had trouble understanding all of the reindexing involved; The code I've found online is not commented well, or crashes.
For example, if I have the collection, {'a', 'b', 'c', 'd', 'e'} and I want to find a 3 combinations; ie,
abc
abd
abe
acd
ace
ade
bcd
bce
bde
cde
How can I implement an algorithm to do this? When I write down the general procedure, this it is clear. That is; I increment the last element in a pointer until it points to 'e', increment the second to last element and set the last element to the second to last element + 1, then increment the last element again until it reaches 'e' again, and so on and so forth, as illustrated by how I printed the combinations. I looked at Algorithm to return all combinations of k elements from n for inspiration, but my code only prints 'abc'. Here is a copy of it:
#include <stdio.h>
#include <stdlib.h>
static void
comb(char *buf, int n, int m)
{
// Initialize a pointer representing the combinations
char *ptr = malloc(sizeof(char) * m);
int i, j, k;
for (i = 0; i < m; i++) ptr[i] = buf[i];
while (1) {
printf("%s\n", ptr);
j = m - 1;
i = 1;
// flag used to denote that the end substring is at it's max and
// the j-th indice must be incremented and all indices above it must
// be reset.
int iter_down = 0;
while((j >= 0) && !iter_down) {
//
if (ptr[j] < (n - i) ) {
iter_down = 1;
ptr[j]++;
for (k = j + 1; k < m; k++) {
ptr[k] = ptr[j] + (k - j);
}
}
else {
j--;
i++;
}
}
if (!iter_down) break;
}
}
int
main(void)
{
char *buf = "abcde";
comb(buf, 5, 3);
return 1;
}
The very big problem with your code is mixing up indices and values. You have an array of chars, but then you try to increment the chars as if they were indices into the buffer. What you really need is an array of indices. The array of chars can be discarded, since the indices provide all you need, or you can keep the array of chars separately.
I found a psuedocode description here, http://www4.uwsp.edu/math/nwodarz/Math209Files/209-0809F-L10-Section06_03-AlgorithmsForGeneratingPermutationsAndCombinations-Notes.pdf
and implemented it in C by
#include <stdlib.h>
#include <stdio.h>
// Prints an array of integers
static void
print_comb(int *val, int len) {
int i;
for (i = 0; i < len; i++) {
printf("%d ", val[i]);
}
printf("\n");
}
// Calculates n choose k
static int
choose(int n, int k)
{
double i, l = 1.0;
double val = 1.0;
for (i = 1.0; i <= k; i++) {
l = ((double)n + 1 - i) / i;
val *= l;
}
return (int) val;
}
static void
comb(int n, int r)
{
int i, j, m, max_val;
int s[r];
// Initialize combinations
for (i = 0; i < r; i++) {
s[i] = i;
}
print_comb(s, r);
// Iterate over the remaining space
for (i = 1; i < choose(n, r); i++) {
// use for indexing the rightmost element which is not at maximum value
m = r - 1;
// use as the maximum value at an index, specified by m
max_val = n - 1; // use for
while(s[m] == max_val) {
m--;
max_val--;
}
// increment the index which is not at it's maximum value
s[m]++;
// iterate over the elements after m increasing their value recursively
// ie if the m-th element is incremented, all elements afterwards are
// incremented by one plus it's offset from m
// For example, this is responsible for switching 0 3 4 to 1 2 3 in
// comb(5, 3) since 3 and 4 in the first combination are at their maximum
// value
for (j = m; j < r - 1; j++) {
s[j + 1] = s[j] + 1;
}
print_comb(s, r);
}
}
int
main(void)
{
comb(5, 3);
return 1;
}

intersection and union of n-arrays in C

I have those functions which are making intersection/union but just of two arrays.
I need too improve them to work with n-arrays: arr = {{1,2,3},{1,5,6},...,{1,9}}.
The arrays are sorted , and their elements are unique among them.
Example (intersection):
Input: {{1,2,3,4},{2,5,4},{4,7,8}}
Output: {4}
arr1[],arr2 - arrays
m,n - length of the arrays
Intersection function:
int printIntersection(int arr1[], int arr2[], int m, int n)
{
int i = 0, j = 0;
while(i < m && j < n)
{
if(arr1[i] < arr2[j])
i++;
else if(arr2[j] < arr1[i])
j++;
else /* if arr1[i] == arr2[j] */
{
printf(" %d ", arr2[j++]);
i++;
}
}
}
and union function:
int printUnion(int arr1[], int arr2[], int m, int n)
{
int i = 0, j = 0;
while(i < m && j < n)
{
if(arr1[i] < arr2[j])
printf(" %d ", arr1[i++]);
else if(arr2[j] < arr1[i])
printf(" %d ", arr2[j++]);
else
{
printf(" %d ", arr2[j++]);
i++;
}
}
while(i < m)
printf(" %d ", arr1[i++]);
while(j < n)
printf(" %d ", arr2[j++]);
}
union(a, b, c) = union(union(a, b), c), and the same goes for intersection(). I.e. you can decompose the union or intersection of n sets into n unions or intersections of 2 sets (as NuclearGhost points out in a comment on the question). What you need to do is change your current functions so that they build up a resulting set, instead of immediately printing the result. You can then make a separate function that prints a set.
For efficiency, you want to take the union or intersection of sets that are roughly of equal size. So a divide-and-conquer approach should work alright, assuming that all input sets are likely to be of roughly equal size.
void intersection(int arr1[], int arr2[], int m, int n, int *out)
{
int i = 0, j = 0;
while(i < m && j < n)
{
if(arr1[i] < arr2[j])
i++;
else if(arr2[j] < arr1[i])
j++;
else /* if arr1[i] == arr2[j] */
{
*out++ = arr2[j++];
i++;
}
}
}
void multi_intersection(int n, int **arrays, int *lengths, int *out) {
if (n == 2) {
intersection(arrays[0], arrays[1], lengths[0], lengths[1], out);
} else if (n == 1) {
memcpy(out, arrays[0], lengths[0] * sizeof (int));
} else {
/* Allocate buffers large enough */
int *buf[2];
int len[2] = { INT_MAX, INT_MAX };
int i;
for (i = 0; i < n; ++i) {
int which = i < n / 2;
if (lengths[i] < len[which]) len[which] = lengths[i];
}
buf[0] = malloc(len[0] * sizeof (int));
buf[1] = malloc(len[1] * sizeof (int));
/* Recurse to process child subproblems */
multi_intersection(n / 2, arrays, lengths, buf[0]);
multi_intersection(n - n / 2, arrays + n / 2, lengths + n / 2, buf[1]);
/* Combine child solutions */
intersection(buf[0], buf[1], len, out);
free(buf[0]);
free(buf[1]);
}
Similar code works for multi_union(), except that the buffer lengths need to be calculated differently: the result of a union could be as large as the sum of the sizes of the inputs, rather than the minimum size of the inputs. It could probably be rewritten to do less buffer allocation. Also the recursion could be rewritten to use iteration, the same way mergesort can be written to use iteration, but the current recursive approach uses only O(log n) additional stack space anyway.
presume the max value in arrays is less than K. N is the number of arrays
int Result[K] = {0};
intersection function
//input array1
int index = 0;
for(; index < arrary1len;index++)
{
Result[array1]++;
}
.....
for(index = 0; index < K; index++)
{
if(Result[index] == N)
printf("%d",index);
}

Resources