
- •В.В. Чуркин технологии программирования
- •Содержание
- •Введение
- •Указатели. Операции над указателями Операции адресации и разыменования.
- •Арифметические операции.
- •Присваивание указателей.
- •Смещение и индексирование указателей.
- •Функции
- •Объявление функции (прототип)
- •Параметры функции
- •Встроенные функции
- •Функции с параметрами со значениями по умолчанию
- •Параметры функции main()
- •Рекурсивные функции
- •Перегрузка функций
- •Шаблоны функций
- •Указатели на функции
- •Объявление и инициализация массива указателей на функции:
- •Указатель на функцию как возвращаемое функцией значение
- •Выделение и освобождение динамической памяти
- •Символьные и строковые данные Символьные константы
- •Строковые константы (строки)
- •Символьные переменные
- •Строки – переменные
- •Специальные функции ввода-вывода строк
- •Стандартная библиотека функций языка с
- •Файлы Потоковый ввод-вывод в языке с Функции верхнего уровня файлового ввода-вывода
- •Открытие и закрытие потока
- •Текстовый режим
- •Бинарный режим
- •Закрытие файла
- •Функции в языке c для работы с файлами
- •Двоичный (бинарный) режим обмена с файлами
- •Строковый обмен с файлами
- •Форматный обмен с файлами
- •Позиционирование в потоке
- •Ввод-вывод нижнего уровня
- •Открытие / закрытие файла
- •Чтение и запись данных
- •Произвольный доступ к файлу
- •Позиционирование файлов
- •Сортировки числовых массивов Принцип наименьших привилегий
- •Обменная сортировка (SwapSort)
- •Сортировка выбором (SelectSort)
- •Пузырьковая сортировка (BubbleSort)
- •Сортировка вставками (InsertSort)
- •Быстрая сортировка (QuickSort)
- •Поиск в числовых массивах
- •Структуры
- •Форматы определения структурных типов
- •Форматы определения объектов структурных типов
- •Операции над объектами структурного типа
- •Доступ к элементам объектов структурного типа
- •Структуры, массивы и указатели
- •Объединения (смеси)
- •Оператор switch (переключатель)
- •Динамические структуры данных
- •Реализация стека с помощью массива
- •Очередь
- •Очередь приоритетов
- •Реализация очереди с помощью массива
- •Линейные списки
- •Функции для работы с двунаправленным линейным списком
- •Реализация списка с помощью массивов
- •Поиск хэшированием
- •Бинарные деревья
- •Бинарное упорядоченное дерево (дерево поиска)
- •Идеально сбалансированное дерево
- •Операции с бинарным упорядоченным деревом
- •Удаление узла из дерева
- •Обход (просмотр) дерева
- •Реализация дерева с помощью массивов
- •Вывод динамических структур в файл и чтение их из файла
- •Сбалансированные (avl) деревья
- •Алгоритм avl-вставки.
- •Повороты
- •Классы и объектно-ориентированное программирование
- •Объявление класса
- •Определение класса (реализация класса)
- •Использование класса (драйвер класса)
- •Доступ к элементам класса
- •Отделение интерфейса от реализации
- •Обслуживающие функции-утилиты
- •Конструкторы
- •Windows-программы в Builder
- •Структура головного файла проекта
- •Структура заголовочного файла модуля формы (“Unit1.H”)
- •Структура файла реализации модуля формы (“Unit1.Cpp”)
- •Области видимости (или области действия) переменных в блоках. Время жизни переменных
- •Доступ к свойствам и функциям-элементам (методам) объектов, переменным и функциям в приложении, содержащем одну форму
- •Константные объекты и константные функции-элементы
- •Перегрузка операций
- •Перегрузка унарных операций
- •Перегрузка бинарных операций
- •Перегрузка операции присваивания
- •Перегрузка операции приведения типа
- •Перегрузка операции индексирования []
- •Композиция классов
- •Дружественные функции класса
- •Дружественный класс
- •Использование указателя this
- •Статические элементы класса
- •Шаблон класса для статически и динамически создаваемых объектов
- •Конструктор 1
- •Деструктор
- •Вызовы конструкторов и деструкторов
- •Перегруженная операция присваивания
- •Конструктор 2 (конструктор копирования, конструктор копии)
- •Наследование. Иерархия классов.
- •Ключи доступа
- •Пример простого наследования (точка, круг)
- •Правила наследования функций-элементов. Вызовы конструкторов и деструкторов в иерархии
- •Виртуальные функции и полиморфизм
- •Правила определения и наследования виртуальных функций
- •Позднее (динамическое) связывание
- •Полиморфизм. Абстрактные и конкретные классы
- •Учебная литература (основная)
- •Учебная литература (для углубленного изучения)
- •Учебно-методические издания
Функции для работы с двунаправленным линейным списком
Для формирования списка и работы с ним требуется иметь по крайней мере один указатель – на начало списка (pbeg). Удобно иметь ещё один указатель – на конец списка (pend). Для простоты допустим, что список состоит из целых чисел.
//----------------------------------------------------------------------------------------------
#include <iostream.h>
struct Node
{ int d;
Node* next;
Node* prev;
};
//--------------------------------------------------------------------------------------------
Node* first(int d); //формирование первого элемента
void add(Node** pd, int d); //добавление элемента в конец списка
Node* find(Node* const pg, int key); //поиск элемента по ключу
int remove(Node** pg, Node** pd, int key); //удаление элемента по ключу
Node* insert(Node* const pg, Node** pd, int key, int d); //вставка после key
//----------------------------------------------------------------------------------------------
void main()
{ Node* pbeg=first(1); //формирование 1-го элемента списка
Node* pend=pbeg; //список состоит из одного элемента
//добавление в конец списка 4-х элементов 2, 3, 4, 5:
for(int i=2; i<6; i++) add(&pend, i);
//вставка элемента 10 после элемента 2:
insert(pbeg, &pend, 2, 10);
//удаление элемента 5:
if(!remove(&pbeg, &pend, 5)) cout<<”не найден”;
//вывод списка на экран:
Node* pv=pbeg; //pv – вспомогательный указатель
while(pv){ cout<<pv->d<<’ ‘;
pv=pv->next; }
}
//----------------------------------------------------------------------------------------------
На экране: 1 2 10 3 4
//---------------------------------------------------------------------------------------------
//Формирование 1-го элемента списка
Node* first(int d)
{ Node* pv=new Node;
pv->d=d; pv->next=0; pv->prev=0;
return pv;
}
//----------------------------------------------------------------------------------------------
//Добавление в конец списка
void add(Node** pd, int d)
{ Node* pv=new Node;
pv->d=d; pv->next=0; pv->prev=*pd;
(*pd)->next=pv; *pd=pv;
}
//----------------------------------------------------------------------------------------------
//Поиск элемента по ключу
Node* find(Node* const pg, int key)
{ Node* pv=pg;
while(pv{
if(pv->d==key) break;
pv=pv->next;
}
return pv;
}
//----------------------------------------------------------------------------------------
//Удаление элемента по ключу
int remove(Node** pg, Node** pd, int key)
{ if(Node* pkey=find(*pg, key))
if(pkey==*pg) //удаляется 1-й элемент
{ *pg=(*pg)->next;
(*pg)->prev=0; }
else if(pkey==*pd) //удаляется последний элемент
{ *pd=(*pd)->prev;
(*pd)->next=0; }
else{ //удаляется элемент внутри списка
(pkey->prev)->next=pkey->next;
(pkey->next)->prev=pkey->prev;
}
delete pkey; //освобождается память под элементом списка
return 1;
}
return 0;
}
//----------------------------------------------------------
//Вставка элемента после элемента с key
Node* insert(Node* const pg, Node** pd, int key, int d)
{ if(Node* pkey=find(pg, key))
{ Node* pv=new Node;
pv->d =d;
//установление связи вставляемого элемента с последующим (1)
pv->next=pkey->next;
//установление связи вставляемого элемента с предыдущим (2)
pv->prev=pkey;
//установление связи предыдущего элемента с вставляемым (3)
pkey->next=pv;
//установление связи последующего элемента с вставляемым (4)
if(pkey!=*pd) (pv->next)->prev=pv;
//обновление указателя на конец списка, если элемент
//вставляется в конец списка
else *pd=pv;
return pv;
}
return 0;
}
Примечание. Все параметры, не изменяемые внутри функций, должны передаваться с const. Указатели, которые могут изменяться (например, при удалении из списка последнего элемента указатель на конец списка требуется переназначить на предпоследний элемент), передаются по адресу.
Сортировка связанного списка заключается в изменении связей между элементами. Исходный список просматривается, и каждый элемент вставляется в новый список на место, определяемое значением его ключа.
//----------------------------------------------------------------------------------------------
//Функция формирования упорядоченного (по возрастанию d) списка
// (предполагается, что первый элемент уже существует).
void add_sort(Node** pg, Node** pd, int d)
{ Node* pv=new Node;
pv->d=d;
Node* pt=*pg; // pt – указатель на текущий элемент списка
while(pt) { // просмотр списка
if(d<pt->d) // занести перед текущим элементом
{ pv->next=pt;
if(pt==*pg) // в начало списка
{ pv->prev=0;
*pg=pv; }
else // в середину списка
{ (pt->prev)->next=pv;
pv->prev=pt->prev; }
pt->prev=pv;
return;
}
pt=pt->next;
}
pv->next=0; // в конец списка
pv->prev=*pd;
(*pd)->next=pv;
*pd=pv;
}
//----------------------------------------------------------------------------------------------
//Функция уничтожения списка
void clear(Node** pg)
{ Node* pv=*pg,*pr=0; // pv и pr – указатели на текущий и предыдущий
// элементы списка
cout<<”Список уничтожается! \n”;
while(pv)
{ pr=pv; pv=pv->next;
delete pr; }
*pg-0;
}
//-----------------------------------------------------------------------------------------