Реализация быстрой сортировки не сортируется в C - PullRequest
0 голосов
/ 10 июля 2019

Уже 2 дня я пытаюсь написать реализацию быстрой сортировки на C, но она не работает. Я имею в виду, он компилируется, но результат не тот, который я ожидал.

Я изучал книгу Data Struct, она переведена на португальский, т. Е. На мой родной язык, в любом случае ... Я приведу нижеприведенные инструкции вместе с моим кодом.

QuickSort Image Разделение изображения

//
//  Quick sort V2.c
//  IFTM Exercises
//
//  Created by Lelre Ferreira on 7/9/19.
//  Copyright © 2019 Lelre Ferreira. All rights reserved.
//

#define size 5
#include <stdio.h>

void printfArrays(int *array);
void receiveArray(int *array);
int QuickSortPartition(int *array, int begin, int end);
void QuickSortFunction(int *array, int begin, int end);


int main (int argc, const char * argv[]){

    int array[size];

    receiveArray(array);
    printfArrays(array);

    return 0;
}

void receiveArray(int* array){

    int i = 0;
    for (i = 0; i < size; i++) {
        printf("Insert value of [%d]: ", i);
        scanf("%d", &array[i]);
    }
}

void printfArrays(int *array){

    int i = 0;
    for (i = 0; i < size; i++) {
        printf("Value sorted: %d\n", array[i]);
    }
}

int QuickSortPartition(int *array, int begin, int end){


    int pivot = array[end];
    int i = (begin - 1), j = 0;

    for (j = begin; j <= end - 1; j++) {
        if (array[j] <= pivot) {
            i++;
            array[i] = array[j];
        }
    }
    array[i + 1] = array[end];
    return (i + 1);
}

void QuickSortFunction(int *array, int begin, int end){

    if (begin < end) {
        int pivot = QuickSortPartition(array, begin, end);
        QuickSortPartition(array, begin, pivot - 1);
        QuickSortPartition(array, pivot + 1, end);
    }

}

Ответы [ 3 ]

1 голос
/ 10 июля 2019

Когда вы пишете функцию, протестируйте ее перед использованием в программе.

Функция QuickSortPartition явно неправильная.

Рассмотрим следующую демонстрационную программу с реализацией вашей функции

#include <stdio.h>

int QuickSortPartition(int *array, int begin, int end){


    int pivot = array[end];
    int i = (begin - 1), j = 0;

    for (j = begin; j <= end - 1; j++) {
        if (array[j] <= pivot) {
            i++;
            array[i] = array[j];
        }
    }
    array[i + 1] = array[end];
    return (i + 1);
}

int main( void )
{
    int a[] = { 5, 4, 2, 1, 3 };
    const size_t N = sizeof( a ) / sizeof( *a );

    for ( size_t i = 0; i < N; i++ ) printf( "%d ", a[i] );
    putchar( '\n' );

    QuickSortPartition( a, 0, ( int )( N - 1 ) );

    for ( size_t i = 0; i < N; i++ ) printf( "%d ", a[i] );
    putchar( '\n' );
}    

Его выход

5 4 2 1 3 
2 1 3 1 3 

Вам нужно поменять значения в функции вместо простого присваивания. Например

#include <stdio.h>

size_t QuickSortPartition( int *array, size_t begin, size_t end )
{
    const int pivot = array[end];

    size_t i = begin - 1;

    for ( size_t j = begin; j < end; j++ ) 
    {
        if ( array[j] <= pivot ) 
        {
            int tmp = array[++i];
            array[i] = array[j];
            array[j] = tmp;
        }
    }

    int tmp = array[++i];
    array[i] = array[end];
    array[end] = tmp;

    return i;
}

int main( void )
{
    int a[] = { 5, 4, 2, 1, 3 };
    const size_t N = sizeof( a ) / sizeof( *a );

    for ( size_t i = 0; i < N; i++ ) printf( "%d ", a[i] );
    putchar( '\n' );

    size_t partition = QuickSortPartition( a, 0, N - 1 );

    printf( "%zu: ", partition );
    for ( size_t i = 0; i < N; i++ ) printf( "%d ", a[i] );
    putchar( '\n' );
}    

Его вывод

5 4 2 1 3 
2: 2 1 3 4 5

