- •Алгоритмы и алгоритмические языки
- •Лекция 1
- •Представление чисел в эвм
- •Вещественные
- •Ошибки вычислений
- •Лекция 2
- •Алгоритмы. Сведение алгоритмов.
- •Нижние и верхние оценки.
- •Сортировки
- •Постановка задачи
- •Сортировка пузырьком.
- •Сортировка слиянием с рекурсией.
- •Сортировка слиянием без рекурсии.
- •Лекция 3
- •Алгоритмы. Сведение алгоритмов.
- •Сортировки и связанные с ними задачи.
- •Доказательство корректности работы алгоритма.
- •Оценки времени работы алгоритма.
- •Некоторые задачи, сводящиеся к сортировке.
- •Лекция 4
- •Алгоритмы. Сведение алгоритмов.
- •Сортировки и связанные с ними задачи.
- •HeapSort или сортировка с помощью пирамиды.
- •Алгоритмы сортировки за время o(n)
- •Сортировка подсчетом
- •Цифровая сортировка
- •Сортировка вычерпыванием
- •Лекция 5
- •Алгоритмы. Сведение алгоритмов.
- •Порядковые статистики.
- •Поиск порядковой статистики за время (n) в среднем
- •Поиск порядковой статистики за время (n) в худшем случае
- •Язык программирования c.
- •Переменные
- •Структуры данных.
- •Вектор.
- •Лекция 6
- •Стек. Реализация 1 (на основе массива).
- •Стек. Реализация 2 (на основе массива с использованием общей структуры).
- •Стек. Реализация 3 (на основе указателей).
- •Стек. Реализация 4 (на основе массива из двух указателей).
- •Стек. Реализация 5 (на основе указателя на указатель).
- •Очередь.
- •Стандартная ссылочная реализация списков
- •Ссылочная реализация списков с фиктивным элементом
- •Реализация l2-списка на основе двух стеков
- •Реализация l2-списка с обеспечением выделения/освобождения памяти
- •Лекция 7
- •Структуры данных. Графы.
- •Поиск пути в графе с наименьшим количеством промежуточных вершин
- •Представление графа в памяти эвм
- •Массив ребер
- •Матрица смежности
- •Матрица инцидентности
- •Списки смежных вершин
- •Реберный список с двойными связями (рсдс) (для плоской укладки планарных графов)
- •Лекция 8
- •Структуры данных. Графы.
- •Поиск кратчайшего пути в графе
- •Алгоритм Дейкстры
- •Конец вечного цикла
- •Алгоритм Дейкстры модифицированный
- •Конец вечного цикла
- •Лекция 9
- •Бинарные деревья поиска
- •Поиск элемента в дереве
- •Добавление элемента в дерево
- •Поиск минимального и максимального элемента в дереве
- •Удаление элемента из дерева
- •Поиск следующего/предыдущего элемента в дереве
- •Слияние двух деревьев
- •Разбиение дерева по разбивающему элементу
- •Сбалансированные и идеально сбалансированные бинарные деревья поиска
- •Операции с идеально сбалансированным деревом
- •Операции со сбалансированным деревом
- •Поиск элемента в дереве
- •Добавление элемента в дерево
- •Удаление элемента из дерева
- •Поиск минимального и максимального элемента в дереве
- •Поиск следующего/предыдущего элемента в дереве
- •Слияние двух деревьев
- •Разбиение дерева по разбивающему элементу
- •Лекция 10
- •Красно-черные деревья
- •Отступление на тему языка с. Поля структур.
- •Отступление на тему языка с. Бинарные операции.
- •Высота красно-черного дерева
- •Добавление элемента в красно-черное дерево
- •Однопроходное добавление элемента в красно-черное дерево
- •Удаление элемента из красно-черного дерева
- •Лекция 11
- •Высота b-дерева
- •Поиск вершины в b-дереве
- •Отступление на тему языка с. Быстрый поиск и сортировка в языке с
- •Добавление вершины в b-дерево
- •Удаление вершины из b-дерева
- •Лекция 12
- •Хеширование
- •Метод многих списков
- •Метод линейных проб
- •Метод цепочек
- •Лекция 14
- •Поиск строк
- •Отступление на тему языка с. Ввод-вывод строк из файла
- •Алгоритм поиска подстроки с использованием хеш-функции (Алгоритм Рабина-Карпа)
- •Конечные автоматы
- •Отступление на тему языка с. Работа со строками
- •Алгоритм поиска подстроки, основанный на конечных автоматах
- •Лекция 15
- •Алгоритм поиска подстроки Кнута-Морриса-Пратта (на основе префикс-функции)
- •Алгоритм поиска подстроки Бойера-Мура (на основе стоп-символов/безопасных суффиксов)
- •Эвристика стоп-символа
- •Эвристика безопасного суффикса
- •Форматы bmp и rle
- •Bmp без сжатия.
-
Отступление на тему языка с. Поля структур.
В вышеприведенном примере кажется весьма накладным использовать целую переменную для хранения всего одного бита информации. Можно попробовать отвести под эту переменную меньше памяти:
typedef struct SBTreeX_
{
char IsRed;
int value;
struct STree_ *par;
struct STree_ *left, *right;
} SBTreeX;
Однако, в силу наличия выравнивания в структурах, для большинства современных машин размеры структур SBTreeX и SBTree окажутся равными.
Можно попробовать `отщипнуть’ один бит для переменной IsRed из целой переменной с ключом данной структуры value. Это можно сделать с помощью полей в структурах. Поля в структурах это – переменные целого типа, при описании которых после имени переменной пишется двоеточие и вслед за ним – количество бит, которые должны быть отведены под данную переменную. Например, в нашем случае, можно определить вершину дерева следующим образом:
typedef struct SBTree1_
{
unsigned int IsRed :1;
unsigned int value :31;
struct STree_ *par;
struct STree_ *left, *right;
} SBTree1;
При этом, следует понимать, что теперь каждая операция с членами структуры IsRed и value будет происходить довольно сложно (имеется реализация данной операции в кодах). Действительно, например, для изменения переменной value ее сначала требуется извлечь из структуры (используя битовые операции), изменить, а затем – поместить обратно.
Следует ожидать, что на IBM-совместимых ЭВМ работа со следующей структурой SBTree2 будет происходить медленнее, чем со структурой SBTree1:
typedef struct SBTree2_
{
unsigned int value :31;
unsigned int IsRed :1;
struct STree_ *par;
struct STree_ *left, *right;
} SBTree2;
Здесь используется следующий факт: на IBM-совместимых ЭВМ переменные типа int занимают 4 байта и байты располагаются в обратном порядке: от старшего к младшему. Поэтому для извлечения целой переменной из структуры SBTree1 требуется скопировать первые 4 байта структуры в отдельную переменную и обнулить старший бит этой переменной. Для структуры SBTree2 после извлечения первых четырех байт из структуры во внешнюю целую переменную надо еще дополнительно сдвинуть все биты целой переменной вправо на 1 бит.
Простейшие тесты подтверждают данное предположение. Естественно, что разные компиляторы по разному оптимизируют работу с битовыми полями. Так, например, компилятор Microsoft Visual C++ почти нивелирует разницу в скорости работы со всеми описанными типами структур (разница в скорости элементарных операций с данными структурами оценивается примерно 10-20%). Для используемого же компилятора gnu C++ разница в скорости оказалась – вдвое.
Отметим, что данный подход применим далеко не всегда. Поля в структурах обязаны иметь тип unsigned int. В современных версиях языка С это требование немного ослабло и вместо этого типа часто можно использовать другие целые типы, но, например, тип float все равно использовать нельзя. Пример использованной программы прилагается.