Как работает рекурсия, и как мне исправить код?

Ссылка скопирована
C#
1 ответ

Пишу код для быстрой сортировки данных на 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 на своем месте, а меньшие элементы слева от него.
    Нужно решить такую задачу?

    Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

    Заказать помощь
    Лучший ответ
    1
    Виктор Sys Ответ

    Рекурсия - это процесс, при котором функция вызывает саму себя в своем теле. Это мощный инструмент в программировании, который позволяет решать задачи более элегантным и компактным способом.

    Однако, при использовании рекурсии есть несколько важных моментов, которые нужно учитывать. Во-первых, необходимо убедиться, что у вас есть базовый случай - это условие, при котором рекурсивные вызовы прекращаются. Второе важное условие - это прогрессия к базовому случаю, то есть каждый рекурсивный вызов должен приближать нас к базовому случаю.

    Если у вас есть проблемы с рекурсией в вашем коде, первым делом стоит проверить условия выхода из рекурсии. Возможно, у вас отсутствует базовый случай или он некорректно определен. Также стоит убедиться, что каждый рекурсивный вызов приводит к приближению к базовому случаю.

    Давайте рассмотрим пример на языке PHP:

    function factorial($n) {
        if ($n == 0) {
            return 1;
        } else {
            return $n * factorial($n - 1);
        }
    }
     
    echo factorial(5); // Выведет 120

    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. Таким образом, каждый рекурсивный вызов приближает нас к базовому случаю.

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

    Другие ответы (0)

    Пока нет других ответов. Будьте первым, кто поможет автору.

    Ответить на вопрос

    комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *

    Вам также может быть интересно