Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие часть 1.doc
Скачиваний:
60
Добавлен:
24.09.2019
Размер:
6.98 Mб
Скачать

4.4.2. Распределяющая сортировка от младшего разряда к старшему

Вышеописанным методом можно выполнять сортировку чисел лишь из небольшого диапазона (так как массив c должен иметь приемлемую длину). Алгоритм распределяющей сортировки берёт за основу алгоритм сортировки подсчётом и позволяет выполнять сортировку чисел (и некоторых других типов) произвольной разрядности. Сначала выполняется сортировка по младшему разряду (в качестве разрядов обычно выступают байты или двухбайтные слова), затем – по следующему и т.д. до старшего. При этом используется тот факт, что сортировка подсчётом является устойчивой, в результате чего данные будут корректно отсортированы (см. начало главы).

Рассмотрим реализацию алгоритма. Сортировка подсчётом немного усложняется – добавляется код для выделения значения заданного разряда-байта, при этом используются битовые операции сдвига влево <<, сдвига вправо >> и побитового “И” &.

//сортировка подсчетом по байту с номером bytenum

void countsort(unsigned int a[], int n, int bytenum)

{ int c[256]; int i;

int shift = bytenum * 8; //смещение этого байта в битах

int mask = 0xFF << shift; //битовая маска для выделения разряда

//подсчитываем количества

memset(c,0,sizeof(c));

for (i=0; i<n; i++) c[ (a[i]&mask) >> shift ]++;

//подсчитываем сумму с накоплением

for (i=1; i<256; i++) c[i]+=c[i-1];

//заполняем результирующий массив b

unsigned int *b = new unsigned int[n];

memset(b,0,sizeof(int)*n);

for (i=n-1; i>=0; i--)

{ b[--c[(a[i]&mask)>>shift]]=a[i];

}

memcpy(a,b,n*sizeof(int));

delete[] b;

}

//Собственно сортировка будет заключаться в вызове

// данной функции для всех разрядов:

void radsort(int a[], int n)

{ for(int i=0; i<sizeof(int); i++)

countsort(a, n, i);

}

Если k – число разрядов в сортируемых числах, то сложность алгоритма составляет Θ(kn). Обычно k ограничено константой, и в этом случае время работы составляет Θ(n). Таким образом, данный алгоритм является наиболее быстрым из вышерассмотренных (хотя разница становится заметной лишь при больших объёмах данных).

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

Ещё один недостаток алгоритма – использование вспомогательного массива такого же размера, как и исходный.

4.4.3. Распределяющая сортировка от старшего разряда к младшему

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

void ssort(char* a[], int n, int k)

{ static char **b = new char* [n];

static int c[256]; int i,j;

//подсчет количеств каждого значения i-го символа

memset(c,0,sizeof(c));

for(i=0; i<n; i++) c[(unsigned char)a[i][k]]++;

//сумма с накоплением

for(i=1; i<256; i++) c[i]+=c[i-1];

//сортировка по i-му разряду

for(i=n-1; i>=0; i--)

b[--c[(unsigned char)a[i][k]]] = a[i];

memcpy(a,b,sizeof(char*)*n);

//для каждой группы с одинаковым значением i-го разряда

//рекурсивно выполняем сортировку по (i+1)-му разряду

i=0;

while((i<n) && (a[i][k]==0)) i++;

while(i<n)

{ j = i;

while((j<n) && (a[i][k]==a[j][k])) j++;

if (j>i+1) ssort(a+i, j-i, k+1);

i=j;

}

}

В худшем случае время выполнения данного алгоритма прямо пропорционально суммарной длине сортируемых строк и является асимптотически оптимальным.

Однако, в среднем время выполнения значительно меньше, так как сортировка группы завершается, как только она начинает состоять из одной строки. Если считать, что длина префикса, которой каждая строка уникально отличается от другой, ограничена некоторой небольшой константой (что недалеко от истины), то время работы составит O(n), где n – число строк.