Объединение 2-х быстро отсортированных массивов дает все 0 - PullRequest
0 голосов
/ 03 мая 2019

Я использую многопоточную программу для сортировки массива. Сначала я разделил массив на 2 половины. 1 поток сортирует первую половину, другой поток сортирует вторую половину, а последний поток объединяет две половины вместе. Я использую быструю сортировку, чтобы отсортировать каждую половину. Проблема в том, что когда я печатаю отсортированный массив, это просто 0 с.

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

* примечание: mainarr - глобальная переменная, объявленная как: int *mainarr

//function to merge two halves in result array
void merge(int l[], int r[], int size_left, int size_right)
{
    //iterator variables, start at 0
    int i = 0, j = 0, k = 0;

    // Traverse both array
    while (i < size_left && j < size_right)
    {
        if (l[i] < r[j]){
            mainarr[k] = l[i];
            i++;
            k++;
        }
        else{
            mainarr[k] = r[j];
            k++;
            j++;
        }
    }

    // Store remaining elements of first array
    while (i < size_left){
        mainarr[k] = l[i];
        k++;
        i++;
    }

    // Store remaining elements of second array
    while (j < size_right){
        mainarr[k] = r[j];
        k++;
        j++;
    }
}

//compare function for qsort
int compare(const void *a, const void *b){
    return (*(int*)a - *(int*)b);
}

//thread begins control in this function
//this function is called from pthread_create
void *runner(void* param) {
    int threadID = atoi(param);
    int midpoint = size/2, index, r;
    int *left = malloc(midpoint*sizeof(int));
    int *right = malloc((size-midpoint)*sizeof(int));

    //if first thread, sort "left" array
    if(threadID == 1){
        int i;
        index=0;
        //create "left" array
        for(i=0; i < midpoint; i++){
            left[index] = mainarr[i];
            index++;
        }
        //sort array
        qsort(left, midpoint, sizeof(int), compare);
        printf("LEFT array: ");
        for(r = 0; r < size; r++)
            printf("%d ", left[r]);
    }
    //if second thread, sort "right" array
    else if(threadID == 2){
        int j;
        index=0;
        //create "right" array
        for(j=midpoint; j < size; j++){
            right[index] = mainarr[j];
            index++;
        }
        //sort array
        qsort(right, (size-midpoint), sizeof(int), compare);
        printf("RIGHT array: ");
        for(r = 0; r < size; r++)
            printf("%d ", right[r]);
    }
    //if third thread, merge the left and right arrays
    else if(threadID == 3){
        merge(left, right, 4, 5);
    }

    //empty else to satisfy convention
    else{}

    pthread_exit(0);
}

В качестве примера я использовал массив [7,0,2,33,234,1,3,67,54]. Итак, я ожидаю, что отсортированный «левый» массив будет [0,2,7,33], отсортированный «правый» массив будет [1,3,54,67,234], а весь отсортированный массив будет [0,1,2,3,7,33,54,67,234]. Однако фактический отсортированный «левый» массив равен [0, 2, 7, 33, 0, 0, 37, 0, 0], фактический отсортированный «правый» массив равен [1, 3, 54, 67, 234, 0, 132881, 0, 0], а фактический весь отсортированный массив равен [0, 0, 0, 0, 0, 0, 0, 0, 0]

.

Я не уверен, в чем проблема - будь то потоки, перезапись памяти или что-то еще. Все помогает, спасибо.

ОБНОВЛЕНИЕ / РЕШЕНИЕ: Я неправильно использую левый и правый пределы операторов if, поэтому при запуске нового потока он очищает содержимое левого и правого массивов, приводя к результату всех 0.

1 Ответ

2 голосов
/ 03 мая 2019

Однако фактически отсортированный «левый» массив равен [0, 2, 7, 33, 0, 0, 37, 0, 0],

Нет, это не такt.

фактический отсортированный «правильный» массив равен [1, 3, 54, 67, 234, 0, 132881, 0, 0]

Нет, этоне.

Вы печатаете элементы за пределами выделенных границ этих массивов.Результирующее поведение не определено.Вам (не) повезло, что программа не просто аварийно завершает работу.Обратите внимание, что значения в фактических границах этих массивов соответствуют ожидаемым.

фактический весь отсортированный массив равен [0, 0, 0, 0, 0, 0, 0, 0, 0]

В некотором роде.

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

На самом деле я не вижу смысла в отдельном потоке слияния.Слияние не может быть выполнено до тех пор, пока не завершатся два потока быстрой сортировки, и, поскольку оно не может выполняться одновременно с другими, я не вижу причин не оставлять эту работу для основного потока.В целом, я предлагаю следующее:

  • Один (новый) поток каждый для быстрой сортировки двух половин массива.В качестве альтернативы, один новый поток для одной половины, а основной поток обрабатывает другую.
  • Выполнение стандартной быстрой сортировки на месте вместо того, чтобы потоки выполняли какое-либо распределение памяти или копирование во временное пространство.
  • После того, как основной поток присоединяется к другим (и), он выполняет само слияние.
...