
- •1. Асимптотическая оценка алгоритма
- •2. Методика оценки не рекурсивных алгоритмов. Пример
- •3. Рекурсивные алгоритмы, построение асимптотической оценки. Пример
- •4. Методика оценки рекурсивных алгоритмов.
- •5. Алгоритмы сортировки массивов за полиномиальное время
- •6. Быстрые алгоритмы сортировки массивов, основанные на сравнении элементов
- •7. Алгоритмы сортировки массивов за линейное время
- •8. Линейные структуры данных, основные операции и характеристики
- •9. Деревья, виды, способы представления, структуры данных, обходы дерева
- •10. Двоичные деревья поиска, операции добавления элементов.
- •11. Двоичные деревья поиска, операции удаления элементов и поиска следующих
- •13. Двоичные кучи, основные операции и характеристики
- •16. Динамическое программирование, основные особенности
- •17. Жадные алгоритмы, основные особенности
- •18. Построение кода Хаффмена
- •19. Алгоритм обхода графов в ширину
- •20. Алгоритм обхода графов в глубину
- •21. Остовое дерево, классификация ребер, топологическая сортировка.
- •22. Сильно связные компоненты, алгоритм поиска
- •23. Построение минимально покрывающего дерева, алгоритм Крускала
- •24. Построение минимального покрывающего дерева, алгоритм Прима
- •25. Происк кратчайшего пути. Алгоритм Дейкстры
- •26. Поиск кратчайшего пути. Алгоритм Беллмана-Форда
5. Алгоритмы сортировки массивов за полиномиальное время
Сортировка - процесс перестановки объектов заданной
совокупности в определенном порядке (возрастающем
или убывающем).
Целью сортировки обычно является облегчение последующего
поиска элементов в отсортированном множестве.
Сортировка простыми вставками
void sort_by_insertion(key a[] , int N)
{
key x;
int i, j;
for (i=1; i < N; i++)
{
x = a[i] ;
for (j=i-1; (j>=0)&& (x < a[j]); j--)
a[j + 1] = a[j];
a[j + 1] = x;
}
}
Анализ сортировки простыми вставками
Наихудший случай: упорядоченный в обратном порядке массив
Количество сравнений:
С (N) = 1 + 2 + 3 + ... + N - 1 = (N *(N -1) )/2= О (N2)
Общее время: T(N) = θ(N2)
Сортировка простым обменом. Метод пузырька.
void bubble_sort (key а[] , int N)
{ int i, j;
key x;
for (i=0; i<N-l; i++)
for (j=N-l; j>i; j--)
if (a[j-l] > a[j]) {
x = a [ j ] ; a [ j ] = a [ j -1] ; a [ j -1] = x;
}
}
Анализ сортировки простым обменом
Наихудший случай: упорядоченный в обратном порядке массив
Количество сравнений:
C(N) = (N - 1) + (N - 2) + ... + 1 = (N * (N-1))/2 = O(N2)
Общее время: T(N) = θ(N2)
6. Быстрые алгоритмы сортировки массивов, основанные на сравнении элементов
Хоара:
Разделяем массив на два подмассива [1 ...m] и [m +1 . ..N],
причем
Рекурсивно сортируем получившиеся два подмассива.
Быстрая сортировка использует стратегию Разделяй и властвуй
Выбираем в массиве некоторый элемент, который будем называть опорным элементом. Известные стратегии: выбирать постоянно один и тот же элемент, например, первый, средний или последний по положению; выбирать элемент со случайно выбранным индексом.
Операция разделения массива: реорганизуем массив таким образом, чтобы все элементы, меньшие или равные опорному элементу, оказались слева от него, а все элементы, большие опорного — справа от него.
Два индекса — l и r, приравниваются к минимальному и максимальному индексу разделяемого массива соответственно.
Вычисляется индекс опорного элемента m.
Индекс l последовательно увеличивается до тех пор, пока l-й элемент не превысит опорный.
Индекс r последовательно уменьшается до тех пор, пока r-й элемент не окажется меньше либо равен опорному.
Если r = l — найдена середина массива — операция разделения закончена, оба индекса указывают на опорный элемент.
Если l < r — найденную пару элементов нужно обменять местами и продолжить операцию разделения с тех значений l и r, которые были достигнуты.
Рекурсивно упорядочиваем подмассивы, лежащие слева и справа от опорного элемента.
Базой рекурсии являются наборы, состоящие из одного или двух элементов. Первый возвращается в исходном виде, во втором, при необходимости, сортировка сводится к перестановке двух элементов. Все такие отрезки уже упорядочены в процессе разделения.
Quicksort (int A[], int p, int r){
void quicksort (int а[], int l, int г)
{ int x, w;
int i , j ;
i = 1; j = r;
x = a[(l + r)/2];
do {
while (a[i] < x) i++;
while (x < a[j]) j--;
if (i <= j) {
w = a[i] ;
a [i] = a [j] ;
a[j] = w;
i++;
j--; }
} while (i<=j);
if (l < j) quicksort (a, l, j);
if (i < r) quicksort (a, i, r);
}
int Partition (int A[], int left, int right)
int s= left++;
while(left<=right){
while(A[left]<A[s]) ++left;
while(A[right]>=A[s]) --right;
if (left<right)
Обменять A[left] ↔ A[right];
}
Обменять A[s] ↔ A[right];
return right;
}
Предположим, что все элементы различны.
Наихудший случай: когда при разделении один из массивов не
имеет элементов.
T(n) = T(0) + T(n - 1) + Θ(n)
= Θ(1) + T(n - 1) + Θ(n)
= T(n - 1) + Θ(n)
= Θ(n2)
Анализ быстрой сортировки (наилучший случай)
Наилучший случай: когда при разделении массив разделяется
на равные части.
Т(n) = 2T (n/2) + Θ(n)
= Θ(n • log(n))
Рандомизированная быстрая сортировка
Время работы не зависит от порядка элементов во входных данных;
Не нужно предположений о распределении входных данных;
Нет входных данных, которые приводят к наихудшему случаю;
Наихудший случай определяется только генератором
случайных чисел.
Рандомизированная быстрая сортировка
Выбираем граничный элемент случайным образом!
RandomizedPartition (A,p,r)
1 i ← Random(p,r)
2 Обменять A[r] ↔ A[i]
3 return Partition(A,p,r)
RandomizedQuickSort(A,p, r)
1 if p < r
2 then q ← RandomizedPartition(A, p, r)
3 RandomizedQuicksort(A,p,q - 1)
4 RandomizedQuicksort(A, q + 1, r)
Наименьшее время сортировки
Теорема. В любом алгоритме, упорядочивающем с помощью
сравнения пар, на упорядочивание последовательности из N
элементов тратится не меньше c * N * log2N сравнений
при c = 0 и N → ∞.
T(n) > c • N • log2N, при c = 0 и N → ∞
Наименьшее время сортировки. Доказательство
Число перестановок последовательности из N элементов равно N!
Сортировка путем сравнения пар есть спуск по дереву решений –
двоичному, где листья перестановки, а внутренние узлы условия.
Число сравнений равно высоте разрешающего дерева