Опубликован: 08.04.2009 | Доступ: свободный | Студентов: 485 / 0 | Длительность: 17:26:00
Специальности: Программист
Лекция 4:

Сортировка

< Лекция 3 || Лекция 4: 12345 || Лекция 5 >

4.3. Применения сортировки.

4.3.1. Найти количество различных чисел среди элементов данного массива. Число действий порядка \text{n log n}. (Эта задача уже была в "Переменные, выражения, присваивания" .)

Решение. Отсортировать числа, а затем посчитать количество различных, просматривая элементы массива по порядку.

4.3.2. Дано n отрезков [{a[i]},{b[i]}] на прямой ( {i}={1}\ldots{n} ). Найти максимальное k, для которого существует точка прямой, покрытая k отрезками ("максимальное число слоев"). Число действий - порядка {n} log{n}.

Решение. Упорядочим все левые и правые концы отрезков вместе (при этом левый конец считается меньше правого конца, расположенного в той же точке прямой). Далее двигаемся слева направо, считая число слоев. Встреченный левый конец увеличивает число слоев на 1, правый - уменьшает. Отметим, что примыкающие друг к другу отрезки обрабатываются правильно: сначала идет левый конец (правого отрезка), а затем - правый (левого отрезка).

4.3.3. Дано n точек на плоскости. Указать (n-1) -звенную несамопересекающуюся незамкнутую ломаную, проходящую через все эти точки. (Соседним отрезкам ломаной разрешается лежать на одной прямой.) Число действий порядка \text{n log n}.

Решение. Упорядочим точки по x -координате, а при равных x -координатах - по y -координате. В таком порядке и можно проводить ломаную.

4.3.4. Та же задача, если ломаная должна быть замкнутой.

Решение. Возьмем самую левую точку (то есть точку с наименьшей x -координатой) и проведем из нее лучи во все остальные точки. Теперь упорядочим эти лучи снизу вверх, а точки на одном луче упорядочим по расстоянию от начала луча (это делается для всех лучей, кроме нижнего и верхнего). Ломаная выходит из выбранной (самой левой) точки по нижнему лучу, затем по всем остальным лучам (в описанном порядке) и возвращается по верхнему лучу.

4.3.5. Дано n точек на плоскости. Построить их выпуклую оболочку - минимальную выпуклую фигуру, их содержащую. (Резиновое колечко, натянутое на вбитые в доску гвозди - их выпуклая оболочка.) Число операций не более \text{n log n}.

Указание. Упорядочим точки - годится любой из порядков, использованных в двух предыдущих задачах. Затем, рассматривая точки по очереди, будем строить выпуклую оболочку уже рассмотренных точек. (Для хранения выпуклой оболочки полезно использовать дек, см. "Типы данных" . Впрочем, при упорядочении точек по углам это излишне.)

4.4. Нижние оценки для числа сравнений при сортировке

Пусть имеется n различных по весу камней и весы, которые позволяют за одно взвешивание определить, какой из двух выбранных нами камней тяжелее. (В программистских терминах: мы имеем доступ к функции тяжелее(i,j:1..n):boolean.) Надо упорядочить камни по весу, сделав как можно меньше взвешиваний (вызовов функции тяжелее ).

Разумеется, число взвешиваний зависит не только от выбранного нами алгоритма, но и от того, как оказались расположены камни. Сложностью алгоритма назовем число взвешиваний при наихудшем расположении камней.

4.4.1. Доказать, что сложность произвольного алгоритма сортировки n камней не меньше log_2 n! (где n!=1\cdot2\cdot\ldots
\cdot n ).

Решение. Пусть имеется алгоритм сложности не более d. Для каждого из n! возможных расположений камней запротоколируем результаты взвешиваний (обращений к функции тяжелее ); их можно записать в виде последовательности из не более чем d нулей и единиц. Для единообразия дополним последовательность нулями, чтобы ее длина стала равной d. Тем самым у нас имеется n! последовательностей из d нулей и единиц. Все эти последовательности разные - иначе наш алгоритм дал бы одинаковые ответы для разных порядков (и один из ответов был бы неправильным). Получаем, что 2^d \ge n! - что и требовалось доказать.

Другой способ объяснить то же самое - рассмотреть дерево вариантов, возникающее в ходе выполнения алгоритма, и сослаться на то, что дерево высоты d не может иметь более 2^d листьев.

Несложно заметить, что log_2 n!\ge \text{cn log n} при подходящем c>0, поскольку в сумме

log n! =  log 1 +  log 2 +  log 3 + \ldots +  log n
вторая половина слагаемых не меньше log_2 (n/2) =  log_2
n -1 каждое.

Тем самым любой алгоритм сортировки, использующий только сравнения элементов массива и их перестановки, требует не менее \text{Cn log n} действий, так что наши алгоритмы близки к оптимальным. Однако алгоритм сортировки, использующий другие операции, может действовать и быстрее. Вот один из примеров.

4.4.2. Имеется массив целых чисел {a[1]}\ldots{a[n]}, причем все числа неотрицательны и не превосходят m. Отсортировать этот массив; число действий порядка {m}+{n}.

Решение. Для каждого числа от 0 до m подсчитываем, сколько раз оно встречается в массиве. После этого исходный массив можно стереть и заполнить заново в порядке возрастания, используя сведения о кратности каждого числа.

Отметим, что этот алгоритм не переставляет числа в массиве, как большинство других, а "записывает их туда заново".

Есть также метод сортировки, в котором последовательно проводится ряд "частичных сортировок" по отдельным битам. Начнем с такой задачи.

4.4.3. В массиве {a[1]}\ldots{a[n]} целых чисел переставить элементы так, чтобы четные числа шли перед нечетными (не меняя взаимный порядок в каждой из групп).

Решение. Сначала спишем (во вспомогательный массив) все четные, а потом - все нечетные.

4.4.4. Имеется массив из n чисел от 0 до 2^k-1, каждое из которых мы будем рассматривать как k -битовое слово из нулей и единиц. Используя проверки " i -ый бит равен 0 " и " i -ый бит равен 1 " вместо сравнений, отсортировать все числа за время порядка nk.

Решение. Отсортируем числа по последнему биту (см. предыдущую задачу), затем по предпоследнему и так далее. В результате они будут отсортированы. В самом деле, индукцией по i легко доказать, что после i шагов любые два числа, отличающиеся только в i последних битах, идут в правильном порядке. (Вариант: после i шагов i -битовые концы чисел идут в правильном порядке.)

Аналогичный алгоритм может быть применен для m -ичной системы счисления вместо двоичной. При этом полезна такая вспомогательная задача:

4.4.5. Даны n чисел и функция f, принимающая (на них) значения 1\ldots m. Требуется переставить числа в таком порядке, чтобы значения функции f не убывали (сохраняя порядок для чисел с равными значениями f ). Число действий порядка m+n.

Указание. Завести m списков суммарной длины n (как это сделать, смотри в "Типы данных" о типах данных) и помещать в i -ый список числа, для которых значение функции f равно i. Вариант: посчитать для всех i, сколько имеется чисел x с f(x)=i, после чего легко определить, с какого места нужно начинать размещать числа x с f(x)=i.

4.4.6. Даны n целых чисел в диапазоне от 1 до n^2. Как отсортировать их, сделав порядка n действий?

< Лекция 3 || Лекция 4: 12345 || Лекция 5 >