![](/user_photo/2706_HbeT2.jpg)
- •1.1. Элементы языка программирования
- •Основные правила записи программы:
- •1.2. Алфавит языка
- •1.3. Лексемы
- •1.4. Концепция данных
- •2.2. Операции
- •2.2.1. Арифметические операции
- •2.2.2. Операции присваивания
- •2.2.3. Операции отношения
- •2.2.4. Логические операции
- •2.2.5. Поразрядные операции
- •2.2.6. Вычисление выражений
- •3. Структурное программирование
- •3.1. Общая характеристика операторов
- •3.2. Оператор-выражение
- •3.3. Условный оператор
- •3.4. Составной оператор
- •3.5. Операторы для программирования циклов
- •3.5.1. Оператор цикла for
- •3.5.2. Оператор цикла while
- •3.5.3. Оператор цикла do while
- •3.5.4. Оператор break
- •3.5.5. Оператор continue
- •3.6. Оператор goto
- •3.7. Пустой оператор
- •3.8. Оператор switch
- •3.9. Оператор return
- •4. Массивы
- •4.1. Объявление массива
- •4.2. Обращение к элементам массива
- •4.3. Типовые алгоритмы работы с массивами
- •4.4. Многомерные массивы
- •5. Строки
- •5.1. Объявление строки
- •5.2. Посимвольная обработка строк
- •5.3. Ввод строк
- •5.4. Библиотечные функции для работы с текстом
- •6. Указатели
- •6.1. Объявление указателей
- •6.2. Операции над указателями
- •6.3. Связь между указателями и массивами
- •6.4. Функция strtok для выделения лексем из текста
- •6.5. Динамические массивы
- •7. Структуры и объединения
- •7.1. Объявление структуры
- •Компонент структуры может быть любого типа, кроме типа объявляемой структуры.
- •7.2. Операции над структурами
- •7.3. Объявление объединения
- •8. Модульное программирование
- •8.1. Нисходящее проектирование и программирование
- •8.2. Определение и вызов функции
- •8.3. Место определения функции в программе
- •8.4. Обмен данными между функциями
- •8.4.1. Использование глобальных переменных
- •8.4.2. Использование аппарата формальных и фактических параметров
- •8.4.3. Передача массивов в функцию
- •8.5. Перегрузка функции
- •8.6. Шаблон функции
- •8.7. Рекурсивные функции
- •8.8. Функции с параметрами по умолчанию
- •8.9. Передача в функцию другой функции
- •9. Работа с файлами
- •9.1. Текстовые и двоичные файлы
- •9.2. Объявление файловых переменных
- •9.3. Чтение текстового файла
- •9.4. Создание текстового файла
- •9.5. Изменение данных в текстовом файле
- •9.6. Вывод в двоичный файл
- •9.7. Чтение данных из двоичного файла
- •9.8. Изменение данных двоичного файла
- •9.9. Организация файла с произвольным доступом
- •10. Данные с динамической структурой
- •10.1. Линейный список
- •10.1.1. Специальные типы линейных списков
- •10.1.2. Реализация линейного списка с помощью массива
- •10.1.3. Реализация линейного списка с помощью связанного однонаправленного списка
- •10.1.4. Реализация линейного списка с помощью связанного двунаправленного списка
- •10.2. Деревья
- •10.2.1. Основная терминология
- •10.2.2. Реализация двоичных деревьев поиска Для реализации дерева поиска используются массивы и связанные указателями элементы [3, 4].
- •10.2.3. Сбалансированные деревья
- •Основные достоинства в-дерева:
- •10.3. Графы
- •10.3.1. Определения
- •10.3.2. Реализация графа с помощью списков смежности
- •10.3.3. Реализация графа с помощью матрицы смежности
- •10.3.4. Поиск кратчайших путей. Алгоритм Дейкстры
- •10.3.5. Матрица достижимости. Алгоритм Уоршалла
10.1.3. Реализация линейного списка с помощью связанного однонаправленного списка
Связанный однонаправленный список – это список элементов, в котором последовательные элементы связанны указателями. Каждый элемент такой структуры содержит значение элемента списка (например, целое число или строку) и указатель на следующий элемент. Последний элемент содержит указатель со значением 0.
В языке С++ элемент списка – это структура из двух полей: информационного, содержащего значение элемента, и служебного, содержащего указатель на следующий элемент. Пример объявления типа элемента однонаправленного связанного списка:
struct element{
int info ; //значение элемента списка –целое число
element *next;//адрес следующего элемента
};
Для элементов связанных списков, в отличие от массивов, не выделяется непрерывный участок памяти. Для доступа к первому элементу списка используется внешний указатель на начало списка. Доступ к следующим элементам выполняется через указатели связи элементов. Указатели связи элементов поддерживают в списке упорядоченность элементов по положению. Иногда для выполнения операций со списком удобно использовать дополнительный внешний указатель на последний элемент списка, например, для операции добавления элемента в конец списка.
Создание и поддержка связанного списка требуют использования динамического распределения памяти: увеличения памяти при добавлении элементов и освобождения памяти, когда она не нужна списку, то есть использования операций new и delete.
Список, основанный на связанных указателями элементах, является более гибкой структурой, чем список, реализованный с помощью массива. Связанный однонаправленый список не требует выделения памяти под весь список заранее, как при использовании массивов: память выделяется под элемент списка в момент выполнения операции добавлении элемента и освобождается, когда потребность в элементе исчезает. Таким образом, при использовании связанных указателями списков происходит рациональное использование памяти, что особенно важно для программ, работающих с несколькими линейными списками. Кроме того, реализация списка в виде связанных указателями элементов позволяет эффективно выполнять операции вставки и удаления элементов, сцепления и разбиения списков, так как для выполнения этих операций не требуется перемещать элементы.
Пример программы, выполняющей операции над линейным списком целых чисел, реализованном с помощью связанного однонапрвленного списка:
#include <iostream.h>
#include <conio.h>
//Добавление элемента x в начало списка
void insertbegin (element* & list, int x);
//Добавление элемента x в конец списка
void insertend (element* & list, int x);
//Вывод списка
void print(element* list);
//Удаление первого элемента списка
void del (element* & list, bool &ok);
//Очистка списка
void clear(element* & list );
void main()
{
element * list1; //адрес начала списка
int x; //значение элемента списка
bool ok;
list1=0; //создание пустого списка
cout<<"x ? ";
cin>>x; //10
insertbegin(list1, x);
print( list1); //10
cout<<"x? ";
cin>>x; //20
insertend(list1, x);
print( list1); //10 20
del(list1,ok);
print( list1); //20
clear(list1);
del(list1,ok);
if (!ok)
cout<<”list1 is empty”<<endl;
print (list1);
getch();
}
void print(element* list)
{
element* node; //указатель на текущий элемент списка
if (list==0)
cout<<”list is empty”<<endl;
else
{
node=list;
while (node!=0) //цикл перемещения node по списку
{
cout<<node->info<<' ';
node=node->next; //перемещение к следующему элементу
}
cout<<endl;
}
}
void insertbegin(element* & list, int x)
{
element* node; //указатель на новый элемент
node=new element; //выделение памяти под новый элемент
//Заполнение элемента
node->info=x;
node->next=list;
list=node; //включение элемента в список
}
void insertend(element * & list, int x)
{
element * node, p; //указатели на новый и текущий элементы
node=new element; //создание элемента
//Заполнение элемента
node->info=x;
node->next= 0;
//Включение элемента в конец списка
if (node==0) //список пуст
list = node;
else
{//Поиск адреса последнего элемента
p=list;
while (p->next!=0)
p=node->next;
p->next=node;
}
}
void del (element* &list)
{
element* node; //адрес удаляемого элемента
if (list==0) //список пуст
ok=false;
else
{
node=list; //сохранение адреса удаляемого элемента списка
list=list->next; //исключение элемента из списка
delete node; //освобождение памяти
ok=true;
}
}
void clear(element* & list)
{
while(list!=0 )
del(list);
}
Недостатки связанных списков:
размер элементов связанных списков больше, чем размер элементов массивов, так как в них хранятся служебные данные – указатели;
связанные списки не допускают прямого обращения к элементу по его номеру;
поиск элементов в упорядоченном по значению элементов массиве выполняется бытрее, чем в упорядоченном связанном списке.