Проблема с реализацией сортировки слиянием в C ++

0

Я получаю две ошибки при реализации алгоритма из псевдокода:

Одна из моих проблем - int L[n1+1]; ошибка: должна быть постоянной; не может выделять постоянный размер 0. Единственный способ запустить это - сделать размер числом, равным 10. Возможно, я неправильно использую psuedocode, поэтому я включил вышеприведенное утверждение. Это может быть причиной моей следующей проблемы.

Моя другая проблема заключается в том, что я печатаю только одну строку кода, несортированную. Моя функция печати безупречна и работает для всех программ сортировки. Я считаю, что функция MERGE работает только один раз. Я опубликовал вывод Сортировки внизу.

У меня есть генератор случайных чисел для массива A, от 0 до RAND_MAX. Первоначальный вызов - MERGESORT(A,1,n);

void MERGE(int *A, int p, int q, int r)
{
    int n1 = q-(p+1);
    int n2 = r-q;

  //psuedocode states, let L[1..n1+1] & R[1..n1+1] be new arrays

    int L[n1+1];        
    int R[n2+1];    

    for(int i=1; i<n1;i++)
    {
        L[i]=A[p+(i-1)];
    }
    for(int j=1; j<n2; j++)
    {
        R[j] = A[q+j];
    }
    L[n1+1]=NULL; //sentinel
    R[n2+1]=NULL; //sentinel
    int i=1;
    int j=1;
    for (int k=p; k<r; k++)
    {
        if(L[i]<=R[j])
        {
            A[k]=L[i];
            i=i+1;
        }
        else
        {
            A[k]=R[j];
            j=j+1;
        }
    }
}

void MERGESORT(int *A,int p, int r)
{
    if (p<r)
    {
        int q=floor((p+r)/2);
        MERGESORT(A,p,q);
        MERGESORT(A,q+1,r);
        MERGE(A,p,q,r);
    }
}

С int L[10]; и мой A[10]; мой результат:

Sort:  7474 28268 32506 13774 14411
Press any key to continue . . .

Если кто-то может просто помочь в двух проблемах, я, скорее всего, верну его на работу.

  • 1
    int q=floor((p+r)/2); floor не нужен. Деление, применяемое к целым числам, является делением без остатка (десятичные разряды «отбрасываются»).
  • 0
    Было бы неплохо, если бы вы могли предоставить SSCCE .
Показать ещё 4 комментария
Теги:
arrays
sorting

2 ответа

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

Вы не можете обнаружить конец ваших массивов слияния:

for (int k=p; k<r; k++)
{

    // You need to check that i/j are still in range.
    // otherwise the following test are not valid.

    if ((i < n1) && (j < n2))
    {
      if(L[i]<=R[j])
      {
        A[k]=L[i];
        i=i+1;
      }
      else 
      {
        A[k]=R[j];
        j=j+1;
      }
    }
    else
    {   /* More work here */
    }

Другие комментарии:

Идентификаторы, которые являются все Capitol MERGE MERGESORT, обычно зарезервированы для макросов. Если вы их используете, вы, вероятно, столкнетесь с проблемами. Предпочитают названия функций смешанного футляра.

Вы можете моделировать массивы с помощью вектора:

// Simulate L[1..n1+1]
minI = 1;
maxI = n1-1;
std::vector<int> const L(A+(minI-1), A+(maxI-1));     

Массивы в C++ нулевые индексируются. Кажется, что у вас одна ошибка (особенно при доступе к концу массива). Я бы посоветовал вам начать подсчет в 0, а не 1. Большинство C++ кода написаны с точки зрения итераторов из [begining..1PastEnd). Я думаю, вы найдете, что ваш алгоритм проще реализовать, если вы адаптируете этот стиль.

  • 0
    Мне кажется, что OP использует закрытые диапазоны, например, [p, q] и [q + 1, r]. Поэтому я думаю, что это должно быть std::vector<int> const L(A+p, A+q+1); а для второго вектора A+q+1, A+r+1 .
  • 0
    Интересно, что я не знал этого о макросах, я основываюсь на алгоритме в моем учебнике, они использовали заглавные буквы, и я пытался сделать это как можно ближе
2

Есть несколько проблем с вашим кодом, я указал их в комментариях. Это решение, наиболее близкое к вашему коду, и оно далеко не лучшее. Рассмотрим использование контейнеров C++, например std::vector. Именование является, по крайней мере, спорным, и, конечно же, сортировка слияния должна быть реализована как алгоритм на месте.

//L and R are auxiliary arrays 
//preallocated with (inputSize/2 + 1) constant size
void MERGE(int *A, int p, int q, int r, int* L, int* R)
{
    if (p > q || q > r)
    {
        return;
    }

    int n1 = q - p + 1;
    int n2 = r - q;

    // note 0-based indices
    int i = 0;
    int j = 0;

    for(;i < n1;i++)
    {
        L[i] = A[p + i];
    }

    for(;j < n2;j++)
    {
        R[j] = A[q + j + 1];  //+1 because p + n1 - 1 == q + 0
    }

    //again - note 0-based indices
    i = 0;
    j = 0;

    for (int k = p; k <= r; ++k)
    {
        // The most important fix - in your code you didn't check
        // for left/right array bounds at all.
        // Sentinel values aren't needed - size is known
        if(i < n1 && (j >= n2 || L[i] <= R[j]))
        {
            A[k] = L[i];
            ++i;
        }
        else if (j < n2)
        {
            A[k] = R[j];
            ++j;
        }
    }
}

void MERGESORT(int* A, int p, int r, int* L, int* R)
{
    if (p < r)
    {
        int q = (p + r) / 2;  //floor was redundant
        MERGESORT(A, p, q, L, R);
        MERGESORT(A, q+1, r, L, R);

        MERGE(A, p, q, r, L, R);
    }
}

void MERGESORT(int* A, int size)
{
    int*L = new int[size/2 + 1]; //preallocate auxiliary arrays
    int*R = new int[size/2 + 1]; //size/2 + 1 is what will be needed at most

    MERGESORT(A, 0, size - 1, L, R);

    delete L;
    delete R;
}

int main()
{
    int A[5]{ 7474, 28268, 32506, 13774, 14411 };

    MERGESORT(A, 5);

    for (int i = 0;i < 5;++i)
    {
        std::cout << A[i] << std::endl;
    }

    return 0;
}

Вывод:

7474
13774
14411
28268
32506

Кредит также относится к DyP для определения всех ошибок в предыдущей версии :)

Ещё вопросы

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