C ++ - сортировка слиянием - не могу определить, что не так

0

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

Вот мой код:

#include <iostream>
#include <array>

int num;
int * array = new int [num];
int * sub = new int [num];

void sort (int low, int mid, int high) {
    std::cout << "Low, mid, high: " << low << ", " << mid << ", " << high << ".\n";

    int a,b,c,d;
    a = low;
    b = low;
    c = mid;

    while ((a < mid) && (c < high)) {
        if (array[a] < array[c]) {
            sub[b] = array[a];
            a++;
        } else {
            sub[b] = array[c];
            c++;
        }
        b++;
    }
    while (a == mid && c < high) {
        sub[b] = array[c];
        c++;
        b++;
    }
    while (c == high && a < mid) {
        sub[b] = array[a];
        a++;
        b++;
    }
    for (d = low; d < high; d++) {
        array[d] = sub[d];
        for (int i = 0; i < num; i++) {
            std::cout << array[i];
            if (i != num - 1) {
                std::cout << ", ";
            } else {
                std::cout << ".\n";
            }
        }
    }
    std::cout << "Done!\n";
}
void split (int low, int high) {
    if (low < high - 1) {
        int mid = (low + high) / 2;
        split(low, mid);
        split(mid, high);
        sort(low, mid, high);
    }
}

int main()
{
    std::cout << "This is a program that sorts integers.\n";
    std::cout << "How many numbers would you like to sort?\n";
    std::cin >> num;
    std::cout << "Please type in the numbers.\n";
    for (int i = 0; i < num; i++) {
        std::cin >> array[i];
    }
    split(0, num);
    std::cout << "Your sorted numbers are: ";
    for (int i = 0; i < num; i++) {
        std::cout << array[i];
        if (i != num - 1) {
            std::cout << ", ";
        } else {
            std::cout << ".\n";
        }
    }
    delete[] array;
    delete[] sub;

    return 0;
}

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

Оригинальный компилятор:

This is a program that sorts integers.
How many numbers would you like to sort?
9
Please type in the numbers.
5
9
2
0
6
4
3
1
8
Low, mid, high: 0, 1, 2.
5, 9, 2, 0, 5, 9, 3, 1, 8.
5, 9, 2, 0, 5, 9, 3, 1, 8.
Done!
Low, mid, high: 2, 3, 4.
5, 9, 0, 0, 5, 9, 0, 2, 8.
5, 9, 0, 2, 5, 9, 0, 2, 8.
Done!
Low, mid, high: 0, 2, 4.
0, 9, 0, 2, 0, 2, 5, 9, 8.
0, 2, 0, 2, 0, 2, 5, 9, 8.
0, 2, 5, 2, 0, 2, 5, 9, 8.
0, 2, 5, 9, 0, 2, 5, 9, 8.
Done!
Low, mid, high: 4, 5, 6.
0, 2, 5, 9, 0, 2, 5, 9, 0.
0, 2, 5, 9, 0, 2, 5, 9, 0.
Done!
Low, mid, high: 7, 8, 9.
0, 2, 5, 9, 0, 2, 5, 0, 0.
0, 2, 5, 9, 0, 2, 5, 0, 9.
Done!
Low, mid, high: 6, 7, 9.
0, 2, 5, 9, 0, 2, 0, 0, 9.
0, 2, 5, 9, 0, 2, 0, 5, 9.
0, 2, 5, 9, 0, 2, 0, 5, 9.
Done!
Low, mid, high: 4, 6, 9.
0, 2, 5, 9, 0, 2, 0, 5, 0.
0, 2, 5, 9, 0, 0, 0, 5, 0.
0, 2, 5, 9, 0, 0, 2, 5, 0.
0, 2, 5, 9, 0, 0, 2, 5, 0.
0, 2, 5, 9, 0, 0, 2, 5, 0.
Done!
Low, mid, high: 0, 4, 9.
0, 2, 5, 9, 0, 0, 0, 0, 0.
0, 0, 5, 9, 0, 0, 0, 0, 0.
0, 0, 0, 9, 0, 0, 0, 0, 0.
0, 0, 0, 0, 0, 0, 0, 0, 0.
0, 0, 0, 0, 0, 0, 0, 0, 0.
0, 0, 0, 0, 0, 0, 0, 0, 0.
0, 0, 0, 0, 0, 0, 2, 0, 0.
0, 0, 0, 0, 0, 0, 2, 5, 0.
0, 0, 0, 0, 0, 0, 2, 5, 9.
Done!
Your sorted numbers are: 0, 0, 0, 0, 0, 0, 2, 5, 9.
Program ended with exit code: 0

Онлайн-оболочка:

