Я получаю две ошибки при реализации алгоритма из псевдокода:
Одна из моих проблем - 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 . . .
Если кто-то может просто помочь в двух проблемах, я, скорее всего, верну его на работу.
Вы не можете обнаружить конец ваших массивов слияния:
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). Я думаю, вы найдете, что ваш алгоритм проще реализовать, если вы адаптируете этот стиль.
std::vector<int> const L(A+p, A+q+1);
а для второго вектора A+q+1, A+r+1
.
Есть несколько проблем с вашим кодом, я указал их в комментариях. Это решение, наиболее близкое к вашему коду, и оно далеко не лучшее. Рассмотрим использование контейнеров 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 для определения всех ошибок в предыдущей версии :)
int q=floor((p+r)/2);
floor
не нужен. Деление, применяемое к целым числам, является делением без остатка (десятичные разряды «отбрасываются»).