Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging multiple sorted arrays in C

Trying to merge 8 pre-sorted arrays. I'm fairly new to C, but this is what I've come up with so far. Needless to say it doesn't work. What I can't figure out is why. I've based it off the C++ mergesort implementation here and tried to extend it to 8 dimensions and simplify it a bit, but for some reason it tends to give me the elements of the first array, followed by 34, 30 then it repeats 23 until the end. It doesn't even pick up that 21 is the smallest value on the first iteration.

int test1[5] = {23, 24, 25, 33, 51};
int test2[5] = {21, 34, 44, 50, 62};
int test3[5] = {34, 36, 41, 44, 46};
int test4[5] = {30, 31, 32, 35, 40};
int test5[5] = {54, 56, 57, 58, 60};
int test6[5] = {31, 33, 36, 51, 52};
int test7[5] = {44, 46, 76, 78, 79};
int test8[5] = {23, 33, 43, 54, 63};

int output[40];
int t1, t2, t3, t4, t5, t6, t7, t8;
t1 = 0;
t2 = 0;
t3 = 0;
t4 = 0;
t5 = 0;
t6 = 0;
t7 = 0;
t8 = 0;
int p = 0;
int temp1;
int temp2;

while(p < 40) {
    if (t1 < 5) {
        temp1 = 1;
        temp2 = test1[t1];
    }else if (test2[t2] <= test1[t1] && t2 < 5) {
        temp1 = 2;
        temp2 = test2[t2];
    }else if (test3[t3] <= temp2 && t3 < 5) {
        temp1 = 3;
        temp2 = test3[t3];
    }else if (test4[t4] <= temp2 && t4 < 5) {
        temp1 = 4;
        temp2 = test4[t4];
    }else if (test5[t5] <= temp2 && t5 < 5) {
        temp1 = 5;
        temp2 = test5[t5];
    }else if (test6[t6] <= temp2 && t6 < 5) {
        temp1 = 6;
        temp2 = test6[t6];
    }else if (test7[t7] <= temp2 && t7 < 5) {
        temp1 = 7;
        temp2 = test7[t7];
    }else if (test8[t8] <= temp2 && t8 < 5) {
        temp1 = 8;
        temp2 = test8[t8];
    }
    switch(temp1) {
        case 1:
            output[p] = temp2;
            t1++;
            break;
        case 2:
            output[p] = temp2;
            t2++;
            break;
        case 3:
            output[p] = temp2;
            t3++;
            break;
        case 4:
            output[p] = temp2;
            t4++;
            break;
        case 5:
            output[p] = temp2;
            t5++;
            break;
        case 6:
            output[p] = temp2;
            t6++;
            break;
        case 7:
            output[p] = temp2;
            t7++;
            break;
        case 8:
            output[p] = temp2;
            t8++;
            break;
    }
    printf("%d\n",  output[p]);
    p++;
}

Thanks for any help you can offer.

like image 853
Andrewnopoulos Avatar asked May 27 '12 14:05

Andrewnopoulos


2 Answers

This is why you get the first 5 elements of the first array:

if (t1 < 5) {
        temp1 = 1;
        temp2 = test1[t1];

Your code is specifically ensuring the first 5 elements of the first array get selected first. You should be comparing the value of the next element in test1 against the next element in the other arrays, not just blindly picking it. Also, your use of if..then..else if.. else if... is not correct. If you find out that array 2's next element is less than array 1's next element, you still have to examine whether arrays 3, 4 and 5 are less.

Try structuring your code like this

int temp1 = -1;
if (t1 < 5) {
    temp1=1;
    temp2=test1[t1];
}
if ((t2 < 5) && ((temp1 < 0) || (test2[t2] < temp2))) {
    temp1=2;
    temp2=test2[t2];
}
if (t3...

followed by your existing switch statement.

like image 63
hatchet - done with SOverflow Avatar answered Sep 28 '22 07:09

hatchet - done with SOverflow


hatchet already told you what went wrong, if ... else if ... will execute the second block if and only if the second condition is valid and the first one wasn't valid.

However, I believe your switch() and if-else based program is a little bit hard to extend, since you need to change all the fixed fields and values to sort another set of arrays. The following program/function provides the same as yours, but is easier to extend. It uses an additional array cursor to save the current position (similar to your t1,t2,...) (Ideone Demo).

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int multimerge(
    int * const * const arrays,      // arrays holding the data
    int const * const arraysizes,    // sizes of the arrays in `arrays`
    int number_of_arrays,            // number of arrays
    int * const output               // pointer to output buffer
){
    int i = 0;       // output cursor
    int j = 0;       // index for minimum search
    int min;         // minimum in this iteration
    int minposition; // position of the minimum

    // cursor for the arrays
    int * cursor = calloc(number_of_arrays,sizeof(int));

    if(cursor == NULL)
        return -1;

    while(1){
        min = INT_MAX;
        minposition = -1; // invalid position

        // Go through the current positions and get the minimum
        for(j = 0; j < number_of_arrays; ++j){

            if(cursor[j] < arraysizes[j] &&  // ensure that the cursor is still valid
               arrays[j][cursor[j]] < min){  // the element is smaller
                min = arrays[j][cursor[j]];  // save the minimum ...
                minposition = j;             // ... and its position
            }
        }

        // if there is no minimum, then the position will be invalid

        if(minposition == -1)
            break;

        // update the output and the specific cursor            
        output[i++] = min;
        cursor[minposition]++;
    }
    free(cursor);

    return 0;
}

int main()
{
    int i = 0;
    int test1[5] = {23, 24, 25, 33, 51};
    int test2[5] = {21, 34, 44, 50, 62};
    int test3[5] = {34, 36, 41, 44, 46};
    int test4[5] = {30, 31, 32, 35, 40};
    int test5[5] = {54, 56, 57, 58, 60};
    int test6[5] = {31, 33, 36, 51, 52};
    int test7[5] = {44, 46, 76, 78, 79};
    int test8[5] = {23, 33, 43, 54, 63};

    int *test[] = {test1, test2, test3, test4, test5, test6, test7, test8};
    int testsizes[] = {5,5,5,5,5,5,5,5};

    int output[40];

    multimerge(test,testsizes,8,output);

    while(i < 30){
        printf("%i\n",output[i++]);
    }    

    return 0;
}
like image 36
Zeta Avatar answered Sep 28 '22 07:09

Zeta