Ошибка сортировки слиянием: ошибка сегментации - PullRequest
0 голосов
/ 08 мая 2018

Я получаю сообщение об ошибке Segmentation Fault:11, пожалуйста, помогите. информация о переменной: (s: начало, e: конец, m: середина, n: массив), тестирование для выборочного массива n[] = {4,3,2,1}. a1 и a2 - временные массивы. Я предполагаю, что есть что-то с вычислением m:mid и передачей.

#include <stdio.h>

void merge(int s, int e, int m, int n[]) {
    int l1 = m - s;
    int l2 = e - m + 1;
    int a1[l1];
    int a2[l2];
    for (int i = 0; i < l1; i++) {
        a1[i] = n[s + i];
    }
    for (int j = 0; j < l2; j++) {
        a2[j] = n[s + m + j];
    }

    int i = 0, j = 0; 
    for (int k = 0; k < l1 + l2; k++) {
        if (a1[i] <= a2[j] && i != l1 && j != l2) {
            n[k] = a1[i];
            i++;
        } else if (a2[j] <= a1[i] && i != l1 && j != l2) {
            n[k] = a2[j];
            j++;
        } else if (j == l2 && i != l1) {
            n[k] = a1[i];
            i++;
        } else if(i == l1 && j != l2) {
            n[k] = a2[j];
            j++;
        }
    }
}

void mergeSort(int s, int e, int n[]) {
    if (s < e) {
        int m = (e - s) / 2;
        mergeSort(s, m - 1, n);
        mergeSort(m, e, n);
        merge(s, e, m, n);
    }
}

int main(void) {
    int n[] = { 4, 3, 2, 1 };
    int r = 4;
    mergeSort(0, r - 1, n);

    for(int i = 0; i < r; i++) {
        printf("%i\n", n[i]);
    }
}

Ответы [ 3 ]

0 голосов
/ 08 мая 2018

Я думаю, что у вас проблема переполнения стека из-за бесконечных рекурсивных вызовов. Смотри

void mergeSort(int s, int e, int n[]){
    if(s<e){
        int m = (e-s)/2;
        mergeSort(s, m-1, n);
        mergeSort(m, e, n);
        merge(s,e,m, n);
    }

}

Вы передаете эти значения s и e:

s e function
-------------
0 3 mergeSort
    0 0 mergeSort -> end
    1 3 mergeSort
        0 0 mergeSort -> end
        1 3 mergeSort
            ... (infinite calls)

Затем стек растет и растет, пока новые функции вызываются, пока, в конце концов, он не превысит максимально возможный размер, что приводит к SEGFAULT.

0 голосов
/ 08 мая 2018

Вычисление m для среднего элемента является поддельным: вы получаете смещение m от s, а не его индекс в массиве.

Вот исправленная версия:

void mergeSort(int s, int e, int n[]) {
    if (s < e) {
        int m = s + (e - s + 1) / 2;
        mergeSort(s, m - 1, n);
        mergeSort(m, e, n);
        merge(s, e, m, n);
    }
}

В вашем коде есть другие проблемы, а именно:

  • Вы должны проверить смещения i и j до dereferencing a1 [i] and a2 [j] `.
  • смещение k не должно использоваться непосредственно в фазе слияния, его следует хранить в n[s + k].
  • в цикле инициализации для a2, вы должны использовать a2[j] = n[m + j]; вместо a2[j] = n[s + m + j];

Обратите внимание, что идиоматично передавать диапазоны в C с включенным первым индексом и последним исключенным индексом. Это позволяет пропускать пустые диапазоны, чего нет у вашего текущего метода. Это также делает код намного проще и легче для чтения.

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

#include <stdio.h>

void merge(int s, int e, int m, int n[]) {
    int l1 = m - s;
    int l2 = e - m;
    int a1[l1];
    int a2[l2];

    for (int i = 0; i < l1; i++) {
        a1[i] = n[s + i];
    }
    for (int j = 0; j < l2; j++) {
        a2[j] = n[m + j];
    }
    for (int i = 0, j = 0, k = 0; k < l1 + l2; k++) {
        if (i < l1 && (j >= l2 || a1[i] <= a2[j])) {
            n[s + k] = a1[i];
            i++;
        } else {
            n[s + k] = a2[j];
            j++;
        }
    }
}

void mergeSort(int s, int e, int n[]) {
    if (e > s + 1) {
        int m = s + (e - s) / 2;
        mergeSort(s, m, n);
        mergeSort(m, e, n);
        merge(s, e, m, n);
    }
}

int main(void) {
    int n[] = { 4, 3, 2, 1 };
    int r = sizeof(n) / sizeof(n[0]);
    mergeSort(0, r, n);

    for(int i = 0; i < r; i++) {
        printf("%i\n", n[i]);
    }
    return 0;
}
0 голосов
/ 08 мая 2018

Я изменил ваш код в нескольких местах. Попробуйте использовать отладчик или ручку и бумагу, чтобы понять, что происходит под капотом.

void merge(int s, int e, int m, int n[]){

    int l1 = m-s + 1;
    int l2 = e - m;
    int a1[l1];
    int a2[l2];
    for(int i = 0; i < l1; i++){
        a1[i] = n[s+i];
    }
    for(int j = 0; j < l2; j++){
        a2[j] = n[m+j + 1];

    }


    int i = 0, j = 0; 
    for(int k = 0; k < l1+l2; k++){
        if(a1[i] <= a2[j] && i != l1 && j != l2){
            n[k] = a1[i];
            i++;
        }else if(a2[j] <= a1[i] && i != l1 && j != l2){
            n[k] = a2[j];
            j++;
        }else if(j == l2 && i != l1){
            n[k] = a1[i];
            i++;
        }else if(i == l1 && j != l2){
            n[k] = a2[j];
            j++;
        }
    }

}
void mergeSort(int s, int e, int n[]){
        if(s<e){
            int m = s + (e-s)/2;
            mergeSort(s, m, n);
            mergeSort(m + 1, e, n);
            merge(s,e,m, n);
}

Думаю, с тобой все будет в порядке.

...