This is a program that sorts integers.
How many numbers would you like to sort?
9
Please type in the numbers.
5
9
2
0
6
4
3
1
8
Low, mid, high: 0, 1, 2.
5, 9, 2, 0, 6, 4, 3, 1, 5.
5, 9, 2, 0, 6, 4, 3, 1, 5.
Done!
Low, mid, high: 2, 3, 4.
5, 9, 0, 0, 6, 4, 3, 1, 5.
5, 9, 0, 2, 6, 4, 3, 1, 5.
Done!
Low, mid, high: 0, 2, 4.
0, 9, 0, 2, 6, 4, 3, 1, 0.
0, 2, 0, 2, 6, 4, 3, 1, 0.
0, 2, 5, 2, 6, 4, 3, 1, 0.
0, 2, 5, 9, 6, 4, 3, 1, 0.
Done!
Low, mid, high: 4, 5, 6.
0, 2, 5, 9, 4, 4, 3, 1, 0.
0, 2, 5, 9, 4, 6, 3, 1, 0.
Done!
Low, mid, high: 7, 8, 9.
0, 2, 5, 9, 4, 6, 3, 0, 0.
0, 2, 5, 9, 4, 6, 3, 0, 1.
Done!
Low, mid, high: 6, 7, 9.
0, 2, 5, 9, 4, 6, 0, 0, 1.
0, 2, 5, 9, 4, 6, 0, 1, 1.
0, 2, 5, 9, 4, 6, 0, 1, 3.
Done!
Low, mid, high: 4, 6, 9.
0, 2, 5, 9, 0, 6, 0, 1, 3.
0, 2, 5, 9, 0, 1, 0, 1, 3.
0, 2, 5, 9, 0, 1, 3, 1, 3.
0, 2, 5, 9, 0, 1, 3, 4, 3.
0, 2, 5, 9, 0, 1, 3, 4, 6.
Done!
Low, mid, high: 0, 4, 9.
0, 2, 5, 9, 0, 1, 3, 4, 0.
0, 0, 5, 9, 0, 1, 3, 4, 0.
0, 0, 1, 9, 0, 1, 3, 4, 0.
0, 0, 1, 2, 0, 1, 3, 4, 0.
0, 0, 1, 2, 3, 1, 3, 4, 0.
0, 0, 1, 2, 3, 4, 3, 4, 0.
0, 0, 1, 2, 3, 4, 0, 4, 0.
0, 0, 1, 2, 3, 4, 0, 5, 0.
0, 0, 1, 2, 3, 4, 0, 5, 9.
Done!
Your sorted numbers are: 0, 0, 1, 2, 3, 4, 0, 5, 9.

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

  • 0
    Было бы здорово, если бы ты решил это сам, друг мой,
  • 3
    int num; int * array = new int [num]; int * sub = new int [num]; ... Я уверен, что выделение двух массивов по 0 элементов в каждом - это не то, что вы хотите сделать.
Показать ещё 6 комментариев
Теги:
mergesort

2 ответа

0
Лучший ответ

Поскольку num не был определен, когда он был объявлен в начале кода, поскольку это была глобальная переменная num автоматически присваивалась 0. Тогда int * array = new int [num]; и int * sub = new int [num]; были объявлены с num еще не определенным пользователем, создав два массива с 0 элементами. Попытка изменить эти массивы привела к неопределенному поведению, которое включало ложное внесение определенных случаев, и в этом случае, используя условия don't-care, чтобы изменить список номеров, созданных пользователем.

Чтобы исправить эту проблему, int * array и int * sub должны быть определены только после того, как num определен пользователем. Это также означает, что функции split и sort должны включать указатели на массивы в качестве параметров.

Вот как выглядит код:

#include <iostream>
#include <array>

void sort (int *array, int *sub, int low, int mid, int high) {
int a = low;
int b = low;
int c = mid;

while ((a < mid) && (c < high)) {
    if (array[a] < array[c]) {
        sub[b] = array[a];
        a++;
    } else {
        sub[b] = array[c];
        c++;
    }
    b++;
}
while (a == mid && c < high) {
    sub[b] = array[c];
    c++;
    b++;
}
while (c == high && a < mid) {
    sub[b] = array[a];
    a++;
    b++;
}
for (int d = low; d < high; d++) {
    array[d] = sub[d];
}
}
void split (int *array, int *sub, int low, int high) {
if (low < high - 1) {
    int mid = (low + high) / 2;
    split(array, sub, low, mid);
    split(array, sub, mid, high);
    sort(array, sub, low, mid, high);
}
}

int main()
{
std::cout << "This is a program that sorts integers.\n";
std::cout << "How many numbers would you like to sort?\n";
int num;
std::cin >> num;
int * array = new int [num];
int * sub = new int [num];
std::cout << "Please type in the numbers.\n";
for (int i = 0; i < num; i++) {
    std::cin >> array[i];
}
split(array, sub, 0, num);
std::cout << "Your sorted numbers are: ";
for (int i = 0; i < num; i++) {
    std::cout << array[i];
    if (i != num - 1) {
        std::cout << ", ";
    } else {
        std::cout << ".\n";
    }
}
delete[] array;
delete[] sub;

return 0;
}
0

Вы можете использовать сортировку слияния снизу вверх. Примеры обоих:

