
- •1 Цель работы
- •2 Краткие теоретические сведения
- •2.1 Односвязный список
- •2.2 Рекурсия при обработке односвязного списка
- •2.3 Двусвязный список
- •2.2 Рекурсия при обработке двусвязного списка
- •3 Методика выполнения лабораторной работы
- •4 Содержание отчета
- •5 Рекомендуемые задания к лабораторной работе
- •7 Контрольные вопросы
2.3 Двусвязный список
Во многих задачах возникает необходимость организовать эффективное перемещение по списку как в прямом, так и в обратном направлениях или заданным признакам элемента найти предшествующий и последующий элементы списка. Для решения подобных задач можно каждому элементу списка приписать указатели на следующий и предыдущий элементы, т,е. организовать двусвязный список.. Таким образом, линейный двусвязный список отличается от односвязного тем, что каждое звено списка помимо содержательной информации включает два указателя. Один из которых (прямой указатель) адресует следующий элемент списка, а другой – обратный указатель – предыдущий элемент списка, как показано на рисунке 3. Элементы такого структурного типа описываются следующим образом:
struct имя_структурного_типа
{
элементы _структуры; /* данные */
struct имя_структурного_типа * указатель;
struct имя_структурного_типа * указатель;
};
beg
данные
Null
Начало списка
rex
. . .
. . .
L2
данные
L1
L2
данные
L1
L2
end
данные
L1
Null
(Последний элемент
списка)
Рисунок 3 - Двусвязный список
Продемонстрируем некоторые особенности обработки двусвязных списков на примере рассмотренной выше задачи. Для работы с двусвязными списками будем, как и ранее, использовать три указателя : 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, имеющий дополнительное поле для второго указателя. Остальные особенности программы поясняются комментариями в тексте программы.