Введение
Алгоритм сортировки
Сортировка вставками — это простой алгоритм сортировки, который строит окончательно отсортированный массив (или список) по одному элементу за раз, выполняя сравнения. Он значительно менее эффективен для больших списков, чем более продвинутые алгоритмы, такие как быстрая сортировка, сортировка кучей или сортировка слиянием. Однако сортировка вставками обладает рядом преимуществ:
Простая реализация: Джон Бентли демонстрирует версию на C/C++ в три строки, которая становится пятистрочной при оптимизации.
Отношение к другим алгоритмам сортировки
Сортировка вставками очень похожа на сортировку выбором. Как и в сортировке выбором, после k проходов по массиву первые k элементов будут отсортированы. Однако принципиальное различие между этими двумя алгоритмами заключается в том, что сортировка вставками просматривает массив в обратном направлении от текущего ключа, а сортировка выбором – в прямом. В результате сортировка выбором помещает первые k элементов в качестве k наименьших элементов несортированной части входных данных, в то время как сортировка вставками просто помещает первые k элементов входных данных в отсортированный порядок. Основное преимущество сортировки вставками перед сортировкой выбором заключается в том, что сортировка выбором всегда должна просматривать все оставшиеся элементы, чтобы найти наименьший элемент в несортированной части списка, в то время как сортировка вставками требует только одного сравнения, когда (k+1)-й элемент больше, чем k-й элемент; когда это часто происходит (например, если входной массив уже отсортирован или частично отсортирован), сортировка вставками значительно эффективнее сортировки выбором. В среднем (при условии, что ранг (k+1)-го элемента случаен) сортировка вставками потребует сравнения и сдвига половины предыдущих k элементов, то есть сортировка вставками выполнит примерно вдвое меньше сравнений, чем сортировка выбором. В худшем случае для сортировки вставками (когда входной массив отсортирован в обратном порядке) сортировка вставками выполняет столько же сравнений, сколько сортировка выбором. Однако недостатком сортировки вставками по сравнению с сортировкой выбором является то, что она требует больше операций записи, поскольку на каждой итерации вставка (k+1)-го элемента в отсортированную часть массива требует множества обменов элементов для сдвига всех последующих элементов, в то время как для каждой итерации сортировки выбором требуется только один обмен. В общем случае сортировка вставками будет записывать в массив O(n²) раз, в то время как сортировка выбором – только O(n) раз. По этой причине сортировка выбором может быть предпочтительнее в случаях, когда запись в память значительно дороже чтения, например, при использовании EEPROM или флэш-памяти. Хотя некоторые алгоритмы «разделяй и властвуй», такие как быстрая сортировка и сортировка слиянием, превосходят сортировку вставками для больших массивов, нерекурсивные алгоритмы сортировки, такие как сортировка вставками или сортировка выбором, обычно быстрее для очень маленьких массивов (точный размер варьируется в зависимости от среды и реализации, но обычно составляет от 7 до 50 элементов). Поэтому полезной оптимизацией при реализации этих алгоритмов является гибридный подход, использующий более простой алгоритм, когда массив разделен до небольшого размера. Если стоимость сравнений превышает стоимость обменов, как это происходит, например, с ключами-строками, хранящимися по ссылке, или с взаимодействием с пользователем (например, при выборе одного из двух элементов, отображаемых рядом), то использование бинарной сортировки вставками может дать лучшую производительность. Бинарная сортировка вставками использует двоичный поиск для определения правильного положения для вставки новых элементов и, следовательно, выполняет ⌈log₂ n⌉ сравнений в худшем случае. Когда каждый элемент в массиве ищется и вставляется, это O(n log n). Чтобы избежать серии обменов при каждой вставке, входные данные можно хранить в связном списке, что позволяет вставлять или удалять элементы из списка за постоянное время, когда позиция в списке известна. Однако поиск в связном списке требует последовательного прохождения по ссылкам до нужной позиции: связный список не имеет произвольного доступа, поэтому он не может использовать более быстрый метод, такой как двоичный поиск. Следовательно, время, необходимое для поиска, составляет O(n), а время сортировки – O(n²). Если используется более сложная структура данных (например, куча или двоичное дерево), время, необходимое для поиска и вставки, можно значительно сократить; это суть сортировки кучей и сортировки двоичным деревом. В 2006 году Бендер, Мартин Фарач Колтон и Мостеиро опубликовали новый вариант сортировки вставками, называемый библиотечной сортировкой или сортировкой с пробелами, который оставляет небольшое количество неиспользуемых мест (то есть «пробелов») по всему массиву. Преимущество заключается в том, что вставки требуют сдвига элементов только до достижения пробела. Авторы показали, что этот алгоритм сортировки с высокой вероятностью выполняется за время O(n log n). Если используется пропускной список, время вставки сокращается до O(log n), и обмены не требуются, поскольку пропускной список реализован на основе структуры связного списка. Окончательное время выполнения для вставки составит O(n log n).