вверх дном:

template <typename T>
T * BottomUpMergeSort(T a[], T b[], size_t n)
{
    for(size_t s = 1; s < n; s += 2)        // swap in place for 1st pass
        if(a[s] < a[s-1])
            std::swap(a[s], a[s-1]);
    for(size_t s = 2; s < n; s <<= 1){      // s = run size
        size_t ee = 0;                      // init end index
        while(ee < n){                      // merge pairs of runs
            size_t ll = ee;                 // ll = start of left  run
            size_t rr = ll+s;               // rr = start of right run
            if(rr >= n){                    // if only left run
                rr = n;
                BottomUpCopy(a, b, ll, rr); //   copy left run
                break;                      //   end of pass
            }
            ee = rr+s;                      // ee = end of right run
            if(ee > n)
                ee = n;
            BottomUpMerge(a, b, ll, rr, ee);
        }
        std::swap(a, b);                    // swap a and b
    }
    return a;                               // return sorted array
}

template <typename T>
void BottomUpCopy(T a[], T b[], size_t ll, size_t rr)
{
    while(ll < rr){                         // copy left run
        b[ll] = a[ll];
        ll++;
    }
}

template <typename T>
void BottomUpMerge(T a[], T b[], size_t ll, size_t rr, size_t ee)
{
    size_t o = ll;                          // b[]       index
    size_t l = ll;                          // a[] left  index
    size_t r = rr;                          // a[] right index

    while(1){                               // merge data
        if(a[l] <= a[r]){                   // if a[l] <= a[r]
            b[o++] = a[l++];                //   copy a[l]
            if(l < rr)                      //   if not end of left run
                continue;                   //     continue (back to while)
            while(r < ee){                  //   else copy rest of right run
                b[o++] = a[r++];
            }
            break;                          //     and return
        } else {                            // else a[l] > a[r]
            b[o++] = a[r++];                //   copy a[r]
            if(r < ee)                      //   if not end of right run
                continue;                   //     continue (back to while)
            while(l < rr){                  //   else copy rest of left run
                b[o++] = a[l++];
            }
            break;                          //     and return
        }
    }
}

сверху вниз, позволяет избежать копирования данных после слияния, чередуя две рекурсивные функции:

template <typename T>
T * TopDownMergeSort(T a[], T b[], size_t n)
{
    TopDownMergeSortAtoA(a, b, 0, n);
    return a;
}

template <typename T>
void TopDownMergeSortAtoA(T a[], T b[], size_t ll, size_t ee)
{
    if (ee - ll > 1) {
        size_t rr = (ll + ee)>>1;           // midpoint, start of right half
        TopDownMergeSortAtoB(a, b, ll, rr);
        TopDownMergeSortAtoB(a, b, rr, ee);
        TopDownMerge(b, a, ll, rr, ee);     // merge b to a
    }
}

template <typename T>
void TopDownMergeSortAtoB(T a[], T b[], size_t ll, size_t ee)
{
    if (ee - ll > 1) {
        size_t rr = (ll + ee)>>1;           //midpoint, start of right half
        TopDownMergeSortAtoA(a, b, ll, rr);
        TopDownMergeSortAtoA(a, b, rr, ee);
        TopDownMerge(a, b, ll, rr, ee);     // merge a to b
    } else if ((ee - ll) == 1) {
        b[ll] = a[ll];
    }
}

template <typename T>
void TopDownMerge(T a[], T b[], size_t ll, size_t rr, size_t ee)
{
    size_t o = ll;                          // b[]       index
    size_t l = ll;                          // a[] left  index
    size_t r = rr;                          // a[] right index

    while(1){                               // merge data
        if(a[l] <= a[r]){                   // if a[l] <= a[r]
            b[o++] = a[l++];                //   copy a[l]
            if(l < rr)                      //   if not end of left run
                continue;                   //     continue (back to while)
            while(r < ee){                  //   else copy rest of right run
                b[o++] = a[r++];
            }
            break;                          //     and return
        } else {                            // else a[l] > a[r]
            b[o++] = a[r++];                //   copy a[r]
            if(r < ee)                      //   if not end of right run
                continue;                   //     continue (back to while)
            while(l < rr){                  //   else copy rest of left run
                b[o++] = a[l++];
            }
            break;                          //     and return
        }
    }
}
  • 0
    Я уверен, что это то, что я делаю. Я конечно знаю, что я не делаю нисходящую сортировку слиянием.
  • 0
    Функция split в примере кода является ключевой частью сортировки слиянием сверху вниз. Он рекурсивно разбивает массивы на две части, пока размер не уменьшится до 1, и только после этого он начинает фактический процесс слияния. Сортировка снизу вверх пропускает всю эту логику разделения и начинается с обработки массива размера n как n «прогонов» размера 1, объединения пар прогонов для создания прогонов размера 2, 4, ... до размера прогона> = размера массива , Примеры вики: сверху вниз и снизу вверх .
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню