Опубликован: 05.01.2015 | Доступ: свободный | Студентов: 2177 / 0 | Длительность: 63:16:00
Лекция 10:

Поразрядная сортировка

Поразрядная LSD-сортировка

Другой метод поразрядной сортировки просматривает байты в направлении справа налево. На рис. 10.14 показано, как задача сортировки трехбуквенных слов решается за три прохода по файлу.

 Пример поразрядной LSD-сортировки

Рис. 10.14. Пример поразрядной LSD-сортировки

Метод LSD-сортировки упорядочивает трехбуквенные слова за три прохода (слева направо).

Файл сначала сортируется по последней букве (методом распределяющего подсчета), потом по средней букве, а затем по первой.

Сначала не так легко поверить, что этот метод работает — вообще-то он и не работает, если используемый метод сортировки неустойчив (см. определение 6.1). После того, как определена необходимость устойчивости, уже нетрудно доказать, что LSD-сортировка работает: мы знаем, что после сортировки ключей по i последним байтам (при соблюдении устойчивости) любые два ключа в файле упорядочены (по просмотренным на текущий момент байтам) — либо потому, что первые из i последних байтов отличны друг от друга (и упорядочены по этому байту), либо потому, что первые из i последних байтов совпадают, (и они уже упорядочены в силу устойчивости).

Иначе говоря, если w — i еще не просмотренных байтов какой-либо пары ключей идентичны, то любое различие между этими ключами определяется уже просмотренными i байтами, так что эти ключи должным образом упорядочены, и сохранят этот порядок в силу свойства устойчивости. Если же w — i еще не просмотренных байтов различны, то уже просмотренные i байтов не играют никакой роли, и какой-то из следующих проходов правильно упорядочит эту пару по одному из более значащих байтов.

Требование устойчивости означает, например, что метод разбиения, используемый в бинарной быстрой сортировке, не может быть использован в бинарной версии такой сортировки справа налево. С другой стороны, метод распределяющего подсчета является устойчивым, что сразу же приводит нас к классическому и эффективному алгоритму. Программа 10.4 представляет собой реализацию этого метода. Очевидно, здесь для перераспределения ключей нужен вспомогательный массив — способы, описанные в упражнениях 10.19 и 10.20 и выполняющие распределение без использования дополнительной памяти, не используют дополнительный массив за счет устойчивости.

Метод LSD-сортировки использовался в старых машинах для сортировки перфокарт. Такие машины могли распределять колоду перфокарт по 10 карманам в соответствии с отверстиями, пробитыми в каком-то столбце. Если в некотором наборе столбцов пробиты определенные числа, оператор может отсортировать перфокарты, пропустив их через машину по крайней правой цифре, затем, собрав все перфокарты в одну колоду, снова пропустить их через машину, по предпоследней цифре, и т.д. Физическая сортировка перфокарт представляет собой устойчивый процесс, который и имитирует сортировка методом распределяющего подсчета. Эта версия LSD-сортировки не только широко использовалась в коммерческих целях в пятидесятых и шестидесятых годах прошлого столетия, но ей пользовались и многие осторожные программисты, которые пробивали в последних колонках перфокарт их порядковые номера в колоде — чтобы можно было механически упорядочить перфокарты, если колода случайно рассыплется.

Программа 10.4. Поразрядная LSD-сортировка

Данная программа реализует распределяющий подсчет по байтам слов, но продвигаясь справа налево. Реализация метода распределяющего подсчета должна быть устойчивой. Если R равно 2 (то есть bytesword и bitwords равны), данная программа является прямой поразрядной сортировкой, т.е. поразрядной сортировкой с просмотром битов справа налево (см. рис. 10.15).

  template <class Item>
  void radixLSD(Item a[], int l, int r)
    { static Item aux[maxN];
      for (int d = bytesword-1; d >= 0; d—)
        { int i, j, count[R+1];
          for (j = 0; j < R; j + +) count[j] = 0;
          for (i = l; i <= r; i++)
            count[digit(a[i], d) + 1]++;
          for (j = 1; j < R; j++)
            count[j] += count[j-1];
          for (i = l; i <= r; i++)
            aux[count[digit(a[i], d)]++] = a[i];
          for (i = l; i <= r; i++) a[i] = aux[i];
        }
    }
      
 Пример (бинарной) LSD-сортировки (показаны разряды ключей)

Рис. 10.15. Пример (бинарной) LSD-сортировки (показаны разряды ключей)

