Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по Технологии разработки ПО 2005.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
833.54 Кб
Скачать

Рекурсия

Рекурсивной называется функция, которая вызывает саму себя. Такая рекурсия называется прямой. Существует ещё косвенная рекурсия, когда две или более функций вызывают друг друга. Если функция вызывает себя, в стеке создаётся копия значений её параметров, как и при вызове обычной функции, после чего управление передаётся первому исполняемому оператору функции. При повторном вызове этот процесс повторяется. Ясно, что для завершения вычислений каждая рекурсивная функция должна содержать хотя бы одну нерекурсивную ветвь алгоритма, заканчивающуюся оператором возврата. При завершении функции соответствующая часть стека освобождается, и управление передаётся вызывающей функции, выполнение которой продолжается с точки, следующей за рекурсивным вызовом.

Классическим примером рекурсивной функции является вычисление факториала числа (n!=n*(n-1)!, где 0!=1 и 1!=1):

unsigned long factor(unsigned long n) {

if (n==0 || n==1) return 1;

return (n*factor(n-1));

}

int main() {

int n;

cout << "Vvedite chislo: "; cin >> n;

cout << "Factorial " << n << " raven " << factor(n);

return 0;

}

Рекурсивные функции чаще всего применяют для компактной реализации рекурсивных алгоритмов, а также для работы со структурами данных, описанными рекурсивно, например с двоичными деревьями. Любую рекурсивную функцию можно реализовать без применения рекурсии. Для этого необходимо обеспечить хранение всех необходимых данных самостоятельно. Достоинством рекурсии является компактная запись, а недостатками – расход времени и памяти на повторные вызовы функции и передачу ей копий параметров, и, главное, опасность переполнения стека.

Алгоритм быстрой сортировки

В прошлом семестре мы рассматривали сортировку массива методом выбора. Это наиболее простой метод, который характеризуется квадратичной зависимостью времени сортировки t от количества элементов N:

t = a×N2 + b×N×lgN,

где a и b – константы, зависящие от программной реализации алгоритма. Иными словами, для сортировки массив требуется просмотреть порядка N раз. Существуют алгоритмы и с лучшими характеристиками, самый известный из которых реализован в методе быстрой сортировки.

Идея алгоритма быстрой сортировки состоит в следующем. Применим к массиву процедуру разделения относительно среднего элемента. Процедура разделения делит массив на две части. В левую помещаются элементы, меньшие, чем элемент, выбранный в качестве среднего, а в правую – большие. Это достигается путём просмотра массива попеременно с обоих концов, при этом каждый элемент сравнивается с выбранным средним, и элементы, находящиеся в неподходящей части, меняются местами. После завершения процедуры разделения средний элемент оказывается на своём окончательном месте. Далее процедуру разделения необходимо повторить отдельно для левой и правой части: в каждой части выбирается среднее, относительно которого она делится на две, и так далее.

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

int main() {

Формирование массива.

l = 0; r = n - 1; // левая и правая границы начального фрагмента

qsort(arr, l, r);

Вывод отсортированного массива.

return 0; }

//---------------------------Рекурсивная функция быстрой сортировки:

void qsort(int* array, int left, int right) {

int i = left, j = right; // устанавливаем начальные значения

int middle = array[(left + right) / 2]; // выбирается средний элемент

int temp;

while (i < j) {

while (array[i] < middle) i++; // продвижение по массиву слева направо

while (middle < array[j]) j--; // продвижение справа налево

if (i <= j) {

temp = array[i];

array[i] = array[j];

array[j] = temp;

i++; j--;

}

}

if (left < j) qsort(array, left, j); //сортировка левой половинки текущего фрагмента

if (i < right) qsort(array, i, right); //сортировка правой половинки текущего фрагмента

}