Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Подбельский Фомин_Программирование на языке СИ_...doc
Скачиваний:
259
Добавлен:
10.08.2019
Размер:
53.81 Mб
Скачать

Рекурсия при обработке списка.

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

В каждом звене списка содержатся полезная информация (данные) и ссылка (адрес) на следующее звено списка. Если такая ссылка нулевая, то список пройден до конца. Для начала просмотра списка нужно знать только адрес его первого элемента.

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

Функция рекурсивного заполнения списка ниже в программе имеет прототип:

Она возвращает указатель на сформированный и заполненный данными с клавиатуры динамический список. Предполагается, что при каждом вызове этой функции формируется новый список. Функция заканчивает работу, если для очередного звена списка введено нулевое значение переменной weight. В противном случае заполненная с клавиатуры структура подключается к списку, а ее элементу struct cell * рс присваивается значение, которое вернет функция input(), рекурсивно вызванная из тела функции. После этого функция возвращает адрес очередного звена списка, т.е. значение указателя struct cell * рс.

Прежде чем рассматривать текст функции input(), помещенный в приведенной ниже программе, еще раз сформулируем использованные в ней конструктивные решения.

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

2. Выделение памяти для звеньев списка и заполнение значениями элементов звеньев (структур) зависит от тех значений, которые пользователь присваивает элементам.

3. Если для очередного звена списка вводится нулевое значение элемента weight, то звено не подключается к списку, процесс формирования списка заканчивается. Такой набор данных, введенных для элемента очередного звена, считается терминальным.

4. Если нулевое значение элемента weight введено для первого звена списка, то функция input( ) возвращает значение NULL.

5. Список определяется рекурсивно как первое (головное) звено, за которым следует присоединяемый к нему список.

6. Псевдокод рекурсивного алгоритма формирования списка:

Если введены терминальные данные для звена

Освободить память, выделенную для звена

Вернуть нулевой указатель

Иначе:

Элементу связи звена присвоить результат формирования продолжения списка

(использовать тот же алгоритм)

Все-если

Вернуть указатель на звено.

Текст функции input( ) на языке Си почти полностью соответствует приведенному псевдокоду и учитывает перечисленные конструктивные решения. Для структуры типа struct cell выделяется память. После того как пользователь введет значения данных, выполняется их анализ. В случае терминальных значений библиотечная функция free(p) освобождает память от ненужного звена списка и выполняется оператор return NULL;. В противном случае элементу связи (указатель struct cell * р) присваивается результат рекурсивного вызова функции input( ). Далее все повторяется для нового экземпляра этой функции. Когда при очередном вызове input( ) пользователь введет терминальные данные, функция input() вернет значение NULL, которое будет присвоено указателю связи предыдущего звена списка, и выполнение функции будет завершено.

Функция рекурсивного просмотра и печати списка имеет такой прототип:

Исходными данными для ее работы служит адрес начала списка (или адрес любого его звена), передаваемый как значение указателя - параметра struct cell * р. Если параметр имеет значение NULL - список исчерпан, исполнение функции прекращается. В противном случае выводятся на экран значения элементов той структуры, которую адресует параметр, и функция output() рекурсивно вызывается с параметром р -> рс. Тем самым выполняется продвижение к следующему элементу списка. Конец известен - функция печатает "Список исчерпан!" и больше не вызывает сама себя, а завершает работу.

Текст программы с рекурсивными функциями:

Возможный результат выполнения программы: