Модели и структуры данных

       

Сортировки распределением.


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

Алгоритм требует представления ключей сортируемой последовательности в виде чисел в некоторой системе счисления P. Число проходов сортировка равно максимальному числу значащих цифр в числе - D. В каждом проходе анализируется значащая цифра в очередном разряде ключа, начиная с младшего разряда. Все ключи с одинаковым значением этой цифры объединяются в одну группу. Ключи в группе располагаются в порядке их поступления. После того, как вся исходная последовательность распределена по группам, группы располагаются в порядке возрастания связанных с группами цифр. Процесс повторяется для второй цифры и т.д., пока не будут исчерпаны значащие цифры в ключе. Основание системы счисления P может быть любым, в частном случае 2 или 10. Для системы счисления с основанием P требуется P групп.

Порядок алгоритма качественно линейный - O(N), для сортировки требуется D*N операций анализа цифры. Однако, в такой оценке порядка не учитывается ряд обстоятельств.

Во-первых, операция выделения значащей цифры будет простой и быстрой только при P=2, для других систем счисления эта операция может оказаться значительно более времяемкой, чем операция сравнения.

Во-вторых, в оценке алгоритма не учитываются расходы времени и памяти на создание и ведение групп. Размещение групп в статической рабочей памяти потребует памяти для P*N элементов, так как в предельном случае все элементы могут попасть в какую-то одну группу. Если же формировать группы внутри той же последовательности по принципу обменных алгоритмов, то возникает необходимость перераспределения последовательности между группами и все проблемы и недостатки, присущие алгоритмам включения. Наиболее рациональным является формирование групп в виде связных списков с динамическим выделением памяти.

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


Область памяти, занимаемая массивом перераспределяется между входным и выходным множествами, как это делалось и в ряде предыдущих примеров. Выходное множество (оно размещается в начале массива) разбивается на группы. Разбиение отслеживается в массиве b. Элемент массива b[i] содержит индекс в массиве a,с которого начинается i+1-ая группа. Номер группы определяется значением анали- зируемой цифры числа, поэтому индексация в массиве b начинается с 0. Когда очередное число выбирается из входного множества и должно быть занесено в i-ую группу выходного множества, оно будет записано в позицию, определяемую значением b[i]. Но предварительно эта позиция должна быть освобождена: участок массива от b[i] до конца выходного множества включительно сдвигается вправо. После записи числа в i-ую группу i-ое и все последующие значения в массиве b корректируются - увеличиваются на 1.

{===== Программный пример 3.15 =====} { Цифровая сортировка (распределение) } const D=...; { максимальное количество цифр в числе } P=...; { основание системы счисления } Function Digit(v, n : integer) : integer; { возвращает значение n-ой цифры в числе v } begin for n:=n downto 2 do v:=v div P; Digit:=v mod P; end; Procedure Sort(var a : Seq); Var b : array[0..P-2] of integer; { индекс элемента, следующего за последним в i-ой группе } i, j, k, m, x : integer; begin for m:=1 to D do begin { перебор цифр, начиная с младшей } for i:=0 to P-2 do b[i]:=1; { нач. значения индексов } for i:=1 to N do begin { перебор массива } k:=Digit(a[i],m); { определение m-ой цифры } x:=a[i]; { сдвиг - освобождение места в конце k-ой группы } for j:=i downto b[k]+1 do a[j]:=a[j-1]; { запись в конец k-ой группы } a[b[k]]:=x; { модификация k-го индекса и всех больших } for j:=k to P-2 do b[j]:=b[j]+1; end; end;

Результаты трассировки программного примера 3.15 при P=10 и D=4 представлены в таблице 3.9.



Таблица 3.9

Быстрая сортировка Хоара.

Данный алгоритм относится к распределительным и обеспечивает показатели эффективности O(N*log2(N)) даже при наихудшем исходном распределении.



Используются два индекса - i и j - с начальными значениями 1 и N соответственно. Ключ K[i] сравнивается с ключом K[j]. Если ключи удовлетворяют критерию упорядоченности, то индекс j уменьшается на 1 и производится следующее сравнение. Если ключи не удовлетворяют критерию, то записи R[i] и R[j] меняются местами. При этом индекс j фиксируется и начинает меняться индекс i(увеличиваться на 1 после каждого сравнения). После следующей перестановки фиксируется i и начинает изменяться j и т.д. Проход заканчивается, когда индексы i и j становятся равными. Запись, находящаяся на позиции встречи индексов, стоит на своем месте в последовательности. Эта запись делит последовательность на два подмножества. Все записи, расположенные слева от нее имеют ключи, меньшие чем ключ этой записи, все записи справа - большие. Тот же самый алгоритм применяется к левому подмножеству, а затем к правому. Записи подмножества распределяются по двум еще меньшим подмножествам и т.д., и т.д. Распределение заканчивается, когда полученное подмножество будет состоять из единственного элемента - такое подмножество уже является упорядоченным.

Процедура сортировки в примере 3.16 рекурсивная. При ее вызове должны быть заданы значения границ сортируемого участка от 1 до N.

{===== Программный пример 3.16 =====} { Быстрая сортировка Хоара } Procedure Sort(var a : Seq; i0,j0 : integer); { i0, j0 - границы сортируемого участка } Var i, j : integer; { текущие индексы в массиве } flag : boolean; { признак меняющегося индекса: если flag=true - уменьшается j, иначе - увеличивается i } x : integer; begin if j0 a[j] then begin x:=a[i]; a[i]:=a[j]; a[j]:=x; { перестановка } { после перестановки меняется изменяемый индекс } flag:= not flag; end; { реально изменяется только один индекс } if flag then j:=j-1 else i:=i+1; end; Sort(a,i0,i-1); { сортировка левого подмассива } Sort(a,i+1,j0); { сортировка правого подмассива } end;

Результаты трассировки примера приведены в таблице 3.10. В каждой строке таблицы показаны текущие положения индексов i и j, звездочками отмечены элементы, ставшие на свои места.Для каждого прохода показаны границы подмножества, в котором ведется сортировка.



Таблица 3.10




Содержание раздела