На данной диаграмме показано выполнение поразрядной сортировки справа налево на нашем бессменном примере. i-й столбец вычисляется из (i — 1)-го столбца путем извлечения (сохраняя устойчивость) всех ключей с 0 в i-ом разряде, а затем всех ключей с 1 в i-ом разряде. Если перед операцией извлечения (i — 1)-й столбец был упорядочен по (i — 1) последним разрядам ключей, то после операции i-й столбец будет упорядочен по i последним разрядам ключей. Здесь явно показано перемещение ключей на третьем этапе.

На рис. 10.15 показана работа бинарной LSD-сортировки на примере упорядочения тех же ключей, что и на рис. 10.3. Для рассматриваемых 5-разрядных ключей полное упорядочение достигается за пять проходов по ключам справа налево. Сортировка записей с одноразрядным ключом сводится к разбиению файла таким образом, что все записи с ключом 0 находятся перед записями с ключом 1. Как уже было сказано, стратегия разбиения, рассмотренная в начале данной главы в программе 10.1, не может быть использована в силу ее неустойчивости, хотя она вроде бы решает ту же задачу. Имеет смысл рассмотреть поразрядную сортировку с основанием 2, поскольку во многих случаях ее удобно реализовать на высокопроизводительных машинах или с помощью специальной аппаратуры (см. упражнение 10.38). В программах мы используем максимально возможное число разрядов, чтобы уменьшить число проходов, и ограничены только размерами массива счетчиков (см. рис. 10.16).

 Динамические характеристики поразрядной LSD-сортировки

Рис. 10.16. Динамические характеристики поразрядной LSD-сортировки

На этой диаграмме показаны этапы LSD-сортировки случайных 8-разрядных ключей, по основанию 2 (слева) и 4 (справа); последняя включает в себя каждый второй этап из диаграммы для основания 2. Например, когда остаются два разряда (второй этап с конца на левой диаграмме, предпоследний на правой диаграмме), сортируемый файл состоит из четырех перемежающихся отсортированных подфайлов, которые состоят из ключей, начинающихся с 00, 01, 10 и 11.

Применение LSD-подхода к сортировке строк обычно затруднено из-за переменной длины ключей. В случае MSD-сортировки достаточно легко сравнивать ключи по их старшим байтам, но LSD-сортировка предполагает постоянную длину ключа, при этом ведущие байты используются только на заключительном проходе. Даже в случае ключей (большой) фиксированной длины LSD-сортировка, очевидно, выполняет бесполезную работу на последних байтах ключей, поскольку, как мы уже убедились, в процессе сортировки обычно важны только левые части ключей. Способ решения этой проблемы будет показан в разделе 10.7, после подробного изучения свойств поразрядной сортировки.

Упражнения

10.32. Используя генератор ключей из упражнения 10.19, выполните LSD-сортировку для N = 103, 104, 105 и 106 . Сравните показатели этой сортировки с параметрами MSD-сортировки.

10.33. Используя генератор ключей из упражнений 10.21 и 10.23, выполните LSD-сортировку для N = 103, 104, 105 и 106 . Сравните показатели этой сортировки с параметрами MSD-сортировки.

10.34. Приведите (несортированный) результат выполнения LSD-сортировки на основе разбиения бинарной быстрой сортировки, для примера, представленного на рис.10.15.

10.35. Приведите результат применения LSD-сортировки для упорядочения по двум первым символам совокупности ключей now is the time for all good people to come the aid of their party.

10.36. Разработайте реализацию LSD-сортировки для связных списков.

10.37. Найдите эффективный метод, который (1) переупорядочивает записи файла таким образом, что записи, начинающиеся с бита 0, находятся перед записями, начинающимися с бита 1, (2) использует объем дополнительной памяти, пропорциональный квадратному корню из количества записей (или менее), и (3) устойчив.

10.38. Реализуйте метод, который сортирует массив 32-разрядных слов, используя лишь следующую абстрактную операцию: для заданной позиции i и указателя на элемент массива a[k] упорядочить (с сохранением устойчивости) элементы a[k], a[k+1], ..., a[k+63] таким образом, чтобы слова с битом 0 в i-ой позиции находились перед словами с битом 1 в i-ой позиции.

Бактыгуль Асаинова
Бактыгуль Асаинова

Здравствуйте прошла курсы на тему Алгоритмы С++. Но не пришел сертификат и не доступен.Где и как можно его скаачат?

Александра Боброва
Александра Боброва

Я прошла все лекции на 100%.

Но в https://www.intuit.ru/intuituser/study/diplomas ничего нет.

Что делать? Как получить сертификат?