Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие часть 1.doc
Скачиваний:
60
Добавлен:
24.09.2019
Размер:
6.98 Mб
Скачать

2.6.2. Реализация линейного списка при рекурсивном подходе

Приведенный выше рекурсивный подход к обработке линейных списков реализуется компактно и наглядно. Для формирования списка будем использовать динамическую память. Описание структуры линейного списка сводится к описанию точечной пары (структуры из двух полей):

голова списка (тип совпадает с типом данных списка);

указатель на хвост (тип  — указатель на список).

Базовые функции получают в качестве параметра указатель на список, что удобно для выполнения рекурсивных вызовов. В дополнение к основным функциям добавим еще рекурсивную функцию очистки списка, которая освобождает память, которую занимали элементы списка, и присваивает значение NULL указателю на список. Это значение и будет признаком пустого списка.

Листинг 2.7 содержит реализацию нескольких достаточно типовых функций по обработке списков. В целях экономии места здесь объединены в одном листинге и базовые функции, и те дополнительные функции, которые реализованы на основе базовых. хотя разумнее вынести реализацию АТД в отдельный файл.

Листинг 2.7. Рекурсивная реализация некоторых функций обработки линейного списка

typedef int type_of_data;

struct list

{ type_of_data list_h;

list *list_t;

};

// базовые функции для работы со списками:

bool isnull(list *l); // возвращает true, если список пустой

type_of_data head(list *l); // возвращает значение - голову списка

list *tail(list *l); // возвращает указатель на хвост

list *cons(type_of_data l_head, list *l_tail); //формирует список из головы и хвоста

list *empty(list *l);// очищает список

// примеры других функций на основе базовых функций

list *concat(list *l1, list *l2); // присоединение l2 к l1

type_of_data sum(list *l); // сумма элементов списка l

list *append(type_of_data x, list *l); // добавление х в конец списка l

list *reverse(list *l); // переписать список l в обратном порядке

void print(list *l); // вывод элементов списка l на экран

// небольшая демонстрационная программа

main()

{ list *l=cons(1,cons(2,cons(3,cons(4,NULL)))); //создание списка(1 2 3 4)

print(l); cout<<endl;

l=concat(l,cons(5,cons(6,NULL))); //добавили список из двух элементов (5 6)

print(l); cout<<endl;

l=append(7,l); print(l); cout<<endl;//добавили еще один элемент (7)

l=reverse(l); // изменили порядок элементов на обратный

print(l); cout<<endl;

cout<<"Sum="<<sum(l)<<endl; // вывели сумму элементов

l=empty(l); if (isnull(l)) cout<<"list is empty";

cin.get(); return 0;

}

// реализация базовых функций:

list* empty(list *l)

{ if (isnull(tail(l))) {delete l; return NULL;}

else return empty(tail(l));

}

bool isnull(list *l)

{ return (l==NULL);

}

type_of_data head(list *l)

{ if (isnull(l)) { cerr<<"!head(NULL)"; exit(1); }

return l->list_h;

}

list *tail(list *l)

{ if (isnull(l)) { cerr<<"!tail(NULL)"; exit(2); }

return l->list_t;

}

list *cons(type_of_data l_head, list *l_tail)

{ list *temp=new list;

temp->list_h=l_head; temp->list_t=l_tail;

return temp;

}

list *concat(list *l1, list *l2)

{ if (isnull(l1)) return l2;

return cons(head(l1),concat(tail(l1),l2));

}

type_of_data sum(list *l)

{ if (isnull(l)) return 0;

return head(l)+sum(tail(l));

}

list *append(type_of_data x, list *l)

{ return concat(l,cons(x,NULL));

}

list *reverse(list *l)

{ if (isnull(l)) return NULL;

return concat(reverse(tail(l)),cons(head(l),NULL));

}

void print(list *l)

{ if (isnull(l)) return;

cout<<head(l)<<" "; print(tail(l));

}

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