Для индексов я использовал тип size_t (и вы должны сделать то же самое) вместо типа int.

А внутри функции QuickSortFunction вам нужно вызывать ее самому вместо функции QuickSortPartition.

void QuickSortFunction(int *array, size_t begin, size_t end){

    if (begin < end) {
        size_t pivot = QuickSortPartition(array, begin, end);
        QuickSortFunction(array, begin, pivot - 1);
        QuickSortFunction(array, pivot + 1, end);
    }

}

Учтите, что эта инициализация в объявлении функции QuickSortPartition

int i = (begin - 1), j = 0;
        ^^^^^^^^^^^

это плохо. (Кажется, все копируют алгоритм из плохого примера :)). И функция неэффективна, когда все элементы меньше или равны значению pivot.

Также вы можете написать отдельную функцию, которая заменяет два элемента массива.

Ниже приведена демонстрационная программа, показывающая, как можно улучшить код функции QuickSortPartition.

#include <stdio.h>

void swap( int *a, int *b )
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

size_t QuickSortPartition( int *array, size_t begin, size_t end )
{
    const int pivot = array[end];

    size_t i = begin;

    for ( size_t j = begin; j < end; j++ ) 
    {
        if ( array[j] <= pivot ) 
        {
            if ( i != j ) swap( &array[i], &array[j] );
            ++i;
        }
    }

    if ( i != end ) swap( &array[i], &array[end] );

    return i;
}

int main( void )
{
    int a[] = { 5, 4, 2, 1, 3 };
    const size_t N = sizeof( a ) / sizeof( *a );

    for ( size_t i = 0; i < N; i++ ) printf( "%d ", a[i] );
    putchar( '\n' );

    size_t partition = QuickSortPartition( a, 0, N - 1 );

    printf( "%zu: ", partition );
    for ( size_t i = 0; i < N; i++ ) printf( "%d ", a[i] );
    putchar( '\n' );
}    
0 голосов
/ 11 июля 2019

Спасибо всем! Я исправил ошибки в предыдущем коде, и в итоге я создал еще один, используя while, я оставлю оба здесь.

//
//  Quick sort V2 fixed.c
//  IFTM Exercises
//
//  Created by Lelre Ferreira on 7/11/19.
//  Copyright © 2019 Lelre Ferreira. All rights reserved.
//

#define size 5
#include <stdio.h>

void printArray(int *array);
void receiveArray(int *array);

void QuickSwap(int* a, int* b);
void QuickSort(int *array, int begin, int end);
int  QuickSortPartition(int *array, int begin, int end);

int main (int argc, const char * argv[]){

    int array[size];

    receiveArray(array);
    QuickSort(array, 0, size-1);
    printArray(array);

    return 0;
}

void printArray(int *array){

    int i = 0;
    for (i = 0; i < size; i++) {
        printf("Value sorted: %d\n", array[i]);
    }
}

void receiveArray(int *array){

    int i = 0;
    for (i = 0; i < size; i++) {
        printf("Insert value of [%d]: ", i);
        scanf("%d", &array[i]);
    }
}

void QuickSwap(int* a, int* b){

    int x = *a;
    *a = *b;
    *b = x;
}

void QuickSort(int *array, int begin, int end){

    if (begin < end) {
        int pivot = QuickSortPartition(array, begin, end);
        QuickSort(array, begin, pivot - 1);
        QuickSort(array, pivot + 1, end);
    }
}

int QuickSortPartition(int *array, int begin, int end){

    int pivot = array[end];
    int i = begin - 1, j = 0;

    for (j = begin; j <= end - 1; j++) {
        if (array[j] <= pivot) {
            i++;
            QuickSwap(&array[i], &array[j]);
        }
    }
    QuickSwap(&array[i + 1], &array[j]);
    return (i + 1);
}

Вторая версия:

//
//  Quick sort V1.c
//  IFTM Exercises
//
//  Created by Lelre Ferreira on 7/8/19.
//  Copyright © 2019 Lelre Ferreira. All rights reserved.
//

#define size 5
#include <stdio.h>

void printArray(int *array);
void QuickSortFunction(int *array, int begin, int end);
int QuickSortPartition(int *array, int begin, int end);

