Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка по лабораторной работе №2.doc
Скачиваний:
41
Добавлен:
02.05.2014
Размер:
108.03 Кб
Скачать

Все-если

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

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

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

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

void output (struct cell * р) ;

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

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

/* Определение структурного типа "Звено списка";*/

struct cell

{

char sign[10] ;

int weight;

struct cell * рс;

};

#include <stdlib.h>

#include <stdio.h>

/* Функция ввода и формирования списка: */

struct cell * input(void)

{

struct cell * р;

p=(struct cell *)malloc(sizeof(struct cell));

printf("sign=") ;

scanf("%s",& p->sign);

printf("weight=") ;

scant("%d",& p->weight) ;

if (р -> weight == 0) {

free (p) ;

return NULL;

}

р -> рс = input(); /* Рекурсивный вызов */

return p;

}

/* Функция "печати" списка; */

void output(struct cell *p)

{

if (p == NULL)

{

printf("\nCписок исчерпан! ");

return;

}

printf("\nsign=%e\tweight=%d",p->sign, p->weight) ;

output(p -> рс); /* Рекурсивный вызов */ }

void main()

{

struct cell * beg=NULL; /* Начало списка */

printf("\nВведите данные структур:\n");

beg=input(); /* Ввод списка. */

/*Напечатать список: */

printf("\nСодержимое списка:");

output(beg) ;

}

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

Введите данные структур:

Sign=Zoro

weight=l938

Sign=Zodiac

weight=1812

Sign=0

weight=0

Содержимое списка:

Sign==Zoro weight=1938

Sign=Zodiac weight=1812

Список исчерпан!

2.3 Двусвязный список

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

beg

данные

Null

Начало списка

rex

. . .

. . .

L2

данные

L1

L2

данные

L1

L2

end

данные

L1

Null

(Последний элемент списка)

Элементы такого структурного типа описываются следующим образом:

struct имя_структурного_типа

{

элементы _структуры; /* данные */

struct имя_структурного_типа * указатель;

struct имя_структурного_типа * указатель;

};

Продемонстрируем некоторые особенности обработки двусвязных списков на примере рассмотренной выше задачи. Для работы с двусвязными списками будем, как и ранее, использовать три указателя : beg – на начало списка, end – на последний элемент, уже включенный в список и rex – указатель для “перебора” элементов списка. Приведенная ниже программа формирует двусвязный список для поставленной задачи.

#include <stdlib.h>

#include <stdio.h>

/* Определение структурного типа “звено двусвязного списка”*/

struct cell2 {

char sign [10];

int weight;

struct cell2 * pc1; /* указатель на предшествующее звено */

struct cell2 * pc2; /* указатель на следующее звено */

};

void main()

{

/* Указатель для перебора звеньев списка: */

struct cell2 * rex;

struct cell2 * beg=NULL; /* Начало списка */

struct cell2 * end=NULL; /* Конец списка */

printf("\nВведите значения структур:\n");

/* Цикл ввода и формирования списка */

do

{ /* Выделить память для очередного звена списка: */

rex=(struct cell2 *)malloc(sizeof(struct cell2));

/* Ввести значения элементов звена: */

printf("sign=") ;

scanf("%s",& rex->sign) ;

printf("weight=") ;

scanf("%d",& rex->weight);

if (rex->weight = = 0)

{

free(rex) ;

break; /* Выход из цикла ввода списка */

}

/* Включить звено в список: */

if (beg==NULL && end==NULL)

/* Список пуст – включить введенный элемент в список первым*/

beg=rex;

beg-> pc1= NULL; /* указатель на предшествующее звено для первого элемента списка равен NULL */

else /* Включить звено в уже существующий список */ ;

end->pc2=rex; /* Бывший последний ссылается на включенное звено */

rex-> pc1= end; ; /*Включенное звено ссылается на предшествующий элемент */

end=rex ; /*Включенное звено стало последним*/

end->pc2= NULL;

}

while(1) ; /* Конец ввода списка */

/* Напечатать список */

printf("\nСодержимое списка:") ;

rex=beg;

while (rex!=NULL)

{

printf("\nsign=%s\tweight=%d",rex->sign, rex->weight) ;

rex=rex->pc2;

}

}

Обратите вниманиена то, что вместо структур типа struct cell используется структурный тип struct cell2, имеющий дополнительное поле для второго указателя. Остальные особенности программы поясняются комментариями в тексте программы.