Я считаю, что этот подход к быстрому сортированию сбивает с толку и ошибочен, но, похоже, он работает. Я имею в виду this pseudocode. Примечание: у них также есть реализация C в конце статьи, но она сильно отличается от их псевдокода, поэтому меня это не волнует.Почему этот QuickSort работает?
Я также написал в C, как это, пытаясь остаться верным псевдокоде как можно больше, даже если это означает, что делает некоторые странные C вещи:
#include <stdio.h>
int partition(int a[], int p, int r)
{
int x = a[p];
int i = p - 1;
int j = r + 1;
while (1)
{
do
j = j - 1;
while (!(a[j] <= x));
do
i = i + 1;
while (!(a[i] >= x));
if (i < j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
else
{
for (i = 1; i <= a[0]; ++i)
printf("%d ", a[i]);
printf("- %d\n", j);
return j;
}
}
}
int main()
{
int a[100] = //{8, 6,10,13,15,8,3,2,12};
{7, 7, 6, 2, 3, 8, 4, 1};
partition(a, 1, a[0]);
return 0;
}
Если запустить это, вы» будете получать следующий вывод:
1 6 2 3 4 8 7 - 5
Однако, это не так, не так ли? Ясно, что a[5]
не имеет всех значений, прежде чем он окажется ниже, так как a[2] = 6 > a[5] = 4
. Не говоря уже о том, что 7
должен быть стержнем (начальный a[p]
), и все же его позиция неверна и потеряна.
следующий алгоритм раздела берется из wikipedia:
int partition2(int a[], int p, int r)
{
int x = a[r];
int store = p;
for (int i = p; i < r; ++i)
{
if (a[i] <= x)
{
int t = a[i];
a[i] = a[store];
a[store] = t;
++store;
}
}
int t = a[r];
a[r] = a[store];
a[store] = t;
for (int i = 1; i <= a[0]; ++i)
printf("%d ", a[i]);
printf("- %d\n", store);
return store;
}
И производит этот выход:
1 6 2 3 8 4 7 - 1
, который является правильным по моему мнению: ось (a[r] = a[7]
) достигла своего окончательного положения.
Однако, если использовать исходную функцию секционирования в следующем алгоритме:
void Quicksort(int a[], int p, int r)
{
if (p < r)
{
int q = partition(a, p, r); // initial partitioning function
Quicksort(a, p, q);
Quicksort(a, q + 1, r); // I'm pretty sure q + r was a typo, it doesn't work with q + r.
}
}
... это, кажется, правильный алгоритм сортировки. Я проверил его на множестве случайных входов, включая все массивы 0-1 длины 20.
Я также попытался использовать эту функцию разделения для алгоритма выбора, в котором он не смог получить правильные результаты. Кажется, что это работает, и это даже очень быстро, как часть алгоритма quicksort.
Так что мои вопросы:
- Может кто-нибудь опубликовать пример, на котором алгоритм не работает?
- Если нет, то почему это работает, поскольку часть раздела кажется неправильной? Это еще один подход к разделению, о котором я не знаю?
Вы имеете в виду, что это правильно, потому что 'a [1..5]' имеет элементы <= '7' и' a [6..7] 'имеет элементы> =' 7'? Это правда, но не должен ли выбранный шарнир достигать конечной позиции? Согласно моим учебникам и википедии, это должно быть. – IVlad
Да. В первой ссылке, которую вы дали, quicksort затем переходит к сортировке [1..5] и [6..7]. Только в ссылке на wikipedia требуется [6], чтобы иметь окончательное значение 7, так как здесь [1..5] и [7..7] сортируются по рекурсивным вызовам. – Henrik
Интересно, я об этом не думал. Я всегда думал, что алгоритм разбиения должен возвращать конечную позицию элемента поворота. Спасибо за ваше объяснение. Я приму ваш ответ немного позже, чтобы дать другим возможность прокомментировать этот алгоритм. – IVlad