Рекурсивные алгоритмы и функции
Задание 1
- В программе оператор if используйте для рекурсивных вызовов, а оператор else используйте как условие останова.
- B программу включите определение количества рекурсивных вызовов.
- Видоизмените программу для случая ошибочного ввода чисел, сделайте, чтобы было повторное приглашение на ввод чисел.
- Напишите функцию вычисления наибольшего общего делителя на основе итерации (с использованием операторов цикла).
Пример 2. Напишите рекурсивную функцию, которая выводит на консоль двоичный эквивалент целого десятичного числа, введенного пользователем с клавиатуры.
Для решения примера отметим, что в двоичной системе счисления числа представлены в виде суммы степеней 2. Подобно тому, как в десятичной системе счисления число 234 означает , число 101 в двоичной системе означает [7]. В двоичных числах используются только цифры 0 и 1.
Очевидно, что за основу решения примера следует использовать целочисленное деление. Если введено число n, то оно может быть, либо четным, либо нечетным. Тогда остаток от деления на 2 будет равняться нулю для четных чисел и единице – для нечетных.
Программный код решения примера:
#include <stdio.h> #include <conio.h> #include <locale.h> // Прототип рекурсивной функции void dec2bin(unsigned long int); int main (void) { unsigned long int n; setlocale(LC_ALL, "Russian"); // для русских шрифтов printf("\n\t Введите целое десятичное число\n \ (или не числовой символ для завершения программы): "); while (scanf_s("%ul", &n) == 1) { printf("\n Двоичный эквивалент: "); dec2bin(n); printf("\n\n\t Введите целое десятичное число\n \ (или не числовой символ для завершения программы): "); } return 0; // выход из программы } // Определение рекурсивной функции void dec2bin(unsigned long int n) { int r; r = n % 2; if (n >= 2 ) dec2bin(n/2); printf("%d", r); return; }
В программе шаги рекурсии осуществляются при условии, что аргумент рекурсивной функции больше или равен двум. Как только это условие нарушается, происходит распечатка результата и выход из функции. Например, при n = 10 остаток от целочисленного деления r = 10%2 = 0. В то же время аргумент функции dec2bin() будет равняться 5. Тогда остаток от целочисленного деления r = 5%2 = 1. Далее аргумент функции будет равняться 2 (5/2), так как аргумент функции определен через целое число. Остаток от целочисленного деления r = 2%2 = 0. Теперь аргумент рекурсивной функции будет равен 1, что прерывает рекурсивные вызовы функции (нарушается условие проверки оператором if ). Остаток от деления r = 1%2 = 1. Вывод результата на консоль будет осуществляться из стека по дисциплине LIFO (Last Input First Output – последним вошел, первым вышел).
Пример выполнения программы показан на рис. 18.2.
Задание 2
- Какой тип рекурсии используется в приведенной программе?
- В программу включите защиту от ввода отрицательных целых чисел.
- Вывод результатов преобразования десятичных чисел в двоичные эквиваленты осуществите в текстовый файл с именем compX.txt, где Х – номер компьютера (1, 2, ...), на котором выполняется лабораторная работа. В текстовый файл занести также и преобразуемое десятичное число.
- В программе вместо функции printf(), как функции вывода результата, примените функцию putchar().
- В программу внесите изменения для подсчета количества рекурсивных вызовов.
- Напишите программу преобразования десятичного числа в свой двоичный эквивалент на основе не рекурсивного подхода, а с помощью операций с разрядами.
- Напишите программу с рекурсивной функцией вывода на консоль десятичного числа для введенного пользователем его двоичного эквивалента.
Пример 3. С использованием косвенной рекурсии напишите программу по решению следующей задачи. Строка состоит из клеток, пронумерованных от 1 до n. Состояние клетки можно изменить – если она пуста, поставить в нее шащку (занять ее), иначе убрать из нее шашку (освободить ее). Вначале строка пуста. Нужно занять все клетки, соблюдая следующее правило. Изменение клетки допустимо, если она имеет номер 1 или расположена непосредственно после занятой клетки, имеющей минимальный номер среди занятых клеток.
Вход. Целое n, .
Выход. Последовательность элементов вида +i или –i, обозначающих соответственно занять клетку i и освободить клетку i [9].
Например, при n = 3 выход имеет вид +1+2–1+3+1.
В основу решения задачи положен программный код из [9].
Программный код решения примера:
#include <stdio.h> #include <conio.h> // для getch(); #include <stdlib.h> // для exit(); // Прототипы функций void fillOnly(int); void free_n(int); void fill_n(int); int main (void) { int n = 1; // размер строки int in = 1; // контроль ввода n printf("\n Enter a length of string (naturel number): "); in = scanf_s("%i", &n); if (in != 1 || n < 1 || n > 15) { printf("\n Error input. Press any key to exit: "); _getch(); exit(0); } puts("\n\tResult:"); fill_n(n); printf("\n\n Press any key to exit: "); _getch(); return 0; } // Объявления функций // 1-я функция void fillOnly(int n) { if (n == 1) printf("\t%+3d\n", 1); else { fillOnly(n-1); printf("\t%+3d\n", n); free_n(n-1); } } // 2-я функция void free_n(int n) { if (n == 1) printf("\t%+3d\n", -1); else { fillOnly(n-1); printf("\t%+3d\n", -n); free_n(n-1); } } //3-я функция void fill_n(int n) { if (n == 1) printf("\t%+3d\n", 1); else { if (n == 2) printf("\t%+3d\n\t%+3d\n", 1, 2); else { fillOnly(n-1); printf("\t%+3d\n", n); fill_n(n-2); } } }
В программе вывод результата на консоль выполнен в виде столбца. Для этого используется эскейп-последовательность \t в функциях printf(). Форматный вывод значений в функциях printf() выполнен с помощью спецификации %+3d, что позволяет автоматически устанавливать знаки чисел, под которые отводятся 3 позиции.
Как видно из приведенного программного кода, в каждой из функций имеется вызов самой функции и других функций. Это указывает на косвенное обращение к функциям.
Пример выполнения программы показан на рис. 18.3.