Рекурсивные алгоритмы и функции
Задание 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.

