- •Алгоритмы и алгоритмические языки
- •Лекция 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 без сжатия.
Сортировка слиянием без рекурсии.
Предыдущий алгоритм можно модифицировать так, что он уже не будет использовать рекурсию. Действительно. Рассмотрим последовательно все пары элементов в сортируемом массиве. Каждый из элементов в паре представляет собой уже отсортированный массив длины 1, поэтому эти массивы (пока длины 1) можно слить в упорядоченные куски длины 2. Далее мы рассматриваем уже пары упорядоченных массивов длины 2 и сливаем их в массивы длины 4. И т.д.
Отметим, что при этих операциях на k-том проходе по упорядочиваемому массиву на правом конце массива мы будем получать либо ситуацию, когда у правого оставшегося куска (длины 2k ) вообще нет парного куска для слияния, либо кусок есть и его длина 2k. В первом случае делать вообще ничего не нужно, а во втором следует стандартным способом сливать куски, возможно, существенно различной длины.
Легко видеть, что данный алгоритм решает задачу за время O(N log2 N), где N – количество элементов в сортируемом массиве.
Лекция 3 Алгоритмы. Сведение алгоритмов. Сортировки и связанные с ними задачи.
Д.Кнут. Искусство программирования для ЭВМ. тт 1-3. Москва. Мир. 1996-1998 Т.Кормен, Ч.Лейзерсон, Р.Ривест. Алгоритмы. Построение и анализ. Москва. МЦНМО. 1999. Препарата Ф., Шеймос М. Вычислительная геометрия. Москва. Мир. 1989
|
QuickSort.
Определение. Медианой множества А = {a1 ,…, aN } называется элемент с индексом (N+1)/2 в отсортированном по возрастанию множестве А.
Пусть, для определенности, мы сортируем массив вещественных чисел. Идея алгоритма заключается в следующем. Выберем некоторое число, желательно близкое, в каком-то смысле, к медиане сортируемого множества. Разобьем наше множество на две половины – в одной (левой половине) должны быть элементы меньше или равные выбранного элемента, а в другой (в правой половине) – больше или равные. Из построения этих подмножеств следует, что их расположение совпадает с их расположением в отсортированном множестве чисел (расположение – в смысле множеств), т.е. после сортировки элементы из этих подмножеств останутся на месте этих же подмножеств. Т.о., применив рекурсивно эту же процедуру для каждого из подмножеств, мы, в конечном итоге, получим отсортированное множество.
Для реализации этой идеи рассмотрим алгоритм, который не предполагает хранения медианы в отдельной ячейке памяти. В процессе работы алгоритма мы будем следить за тем, в какой ячейке памяти располагается элемент исходного множества, который мы выбрали в качестве медианы. Подобная реализация в реальности чуть более медленная, но доказательство работы алгоритма намного проще, чем в случае хранения медианы в отдельной ячейке.
В следующей реализации в комментариях показаны соотношения на значения элементов, которые выполняются после каждого шага алгоритма. Эти соотношения доказывают, что каждый раз массив разбивается на части, левая из которых не превосходит медианы, а правая – не меньше медианы. Здесь для простоты множество элементов { A s , A s+1 , … , A t } будем обозначать {s,t}. Медиану будем обозначать M.
QuickSort(A,p,q)
Если q-p < 1 то ВЫЙТИ
Вечный цикл
i=p; j=q; // пусть M=A j
//цикл 1:
Пока Ai < A j : i + +;
//{p,i-1}<=M<={j,q}, Ai>=M
поменять местами A i и A j ;//x -> Ai
//{p,i}<=M<={j,q}
j --;
//{p,i}<=M<={j+1,q}
Если i >= j то
//либо i==j то {p, j}<=M<={ j+1,q}
// либо i==j+1 то M== Aj+1 => {p, j}<=M<={ j+1,q}
{ QuickSort(A, p, j ); QuickSort(A, j+1, q );ВЫЙТИ }
//цикл 2:
Пока A j > Ai : j - -;
//{p,i}<=M<={j+1,q}, A j<=M
поменять местами A i и A j ;//x -> A j
//{p,i}<=M<={j,q}
i + +;
//{p,i-1}<=M<={j,q}
Если i >= j то
//либо i==j то M== Aj => {p, j}<=M<={ j+1,q}
// либо i==j+1 то {p, j}<=M<={ j+1,q}
{ QuickSort(A, p, j ); QuickSort(A, j+1, q );ВЫЙТИ }
Конец вечного цикла
В силу построения алгоритма j не может стать меньше 0 и не может быть больше или равным q, поэтому гарантируется, что мы не попадем в бесконечную рекурсию и границы рассмотрения массива корректны.
Отметим, что после первого цикла также имеем:
Если i >= j то
//либо i==j то {p, i}<=M<={ i+1,q}
// либо i==j+1 то M== Aj+1 => {p, i}<=M<={ i+1,q}
т.е. рекурсию можно было бы организовать в виде:
{ QuickSort(A, p, i ); QuickSort(A, i+1, q );ВЫЙТИ }
но в этом случае мы можем попасть в бесконечную рекурсию, т.к. в цикле i может дойти вплоть до q.
После второго цикла также имеем:
Если i >= j то
//либо i==j то {p, i-1}<=M<={ i,q}
// либо i==j+1 то {p, i-1}<=M<={ i,q}
т.е. рекурсию можно было бы организовать в виде:
{ QuickSort(A, p, i-1 ); QuickSort(A, i, q );ВЫЙТИ }
В этом случае i не может стать меньше 1 и не может быть больше q, поэтому такой вариант алгоритма также возможен.
--------------------------------------------------------------------------------
В более стандартной реализацией основной идеи данного алгоритма выбирается произвольный элемент x сортируемого множества в качестве среднего элемента и помещается в отдельную ячейку памяти. Далее, один шаг алгоритма заключается в следующем. Мы двигаемся слева направо, пока элементы множества меньше x. Затем мы движемся справа налево, пока элементы множества больше x. Если мы еще не встретились, то следует поменять местами элементы, на которых мы стоим при движении в каждую сторону и повторить шаг алгоритма. Если же мы встретились, то алгоритм вызывается для каждой из полученных половин множества.
QuickSort(A,p,q)
Если q-p < 1 то ВЫЙТИ
Вечный цикл
i=p; j=q; x=Ai
Пока A i < x : i + +;//{p,i-1}<=x, Ai >=x
Пока A j > x : j - -;//{j+1,q}>=x, Aj <=x
Если i < j то
поменять местами A i и A j ; //{p,i}<=x, {j,q}>=x
иначе
{
//либо i==j то Ai ==x => {p,j}<=x, {j+1,q}>=x
//либо i==j+1 то {p,j}<=x, {j+1,q}>=x
QuickSort(A, p, j ); QuickSort(A, j+1, q );ВЫЙТИ
}
i + +; j - -;//{p,i-1}<=x, {j+1,q}>=x
Конец вечного цикла
Замечание 1. При работе алгоритм индексы массива i и j никогда не выйдут за его границы p и q.
Замечание 2. В алгоритме никогда не произойдет вечной рекурсии, т.е. при рекурсивном вызове
p j < q
Замечание 3. Алгоритм гарантирует корректное разбиение массива, т.е. после разбиения массива выполняются соотношения
Ak x для всех k: p k j
Al x для всех k: j+1 k qj
Тонкость алгоритма характеризует следующее наблюдение. Давайте попробуем ``обезопасить алгоритм’’ и включим обеспечение условия i j в циклы алгоритма Пока… . Т.е. приведем алгоритм к следующему виду:
QuickSort*(A,p,q)
Если q-p < 1 то ВЫЙТИ
Вечный цикл
i=p; j=q; x=Ai
Пока A i < x и i < j : i + +;
Пока A j > x и i < j : j - -;
Если i < j то
поменять местами A i и A j ;
иначе
{ QuickSort(A, p, j ); QuickSort(A, j+1, q );ВЫЙТИ }
i + +; j - -;
Конец вечного цикла
Алгоритм QuickSort* оказывается неверным !!! Это легко увидеть на простейшем примере: {3,4,2,5}.