int main (int argc, const char * argv[]){

    int array[] = {2, 3, 1, 5, 4};

        QuickSortFunction (array, 0, size-1);
        printArray(array);

    return 0;
}

void printArray(int* array){

    int i = 0;
    for (i = 0; i < size; i++) {
        printf("Value sorted: %d\n", array[i]);
    }
}

int QuickSortPartition(int *array, int begin, int end){

    int left, right;
    int pivot, aux;

    right = end;
    left = begin;
    pivot = array[begin];

    while (left < right) {
        while (array[left] <= pivot)
            left++;
        while (array[right] > pivot)
                right--;
                if (left < right) {
                    aux = array[left];
                    array[left] = array[right];
                    array[right] = aux;
                }
            }

            array[begin] = array[right];
            array[right] = pivot;
            return right;
}

void QuickSortFunction(int *array, int begin, int end){

    if (begin < end) {
        int pivot = QuickSortPartition(array, begin, end);
        QuickSortFunction(array, begin, pivot - 1);
        QuickSortFunction(array, pivot + 1, end);
    }
}
0 голосов
/ 10 июля 2019

Две неправильные вещи:

  1. Вы никогда не вызываете свою функцию сортировки.
  2. Как только вы исправите (1), вы обнаружите, что ваша функция разбиения полностью нарушена.Вы пытаетесь использовать схему разбиения Lomuto , и она не соответствует никому близко к тому, что должно быть.

Какой бы перевод вы ни выполнили для этого алгоритма для (2), это не правильно.Общий алгоритм для раздела Lomuto с фиксированным выбором поворота всегда в конце (ужасный выбор, но это выходит за рамки этого вопроса) выглядит следующим образом:

Обновленная функция разделения

// added to make the partition algorithm easier to understand.
void swap_int(int *a, int *b)
{
    int tmp = *a;
    *a  = *b;
    *b = tmp;
}

int QuickSortPartition(int *array, int begin, int end){

    int i=begin, j;

    for (j = begin; j <= end; j++)
    {
        if (array[j] < array[end])
            swap_int(array+j, array + i++);
    }
    swap_int(array+i, array+end);

    return i;
}

Здесь i обозначает активный слот, где в конечном итоге будет находиться значение разворота.Первоначально пивот хранится на array[end].Как только цикл развертки завершен, i сидит в слоте, где последний своп установит ось на место.Это также возвращаемое значение функции, используемое вызывающей стороной для обозначения того, что не для включения в более поздние рекурсии (поскольку его значение уже находится дома).

Окончательный результат выглядит следующим образом:

#include <stdio.h>

void printfArrays(int *array);
void receiveArray(int *array);
int QuickSortPartition(int *array, int begin, int end);
void QuickSortFunction(int *array, int begin, int end);

#define size 5

int main (int argc, const char * argv[]){

    int array[size];

    receiveArray(array);
    QuickSortFunction(array, 0, size-1);
    printfArrays(array);

    return 0;
}

void receiveArray(int* array){

    int i = 0;
    for (i = 0; i < size; i++) {
        printf("Insert value of [%d]: ", i);
        scanf("%d", array+i);
    }
}

void printfArrays(int *array){

    int i = 0;
    for (i = 0; i < size; i++) {
        printf("Value sorted: %d\n", array[i]);
    }
}

static void swap_int(int *a, int *b)
{
    int tmp = *a;
    *a  = *b;
    *b = tmp;
}

int QuickSortPartition(int *array, int begin, int end){

    int i=begin, j;

    for (j = begin; j <= end; j++)
    {
        if (array[j] < array[end])
            swap_int(array+j, array + i++);
    }
    swap_int(array+i, array+end);

    return i;
}

void QuickSortFunction(int *array, int begin, int end){

    if (begin < end) {
        int pivot = QuickSortPartition(array, begin, end);
        QuickSortFunction(array, begin, pivot - 1);
        QuickSortFunction(array, pivot + 1, end);
    }
}

Вход

 4 1 3 5 2

Выход

Value sorted: 1
Value sorted: 2
Value sorted: 3
Value sorted: 4
Value sorted: 5

Существует множество других не связанных между собой вещей в этом коде, которые было бы целесообразно рассмотреть (проверка IO, лучшая схема выбора сводных данных, например, медиана-три и т. Д.), Но основные проблемы были рассмотрены выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...