Как работает рекурсия, и как мне исправить код?
Пишу код для быстрой сортировки данных на c++. Не могу понять как работает рекурсия, к тому же вылазит сообщение об ошибке: Exception thrown at 0x00007FF6637D6BF8 in Testing.exe: 0xC0000005: Access violation reading location 0x00000006D7D00000. Хотелось бы, чтобы кто-нибудь помог с этим и с пониманием как работает рекурсия.
#include <iostream> using namespace std; void quicksort(int* array, int size_of_array) { int id_last_element = size_of_array - 1; int id_first_element = 0; int flag = 1; int pivot = 0; while (id_first_element != id_last_element) { if (flag % 2 != 0) { if (array[pivot] > array[id_last_element]) { cout << array[pivot] << " change on " << array[id_last_element] << endl; swap(array[pivot], array[id_last_element]); pivot = id_last_element; cout << "Array: "; for (int k = 0; k < size_of_array; k++) { cout << array[k] << " "; } cout << endl; id_first_element++; flag++; } else { id_last_element--; } } else if (flag % 2 == 0) { if (array[pivot] < array[id_first_element]) { cout << array[pivot] << " CHANGE ON " << array[id_first_element] << endl; swap(array[pivot], array[id_first_element]); pivot = id_first_element; for (int k = 0; k < size_of_array; k++) { cout << array[k] << " "; } cout << endl; id_last_element--; flag++; } else { id_first_element++; } } } if (id_last_element > 0) { quicksort(array, id_last_element + 1); } if (id_first_element <= size_of_array) { quicksort(array, size_of_array - id_first_element); } } int main() { setlocale(LC_ALL, "Rus"); int array_1[10] = { 5,3,8,2,6,9,1,7,4,10 }; int array_size = end(array_1) - begin(array_1); cout << "Unsorted array:"; for (int i = 0; i < array_size; i++) { cout << array_1[i] << " "; } cout << endl; quicksort(array_1, array_size); cout << "result is:" << endl; for (int j = 0; j < array_size; j++) { cout << array_1[j] << endl; } system("pause"); return 0; } |
#include <iostream> using namespace std; void quicksort(int* array, int size_of_array) { int id_last_element = size_of_array - 1; int id_first_element = 0; int flag = 1; int pivot = 0; while (id_first_element != id_last_element) { if (flag % 2 != 0) { if (array[pivot] > array[id_last_element]) { cout << array[pivot] << " change on " << array[id_last_element] << endl; swap(array[pivot], array[id_last_element]); pivot = id_last_element; cout << "Array: "; for (int k = 0; k < size_of_array; k++) { cout << array[k] << " "; } cout << endl; id_first_element++; flag++; } else { id_last_element--; } } else if (flag % 2 == 0) { if (array[pivot] < array[id_first_element]) { cout << array[pivot] << " CHANGE ON " << array[id_first_element] << endl; swap(array[pivot], array[id_first_element]); pivot = id_first_element; for (int k = 0; k < size_of_array; k++) { cout << array[k] << " "; } cout << endl; id_last_element--; flag++; } else { id_first_element++; } } } if (id_last_element > 0) { quicksort(array, id_last_element + 1); } if (id_first_element <= size_of_array) { quicksort(array, size_of_array - id_first_element); } } int main() { setlocale(LC_ALL, "Rus"); int array_1[10] = { 5,3,8,2,6,9,1,7,4,10 }; int array_size = end(array_1) - begin(array_1); cout << "Unsorted array:"; for (int i = 0; i < array_size; i++) { cout << array_1[i] << " "; } cout << endl; quicksort(array_1, array_size); cout << "result is:" << endl; for (int j = 0; j < array_size; j++) { cout << array_1[j] << endl; } system("pause"); return 0; }
Дополнительно:
если в кратце то рекурсия работает так Как работает рекурсия, и как мне исправить код?
https://pikabu.ru/story/otlichaete_li_vyi_tsikl_ot...
Код разбиения у вас неверный. Забейте пока на рекурсию, отладьте код до рекурсивных вызовов.
Во-первых, удалите flag. Ужасный, отвратительный подход. Что он означает? Зачем он вам нужен? Разве нельзя обе части выполнять в цикле всегда, вместо того, что бы чередовать их очень не читаемым и запутанным методом?
Далее, надо поддерживать какой-то инвариант. У вас там 2 переменные в цикле first и last. Что вы поддерживаете? Все элементы до first не превосходят pivot, а все после last не меньше его? Определитесь с этим и докажите себе, что после каждой итерации цикла этот инвариант сохранится. Вместо того, чтобы следить за тем, где у вас ведущий элемент, просто запомните в переменную его значение.
Если не разберетесь, смотрите на код в википедии, например.
- Здравствуйте, спасибо за ответ. На счет флага согласен полностью, вы тут правы. Но на счет инварианта немного не понял, можете ли вы мне объяснить что это такое, пожалуйста? Заранее спасибо.
- maybe_a_rat_fucker, Определение инварианта посмотрите в википедии.
Применительно программирования - это некоторое условие, которое должно выполняться в начале блока кода. Если не выполняется, это означает, что нарушена структура или логика и т.п. Так же инвариант может быть и при выходе из блока кода.
Например, когда реализуете дерево или список, то, например, внутри операции добавления/удаления узла структура может быть временно не корректной, но на выходе эти операции должны оставлять корректную структуру. Так же как и на в ходе ожидают увидеть корректную структуру - иначе операция может привести к непредсказуемому результату.На С/С++ инварианты обычно помещают в начале/конце функций/методов в assertы. В дебажной сборке инварианты будут проверяться, в релизной - их не будет. assertы с инвариантами в нужных местах облегчают и ускоряют отладку и не замедляют выполнение программы в релизной сборке.
- maybe_a_rat_fucker, вам надо какой-то факт о массиве поддерживать и усилять. Пример я уже привел выше. Если левее id_first_element все числа не превосходят pivot, и аналогично с id_last, а индексы сближаются, то ясно, почему в конце цикла массив оказывается частично упорядочен с pivot на своем месте, а меньшие элементы слева от него.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Рекурсия - это процесс, при котором функция вызывает саму себя в своем теле. Это мощный инструмент в программировании, который позволяет решать задачи более элегантным и компактным способом.
Однако, при использовании рекурсии есть несколько важных моментов, которые нужно учитывать. Во-первых, необходимо убедиться, что у вас есть базовый случай - это условие, при котором рекурсивные вызовы прекращаются. Второе важное условие - это прогрессия к базовому случаю, то есть каждый рекурсивный вызов должен приближать нас к базовому случаю.
Если у вас есть проблемы с рекурсией в вашем коде, первым делом стоит проверить условия выхода из рекурсии. Возможно, у вас отсутствует базовый случай или он некорректно определен. Также стоит убедиться, что каждый рекурсивный вызов приводит к приближению к базовому случаю.
Давайте рассмотрим пример на языке PHP:
function factorial($n) { if ($n == 0) { return 1; } else { return $n * factorial($n - 1); } } echo factorial(5); // Выведет 120
В этом примере функция factorial вычисляет факториал числа. Мы определили базовый случай - если $n равно 0, то возвращаем 1. В противном случае, мы умножаем $n на результат рекурсивного вызова функции factorial с аргументом $n - 1. Таким образом, каждый рекурсивный вызов приближает нас к базовому случаю.
Если у вас есть проблемы с рекурсией в вашем коде, рекомендую внимательно просмотреть базовый случай и прогрессию к нему. Убедитесь, что ваша рекурсивная функция корректно приближается к базовому случаю и возвращает ожидаемый результат.