Почему дополнительный элемент добавляется в мой массив void **, когда я использую сортировку слиянием? - PullRequest
1 голос
/ 08 апреля 2019

Когда я использую mergeSort для сортировки массива void** (этот массив содержит void* указатели, которые указывают на целые числа), в массив добавляется дополнительный 1 (новый элемент).Я почти уверен, что проблема в mergeSort или merge, так как при печати моего void** массива перед вызовом mergeSort данные верны (просто не отсортированы).Вот код:

#define SIZE 10

void mergeSort(void**, int, int);
void merge(void**, int, int, int);
int compare(void*, void*);

int main(void) {
    int array[SIZE] = { 5, 6, 3, 2, 5, 6, 7, 4, 9, 3 };
    void *voidArray[SIZE];
    int query = 1;
    void *queryPointer = &query;

    for (int j = 0; j < SIZE; j++) {
        voidArray[j] = &array[j];
    }

    printArray(voidArray);
    mergeSort(voidArray, 0, SIZE);
    printArray(voidArray);
    result = binarySearch(voidArray, 0, SIZE, queryPointer);

    if (result == -1) {
        puts("Query not found.");
        return(0);
    }

    printf("Query found at index %d.\n", result);
    return(0);
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void mergeSort(void **array, int head, int tail) {
    if (head < tail) {
        int middle = (head + ((tail - head) / 2));
        mergeSort(array, head, middle);
        mergeSort(array, (middle + 1), tail);
        merge(array, head, middle, tail);
    }
}

void merge(void **array, int head, int middle, int tail) {
    int headLength = (middle - head + 1);
    int tailLength =  (tail - middle);
    void *headSide[headLength];
    void *tailSide[tailLength];

    for (int i = 0; i < headLength; i++) {
        headSide[i] = array[head + i];
    }

    for (int j = 0; j < tailLength; j++) {
        tailSide[j] = array[middle + 1 + j];
    }

    int k = head;
    int l = 0;
    int m = 0;
    while (l < headLength && m < tailLength) {
        if (compare(headSide[l], tailSide[m]) == -1) {
            array[k] = headSide[l];
            l++;      
        } else {  
            array[k] = tailSide[m];
            m++;
        }
        k++;
    }

    while (l < headLength) {
        array[k] = headSide[l];
        l++;
        k++;
    }

    while (m < tailLength) {
        array[k] = tailSide[m];
        m++;
        k++;
    }
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

int compare(void *index, void *query) {
    if (*((int *)index) == *((int *)query)) {
        return (0);
    }

    if (*((int*)index) > *((int*)query)) {
        return (1);        
    }

    return (-1);
}

Выходные данные должны иметь несортированный массив, отсортированный массив и был ли найден запрос.В несортированном массиве нет 1, но в отсортированном массиве есть 1;также, число 9 отсутствует в отсортированных результатах (интересно, если я выполню двоичный поиск для 9, он скажет мне, что 9 найден в индексе 10).

Пример вывода (для запроса 1):

5 6 3 2 5 6 7 4 9 3
1 2 3 3 4 5 5 6 6 7

Запрос найден по индексу 0.

Ответы [ 3 ]

0 голосов
/ 11 апреля 2019
headSide[i] = array[head + i];

headSide[i] равно void и array[head + i] равно void*

0 голосов
/ 16 апреля 2019

Существует некоторая путаница в аргументах margeSort и merge.Передача индекса последнего элемента в диапазоне не является идиоматической в ​​C. Гораздо проще передать индекс элемента после конца диапазона, что согласуется с передачей 0 и SIZE int main(): mergeSort(voidArray, 0, SIZE); и result = binarySearch(voidArray, 0, SIZE, queryPointer);

Вот модифицированная версия с этим API:

void mergeSort(void **array, int head, int tail) {
    if (tail - head > 1) {
        int middle = head + (tail - head) / 2);
        mergeSort(array, head, middle);
        mergeSort(array, middle, tail);
        merge(array, head, middle, tail);
    }
}

void merge(void **array, int head, int middle, int tail) {
    int headLength = middle - head;
    int tailLength = tail - middle;
    void *headSide[headLength];
    void *tailSide[tailLength];

    for (int i = 0; i < headLength; i++) {
        headSide[i] = array[head + i];
    }
    for (int j = 0; j < tailLength; j++) {
        tailSide[j] = array[middle + j];
    }

    int k = head;
    int l = 0;
    int m = 0;
    while (l < headLength && m < tailLength) {
        if (compare(headSide[l], tailSide[m]) <= 0) {
            array[k++] = headSide[l++];
        } else {  
            array[k++] = tailSide[m++];
        }
    }
    while (l < headLength) {
        array[k++] = headSide[l++];
    }
    while (m < tailLength) {
        array[k++] = tailSide[m++];
    }
}

Обратите внимание, что при выделении временных массивов headSide и tailSide с автоматическим хранением ( в стеке ) опасно для больших массивов.Кроме того, нет необходимости сохранять элементы из правой половины в tailSide, так как они не будут перезаписаны до их копирования в конечную позицию.Вот более простая версия merge:

void merge(void **array, int head, int middle, int tail) {
    int headLength = middle - head;
    void *headSide[headLength];

    for (int i = 0; i < headLength; i++) {
        headSide[i] = array[head + i];
    }

    int k = head;
    int l = 0;
    while (l < headLength && middle < tail) {
        if (compare(headSide[l], array[middle]) <= 0) {
            array[k++] = headSide[l++];
        } else {  
            array[k++] = array[middle++];
        }
    }
    while (l < headLength) {
        array[k++] = headSide[l++];
    }
}
0 голосов
/ 08 апреля 2019

Проверьте свой индекс массива.

int tailLength =  (tail - middle)

tail - размер массива, я думаю, tailLength неверно.

...