Качество Стоимость - Основы программного конструирования

advertisement
ОСНОВЫ ПРОГРАММНОГО
КОНСТРУИРОВАНИЯ
я
Ка
ч
ем
Вр
ес
тво
Лекция № 11
28 апреля 2015 г.
Стоимость
https://github.com/cypok/console_graphics
https://github.com/cypok/sdl_example
ЗАДАЧКА О СОРТИРОВКАХ
Даны 7 массивов чисел:
1.
B A 9 6 1 D F 3 0 E 8 5 C 2 4 7;
2.
1 6 9 3 0 A 8 5 B 2 4 7 C D E F;
3.
0 1 2 3 4 5 F 6 B E 8 D C 9 A 7;
4.
C A B 7 8 5 9 6 0 1 3 2 4 D E F;
5.
4 2 0 3 1 5 7 6 9 A 8 B C E F D;
6.
1 6 9 A B D F 3 0 E 8 5 C 2 4 7;
7.
0 1 2 3 4 5 6 7 8 9 A B C D E F.
Массив 1 — начальный.
Массив 7 — отсортированный.
Массивы 2-6 являются
промежуточными состояниями при
сортировке начального массива
разными алгоритмами:
a. сортировка выбором,
b. пузырьковая сортировка (обычная,
слева направо),
c. сортировка вставками,
d. быстрая сортировка (без
перемешивания, первый элемент как
медиана),
e. пирамидальная сортировка.
Определить, какой массив 2-6 соответствует какой сортировке a-e. Ответа
недостаточно, нужно объяснение, почему именно этот массив может
соответствовать именно этой сортировке.
Подсказка: нужно заметить характерные свойства каждой из сортировок.
СОРТИРОВКА СЛИЯНИЕМ
(MERGESORT)
•
Разделение. Как-либо делим массив на 2 части.
•
Покорение. Для каждой из частей размером больше 1
алгоритм вызывается рекурсивно.
•
Комбинирование. Линейное слияние отсортированных
подмассивов.
СОРТИРОВКА СЛИЯНИЕМ
(MERGESORT)
Линейный алгоритм слияния 2 отсортированных массивов:
• Заводим
2 индекса, изначально указывающих на начала
массивов.
• На
каждом шаге выбираем наименьший элемент из двух, на
которые указывают индексы, записываем его в
результирующий массив и сдвигаем этот индекс. Если
соответствующий массив кончился, отбрасываем индекс
вместе с массивом.
• Когда
все массивы кончились, в результирующем массиве
лежат все элементы, отсортированные.
ОСОБЕННОСТИ
СОРТИРОВКИ СЛИЯНИЕМ
• Сложность
O(N log(N)).
дополнительная память (еще один массив размером N).
• Требуется
• Осуществляет
доступ к сортируемым элементам
последовательно. Поэтому годится для сортировки
связанных списков.
• Является
стабильной, в отличие от быстрой и
пирамидальной сортировок.
АНИМАЦИЯ
http://www.sorting-algorithms.com/merge-sort
ИНТЕРВЬЮ БАРАКА ОБАМЫ
В GOOGLE
Eric Schmidt: What is the most efficient way to sort a million
32-bit integers?
Barack Obama: Well...
Eric Schmidt: Maybe–I'm sorry...
Barack Obama: No, no, no, no. I think–I think the bubble sort
would be the wrong way to go.
СОРТИРОВКА ЗА
ЛИНЕЙНОЕ ВРЕМЯ
произвольных ключей математически доказано: количество сравнений не менее N log(N).
• Для
•А
что, если ключи не произвольные?
• Сколько
операций нужно, чтобы отсортировать
последовательность битов?
01001010100000110010111001001111
СОРТИРОВКА ПОДСЧЕТОМ
(COUNTING SORT)
• Предположим, что
все ключи – целые числа 0…K−1.
массив счетчиков C[k] размером K, изначально
заполненный нулями.
• Заведем
• Подсчитаем
количество вхождений каждого ключа.
к каждому элементу C[k] все предыдущие, получая: C[k] = количество ключей, не превышающих k.
• Добавим
с конца массива элементов, ставя элемент A[n] на позицию
C[Key(A[n])]−1 и уменьшая счетчик.
• Идем
СВОЙСТВА
СОРТИРОВКИ ПОДСЧЕТОМ
• Временная
сложность O(N+K).
• Стабильность.
• Дополнительная
память:
массив длины N (если стабильность не нужна, можно обойтись без него);
• вспомогательный
• массив
счетчиков.
ПОРАЗРЯДНАЯ
СОРТИРОВКА (RADIX SORT)
• Предположим, что
• Алгоритм
«от младшей к старшей»:
• Стабильная
•…
ключи состоят из d «цифр».
сортировка массива по 1-й цифре (младшей).
по 2-й цифре.
•…
•…
по d-й цифре (старшей).
• Годится
для сортировки по составным ключам.
• Сложность
O(N).
КАРМАННАЯ СОРТИРОВКА
ключи – N равномерно
распределенных в интервале [0,1) чисел.
• Предположим, что
• Поделим
интервал на N подинтервалов (карманы).
• Раскидаем
элементы по карманам.
• Отсортируем
элементы в каждом кармане отдельно
(сортировка вставками).
• Последовательно
•В
выложим содержимое карманов.
среднем работает за O(N).
ЗАДАЧА ПОИСКА
ЛИНЕЙНЫЙ ПОИСК
Дан массив A[0…N−1] и ключ K. Требуется определить
положение элемента с данным ключом в массиве или
установить, что его там нет.
Последовательно сравниваем ключи, пока не найдем
совпадающий ключ или массив не кончится.
Сложность O(N).
БИНАРНЫЙ ПОИСК
(ДЕЛЕНИЕМ ПОПОЛАМ)
Дан отсортированный массив A[0…N−1] и ключ K. Требуется
определить положение элемента с данным ключом в массиве или
установить, что его там нет.
Возьмем серединный элемент массива (m-й) и сравним его ключ Km с K:
•
Если Km = K, то ключ найден.
•
Если Km < K, то продолжаем поиск в правой половине: A[m+1…N−1].
•
Если Km > K, то продолжаем поиск в левой половине: A[0…m−1].
Сложность O(log(N)).
ЗНАКОМЫЕ СТРУКТУРЫ
ДАННЫХ ДЛЯ ПОИСКА
• Двоичные
деревья поиска.
• Хеш-таблицы.
ПОИСК
ПОДСТРОКИ В СТРОКЕ
строка — «стог сена» длины N («abcddsdfff»).
Определить, встречается ли в ней строка-«иголка» длины
M («ddf») и если да, то на какой позиции.
• Задача: дана
• Метод
грубой силы: подставляем «иголку» к каждой
возможной позиции в «стоге сена», покуда не совпадет
или «стог» не кончится.
Количество сравнений: O((N−M)·M).
КАК УБЫСТРИТЬ ПОИСК?
«стог сена»
«иголка»
b c a b c b c b a a …
a a a a a
• Явно
нет смысла сдвигать «иголку» на одну позицию
вправо.
• Хорошо
бы как-то учесть частичное совпадение строк и
не проверять все символы заново каждый раз.
АЛГОРИТМ БОУЭРА-МУРА
(МОДИФИЦИРОВАННЫЙ)
•
Строки h и n: «стог сена» (haystack) и «иголка» (needle),
соответственно.
•
Хитрый массив d, индексируемый символами x из алфавита.
Для каждого символа x из h:
•
если x отсутствует в n, то d[x] равно M;
•
если x – не последний в n, то d[x] равно расстоянию от
самого правого вхождения x в n до последнего символа в n;
•
если x – последний в n, то d[x] равно расстоянию от
предпоследнего вхождения x в n до конца n.
ПОИСК ПО БОУЭРУ-МУРУ
• Подставляем
«иголку» к началу «стога» (i = M−1).
символы с конца «иголки»: h[k] и n[j],
уменьшая k и j (изначально k = i, j=M−1).
• Сравниваем
• Если
j дошло до начала «иголки» (0), подстрока найдена!
на каком-то шаге h[k] ≠ n[j], то сдвигаем «иголку» на
d[h[i]] вправо (i += d[h[i]]).
• Если
АЛГОРИТМ РАБИНА-КАРПА
• Представим, что
«иголка» и «стог» состоят только из
символов 0…9.
Пример: ищем «123» в «8786124612612341».
• Tn
= «иголка» как число в десятичной записи.
• T[k]
= M символов «стога», начиная с позиции k, как число.
• T[k+1]
= (T[k] − 10M−1·h[k])·10 + h[k+M].
• Линейное
время поиска.
РАБИН-КАРП
В РЕАЛЬНОЙ СИТУАЦИИ
• Вместо
10 взять 256 (для ASCII-строк) и выполнять
вычисления по модулю некоего большого числа.
10 взять 2, за большое число принять 2N, где N –
размер слова.
• Вместо
• Что-то
• При
наподобие хеш-функции.
совпадении хешей посимвольная проверка.
КОНЕЦ ОДИННАДЦАТОЙ ЛЕКЦИИ
Долго искать в темной комнате черную кошку, особенно если ее там нет.
Download