Опубликован: 14.12.2010 | Уровень: для всех | Доступ: платный
Лекция 19:

Рекурсивные алгоритмы и функции

< Лекция 18 || Лекция 19: 1234 || Лекция 20 >

Задание 1

  1. В программе оператор if используйте для рекурсивных вызовов, а оператор else используйте как условие останова.
  2. B программу включите определение количества рекурсивных вызовов.
  3. Видоизмените программу для случая ошибочного ввода чисел, сделайте, чтобы было повторное приглашение на ввод чисел.
  4. Напишите функцию вычисления наибольшего общего делителя на основе итерации (с использованием операторов цикла).

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

Для решения примера отметим, что в двоичной системе счисления числа представлены в виде суммы степеней 2. Подобно тому, как в десятичной системе счисления число 234 означает 2\times10^2 + 3\times10^1 + 4\times10^0, число 101 в двоичной системе означает 1\times2^2 + 0\times2^1 + 1\times2^0 [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.

Преобразование десятичных чисел в двоичные эквиваленты

Рис. 18.2. Преобразование десятичных чисел в двоичные эквиваленты

Задание 2

  1. Какой тип рекурсии используется в приведенной программе?
  2. В программу включите защиту от ввода отрицательных целых чисел.
  3. Вывод результатов преобразования десятичных чисел в двоичные эквиваленты осуществите в текстовый файл с именем compX.txt, где Х – номер компьютера (1, 2, ...), на котором выполняется лабораторная работа. В текстовый файл занести также и преобразуемое десятичное число.
  4. В программе вместо функции printf(), как функции вывода результата, примените функцию putchar().
  5. В программу внесите изменения для подсчета количества рекурсивных вызовов.
  6. Напишите программу преобразования десятичного числа в свой двоичный эквивалент на основе не рекурсивного подхода, а с помощью операций с разрядами.
  7. Напишите программу с рекурсивной функцией вывода на консоль десятичного числа для введенного пользователем его двоичного эквивалента.

Пример 3. С использованием косвенной рекурсии напишите программу по решению следующей задачи. Строка состоит из клеток, пронумерованных от 1 до n. Состояние клетки можно изменить – если она пуста, поставить в нее шащку (занять ее), иначе убрать из нее шашку (освободить ее). Вначале строка пуста. Нужно занять все клетки, соблюдая следующее правило. Изменение клетки допустимо, если она имеет номер 1 или расположена непосредственно после занятой клетки, имеющей минимальный номер среди занятых клеток.

Вход. Целое n, 1\leqslant n \leqslant15.

Выход. Последовательность элементов вида +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.

Пример заполнения и освобождения клеток

Рис. 18.3. Пример заполнения и освобождения клеток
< Лекция 18 || Лекция 19: 1234 || Лекция 20 >
Мухаммадюсуф Курбонов
Мухаммадюсуф Курбонов
Александр Соболев
Александр Соболев
Россия
Артем Полутин
Артем Полутин
Россия, Саранск