- •1.Описание Языка си
- •1.1. Элементы Языка си
- •1.1.1. Используемые символы
- •1.1.2. Константы
- •1.1.3. Идентификатор
- •1.1.4. Ключевые слова
- •1.1.5. Использование комментариев в тексте программы
- •1.2.2. Целый тип данных
- •1.2. Типы Данных и Их Объявление
- •1.2.1 Категории типов данных
- •1.2.3. Данные плавающего типа
- •1.2.4. Указатели
- •1.2.5. Переменные перечислимого типа
- •1.2.6. Массивы
- •1.2.7. Структуры
- •1.2.8. Объединения (смеси)
- •1.2.9. Поля битов
- •1.2.10. Переменные с изменяемой структурой
- •1.2.11. Определение объектов и типов
- •1.2.12. Инициализация данных
- •1.3. Выражения и Присваивания
- •1.3.1. Операнды и операции
- •1.3.2. Преобразования при вычислении выражений
- •1.3.3. Операции отрицания и дополнения
- •1.3.4. Операции разадресации и адреса
- •1.3.5. Операция sizeof
- •1.3.6. Мультипликативные операции
- •1.3.7. Аддитивные операции
- •1.3.8. Операции сдвига
- •1.3.9. Поразрядные операции
- •1.3.10. Логические операции
- •1.3.11. Операция последовательного вычисления
- •1.3.12. Условная операция
- •1.3.13. Операции увеличения и уменьшения
- •1.3.14. Простое присваивание
- •1.3.15. Составное присваивание
- •1.3.16. Приоритеты операций и порядок вычислений
- •1.3.17. Побочные эффекты
- •1.3.18. Преобразование типов
- •1.4. Операторы
- •1.4.1. Оператор выражение
- •1.4.2. Пустой оператор
- •1.4.3. Составной оператор
- •1.4.4. Оператор if
- •1.4.5. Оператор switch
- •1.4.6. Оператор break
- •1.4.7. Оператор for
- •1.4.8. Оператор while
- •1.4.9. Оператор do while
- •1.4.10. Оператор continue
- •1.4.11. Оператор return
- •1.4.12. Оператор goto
- •1.5.1. Определение и вызов функций
- •1.5.2. Вызов функции с переменным числом параметров
- •1.5.3. Передача параметров функции main
- •1.6.1. Исходные файлы и объявление переменных
- •1.6.2. Объявления функций
- •1.6.3. Время жизни и область видимости программных объектов
- •1.6.4. Инициализация глобальных и локальных переменных
- •1.7.5. Динамическое размещение массивов
- •1.8. Директивы Препроцессора
- •1.8.1. Директива #include
- •1.8.2. Директива #define
- •1.8.3. Директива #undef
- •2. Организация списков и их обработка
- •2.1. Линейные списки
- •2.1.1. Методы организации и хранения линейных списков
- •2.1.2. Операции со списками при последовательном хранении
- •2.1.3. Операции со списками при связном хранении
- •2.1.4. Организация двусвязных списков
- •2.1.5. Стеки и очереди
- •2.1.6. Сжатое и индексное хранение линейных списков
2.1.4. Организация двусвязных списков
Связанное хранение линейного списка называется списком с двумя связями или двусвязным списком, если каждый элемент хранения имеет два компонента указателя (ссылки на предыдущий и последующий элементы линейного списка).
В программе двусвязный список можно реализовать с помощью описаний:
typedef struct ndd
{ float val; /* значение элемента */
struct ndd * n; /* указатель на следующий элемент */
struct ndd * m; /* указатель на предыдующий элемент */
} NDD;
NDD * dl, * p, * r;
Графическая интерпретация метода связанного хранения списка F=<2,5,7,1> как списка с двумя связями приведена на рис.20.
Рис.20.
Схема хранения двусвязного списка.
Вставка нового узла со значением new за элементом, определяемым указателем p, осуществляется при помощи операторов:
r=malloc(NDD);
r->val=new;
r->n=p->n;
(p->n)->m=r;
p->=r;
Удаление элемента, следующего за узлом, на который указывает p
p->n=r;
p->n=(p->n)->n;
( (p->n)->n )->m=p;
free(r);
Связанное хранение линейного списка называется циклическим списком, если его последний указывает на первый элемент, а указатель dl - на последний элемент списка.
Схема циклического хранение списка F=<2,5,7,1> приведена на рис.21.
Рис.21.
Схема циклического хранения списка.
При решении конкретных задач могут возникать разные виды связанного хранения.
Пусть на входе задана последовательность целых чисел B1,B2,...,Bn из интервала от 1 до 9999, и пусть Fi (1<I по возрастанию. Составить процедуру для формирования Fn в связанном хранении и возвращения указателя на его начало.
При решении задачи в каждый момент времени имеем упорядоченный список Fi и при вводе элемента Bi+1 вставляем его в нужное место списка Fi, получая упорядоченный список Fi+1. Здесь возможны три варианта: в списке нет элементов; число вставляется в начало списка; число вставляется в конец списка. Чтобы унифицировать все возможные варианты, начальный список организуем как связанный список из двух элементов <0,1000>.
Рассмотрим программу решения поставленной задачи, в которой указатели dl, r, p, v имеют следующее значение: dl указывает начало списка; p, v - два соседних узла; r фиксирует узел, содержащий очередное введенное значение in.
#include
#include
typedef struct str1
{ float val;
struct str1 *n; } ND;
main()
{ ND *arrange(void);
ND *p;
p=arrange();
while(p!=NULL)
{
printf("\n %f ",p->val);
p=p->n;
}
}
ND *arrange() /* формирование упорядоченного списка */
{ ND *dl, *r, *p, *v;
float in=1;
char *is;
dl=malloc(sizeof(ND));
dl->val=0; /* первый элемент */
dl->n=r=malloc(sizeof(ND));
r->val=10000; r->n=NULL; /* последний элемент */
while(1)
{
scanf(" %s",is);
if(* is=='q') break;
in=atof(is);
r=malloc(sizeof(ND));
r->val=in;
p=dl;
v=p->n;
while(v->valn;
}
r->n=v;
p->n=r;
}
return(dl);
}
