- •Методы построения хэш-функций
- •Адресация в хэш-таблицах
- •Открытая адресация
- •Способы вычисления последовательности испробованных мест при открытой адресации
- •Реализация хэш-таблицы с открытой адресацией
- •Int HashFn(int key, int m, int p)
- •Int Next_hash(int hash, int m, int p)
- •Int HashOt::SearchInd(int key)
- •Прямая адресация
- •Реализация хэш-таблиц с прямой адресацией
- •Void* Data;
- •Int _tmain(int argc, _tchar* argv[])
- •Исследование времени
- •Оценка сложности алгоритмов
- •Анализ трудоёмкости алгоритмов
- •Классы сложности
- •Поиск и сортировка
- •Int Is_sorted(int a[ ], int n)
- •Void main()
- •Int BinP(int c[], int n, int val)
- •Void main()
- •Сортировка
- •Обменные сортировки
- •Void BubbleSort(int *a, int n)
- •Void main()
- •Void BubbleSort(int *a, int n)
- •Void main()
- •Шейкерная сортировка (перемешиванием)
- •Void ShakerSort(int *b, int Start, int n)
- •Void main()
- •Void BubbleSort(int *a, int n)
- •Void ShakerSort(int *b, int Start, int n)
- •Void main()
- •Сортировка выбором
- •Void SelectSort(int a[], int n)
- •Void main()
- •Сортировка квадратичной выборкой
- •Сортировка вставками
- •Void main()
- •InsertSort(a, n);
- •Cортировка Шелла
- •Void main()
- •Сортировка разделением (быстрая сортировка)
- •Void QuickSort(int a[], int n)
- •Void main()
- •Int GetHoarBorder(int m[], int sm, int em)
- •Int* SortHoar(int m[], int sm, int em)
- •Void main()
- •Сортировка подсчетом
- •Void CountSort(int in[], int out[], int n)
- •Void main()
- •Пирамидальная сортировка
- •Void Heapify (int a[], int pos, int n)
- •Void PiramSort(int a[], int n)
- •Void main()
- •Void iswap(int &n1, int &n2)
- •Int main()
- •Сортировка слиянием
- •Void InsOrd(int m[], int sm, int em, int e)
- •Void main()
- •Поразрядная (распределяющая) сортировка
- •Int VelichRazr(int chislo, int razr)
- •Void PorazrSort(int b[n][n], int a[n], int razr)
- •Void main()
- •Методы разработки алгоритмов
- •Свойства алгоритма
- •Метод декомпозиции (разбиения)
- •Динамическое программирование
- •Жадные алгоритмы
- •Полный перебор
- •Алгоритмы локального поиска
- •Методы и технологии разработки программ
Анализ трудоёмкости алгоритмов
Целью анализа трудоёмкости алгоритмов является нахождение оптимального алгоритма для решения задачи.
В качестве критерия оптимальности алгоритма выбирается трудоемкость алгоритма, понимаемая как количество элементарных операций, которые надо выполнить для решения задачи с помощью данного алгоритма.
Функцией трудоемкости называется отношение, связывающие входные данные алгоритма с количеством элементарных операций.
Одним из упрощенных видов анализа, является асимптотический анализ алгоритмов.
Целью асимптотического анализа является сравнение затрат времени и других ресурсов при использовании различных алгоритмов, предназначенных для решения одной и той же задачи, при больших объемах входных данных.
Используемая в асимптотическом анализе оценка функции трудоёмкости, называемая сложностью алгоритма, позволяет определить, как быстро растет трудоёмкость алгоритма с увеличением объема данных.
Для описания скорости роста функций используется асимптотическая оценка O.
Она представляет собой верхнюю асимптотическую оценку трудоемкости алгоритма и позволяет определить, как быстро растет трудоемкость алгоритма с увеличением объема данных.
Определение. T(n) = O(f(n)), если существуют константы c > 0, n0 > 0 такие, что выполняется неравенство: 0 <= T(n) <= cf(n) для любого n >= n0
Здесь n - величина объёма данных.
Иначе говоря, запись T(n) = O(f(n)) означает, что T(n) принадлежит классу функций, которые растут не быстрее, чем функция f(n) с точностью до постоянного множителя.
Когда используют обозначение O(), имеют в виду не точное время исполнения, а только его предел сверху, причем с точностью до постоянного множителя.
Напр., если говорят, что алгоритму требуется время порядка O(n2), то имеют в виду, что время выполнения задачи растет не быстрее, чем квадрат количества элементов.
Пример. Функция T(n) = 3n3+2n2 имеет степень роста O(n3), т.е. время выполнения задачи растет не быстрее, чем куб количества исходных данных. Если c = 5, n0 = 0, то 3n3+2n2 <=5n3
При оценке трудоемкости используют правило сумм: в общем случае трудоемкость выполнения программных фрагментов имеет порядок фрагмента с наибольшим временем выполнения.
Пример. Пусть есть три фрагмента с временами выполнения O(n3), O(n2), O(nlogn). Тогда время выполнения первых двух фрагментов – это максимум из первых двух оценок - O(n3). Затем сравнивается результат и третья оценка.
Для всех трех - O(n3).
При оценке трудоемкости используется также правило произведений: если T1(n) и T2(n) имеют степени роста O(f(n)) и O(g(n)) соответственно, то произведение T1(n)T2(n) имеет степень роста O(f(n))O(g(n)).
Например, O(n2 / 2) эквивалентно O(n2).
Скорость роста некоторых функций:
n log n n*log n n2
1 0 0 1
16 4 64 256
256 8 2048 65536
4096 12 49152 16777216
65536 16 1048565 4294967296
1048476 20 20969520 1099301922576
16775616 24 402614784 281421292179456
Из таблицы видно, что для задач с небольшим значением n метод решения задачи не влияет на скорость, но по мере роста n время, нужное для получения решения, становится большим (107 секунд равно 3,8 месяца, 108 секунд – 3,1 года).
Оценка Ώ задает нижнюю асимптотическую оценку роста функции T(n) и определяет класс функций, которые растут не медленнее, чем f(n) с точностью до постоянного множителя.
Определение. T(n) = Ώ(f(n)), если существуют константы c > 0, n0 > 0 такие, что выполняется неравенство: T(n) >= cf(n) >= 0 для любого n >= n0.
Например, запись T(n) = Ώ(nlog(n)) обозначает класс функций, которые растут не медленнее, чем f(n) = nlog(n).
(В этот класс попадают все полиномы со степенью, большей единицы, равно как и все степенные функции с основанием большим единицы).
Для задания одновременно верхней и нижней оценки роста функции T(n) используется оценка Ө (“тэта большое”).
Определение. T(n) = Ө(f(n)), если при f > 0 и n > 0 существуют константы c1, c2, n0 такие, что выполняется неравенство: c1f(n) <= T(n) <= c2f(n) для любого n >= n0.
Функция f(n) является асимптотически точной оценкой функции T(n), т.к. по определению функция T(n) не отличается от функции f(n) с точностью до постоянного множителя.
Например, для метода пирамидальной сортировки оценка трудоёмкости составляет T(n) = Ө(nlog(n)), то есть f(n) = nlogn.
Равенство T(n) = Ө(f(n)) выполняется тогда и только тогда, когда T(n) = O(f(n)) и T(n) = Ώ (f(n)).
Важно понимать, что Ө(f(n)) представляет собой не функцию, а множество функций, описывающих рост T(n) с точностью до постоянного множителя.
Асимптотические оценки можно представить в порядке увеличения скорости их роста:
O(1) < O(log2 n) < O(n) < O(nlog2 n) < O(n2) < O(n3) < O(2n)
