Как работает разделение Хоара в QuickSort?

Вот псевдокод прямо из книги (CORMEN):

Partition(A,p,r)
        x=A[p]
        i=p-1
        j=r+1 
        while(TRUE)
            repeat
                j=j-1
            until A[j]<=x
            repeat
                i=i+1
            until A[i]>=x
            if i<j
                SWAP A[i] <=> A[j]
            else return j

Вот код на С++:

#include<bits/stdc++.h>
using namespace std;


int partition(int a[], int low, int high)
{
    int pivot = a[low];
    int i = low - 1;
    int j = high + 1;
    while (1)
    {
        do {
            i++;
        } while (a[i] < pivot);

        do {
            j--;
        } while (a[j] > pivot);

        if (i >= j) {
            cout<<j<<endl;
            return j;

        }

        swap(a[i], a[j]);
    }
}


/* The main function that implements QuickSort
arr[] --> Array to be sorted,
low --> Starting index,
high --> Ending index */
void quickSort(int arr[], int low, int high)
{
    if (low < high)
    {
        /* pi is partitioning index, arr[p] is now
        at right place*/
        int pi = partition(arr, low, high);

        // Separately sort elements before
        // partition and after partition
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}

/* Function to print an array */
void printArray(int arr[], int size)
{
    int i;
    for (i=0; i < size; i++)
        printf("%d ", arr[i]);
    printf("\n");
}

// Driver program to test above functions
int main()
{
    int arr[] = {7,3,2,6,4,1,3,5};
    int n = sizeof(arr)/sizeof(arr[0]);
    cout<<"partition:\n";
    partition(arr,0,7);
    printArray(arr, n);

    quickSort(arr, 0, n-1);
    printf("Sorted array: \n");
    printArray(arr, n);
    return 0;
}

Если я использую этот массив на входе:

[5,3,2,6,4,1,3,7]

все работает логически хорошо, потому что массив, возвращаемый разделением, будет:

[3,3,2,1,4,6,5,7] 

Завершение i = 5 и j = 4, поэтому мой стержень равен 4. И все элементы слева от 4 являются второстепенными, а все справа - основными.

Теперь, если я использую этот массив на входе:

[7,3,2,6,4,1,3,5]

У меня будет такая ситуация в конце раздела

[5,3,2,6,4,1,3,7]

который вернется ко мне как точка опоры j = 6, то есть 3. Теперь элементы слева от 3 не все второстепенные, а справа - основные. Но как это возможно? Разве я не должен иметь элементы слева от основного минора и справа от мажора?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

С разделением Хоара стержень и значения, равные стержню, могут оказаться где угодно. Возвращаемый индекс не является индексом сводной точки, а просто разделителем. Для приведенного выше кода, когда разделение выполнено, элементы <= pivot будут слева или слева от j, а элементы >= pivot будут справа от j. После выполнения шага раздела код C++ должен быть:

        quickSort(arr, low, pi);           // not pi - 1
        quickSort(arr, pi + 1, high);

пример кода, который включает тестирование быстрой сортировки:

uint32_t Rnd32()
{
static uint32_t r = 0;
    r = r*1664525 + 1013904223;
    return r;
}

int Partition(int ar[], int lo, int hi)
{
    int pv = ar[lo+(hi-lo)/2];
    int i = lo - 1;
    int j = hi + 1;
    while(1){
        while(ar[++i] < pv);
        while(ar[--j] > pv);
        if (i >= j)
            return j;
        std::swap(ar[i], ar[j]);
    }
}

void QuickSort(int ar[], int lo, int hi)
{
    while (lo < hi){
        int pi = Partition(ar, lo, hi);
        if ((pi - lo) < (pi - hi)){
            QuickSort(ar, lo, pi);
            lo = pi + 1;
        } else {
            QuickSort(ar, pi + 1, hi);
            hi = pi;
        }
    }
}

#define COUNT (16*1024*1024)

int main(int argc, char**argv)
{
    size_t i;
    int * ar = new int [COUNT];
    for(i = 0; i < COUNT; i++){
        ar[i] = Rnd32();
    }

    QuickSort(ar, 0, COUNT-1);

    for(i = 1; i < COUNT; i++)
        if (ar[i-1] > ar[i])
            break;
    if (i == COUNT)
        std::cout << "passed" << std::endl;
    else
        std::cout << "failed" << std::endl;

    delete[] ar;

    return(0);
}

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

mimmolg99 02.05.2022 21:00

@MimmoLugubre - для небольших случаев и некоторых шаблонов данных он просто работает с кодом вопросов, но если вы протестируете другие шаблоны и дополнительные данные, вы обнаружите, что первый вызов должен быть quickSort(arr, lo, pi); \\ not pi - 1 .

rcgldr 03.05.2022 02:22

@MimmoLugubre - я обновил свой ответ, включив в него тестовый код.

rcgldr 03.05.2022 05:23

Другие вопросы по теме