Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ukhanov_-_Struktury_i_algoritmy_obrabotki_danny...doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
1.81 Mб
Скачать

Двоичная поразрядная сортировка

Ключ рассматривается как последовательность битов. Устанавливаем указатели на начало и конец таблицы. Двигаемся слева направо от начала в поисках ключа со старшим битом 1. Двигаемся справа налево от конца в поисках ключа со старшим битом 0. Меняем местами эти ключи. Продолжаем встречное движение по данному принципу до встречи. В результате таблица расщепляется на две части. В левой части все ключи имеют старший бит равный 0, в правой - 1. Таким образом, Aj<Aj+i. Затем эта процедура выполняется для второго бита и полученных подпоследовательностей и т.д.

Пример:

\ S

010 101 111 001 011 100

\ ,/

010 101 111 001 011 100

010 011 001 111 101 100

Получили разделение исходного множества ключей на два. В первом множестве собраны ключи со старшим битом, равным 0, во втором - 1. Далее нужно повторить процесс расщепления для каждого множества по второму биту.

Число расщеплений будет равно log2N. Каждый раз будем просматривать N элементов. Таким образом, время сортировки пропорционально N-log2N .

Функция расщепления.

11 Х- указатель на начало таблицы

// 1, г - границы расщепляемого участка // keylen - длина ключей

// nombit - номер бита, по которому происходит расщепление // возвращает индекс самого правого ключа с битом nombit равным нулю int BitPart (char *t, int keylen, int 1, int r, int nombit) { char *lrec, *rrec; // указатели на левую и правую записи соответственно int lb, rb; // биты левой и правой записи с номером nombit

while (К г) { lrec = t + Pkeylen; // смещаемся в t на Pkeylen байт

rrec = t + r*keylen; // смещаемся в t на r*keylen байт

lb = GiveBit (lrec, nombit); rb = GiveBit (rrec, nombit); if (!lb && !rb) l ++; if (!lb && rb) { 1++; r ; } if (lb && !rb) {

l ++; r --;

Change (lrec,rrec); } if (lb && rb) r --;

}

if (lb && rb) return r-1;

else return r; }

Функция сортировки.

// выполняет сортировку участка от l до r таблицы t с длинной ключа // keylen по биту, начиная с nombit void BSort (char *t, int l, int r, int keylen, int nombit) {

int k;

if (!(l < r)) return; // условие завершения прохода для данного nombit

if (nombit / 8 > keylen) return; // условие завершения по количеству nombit

k = BitPart (t, keylen, l, r, nombit);

BSort (t, l, k, keylen, nombit+1);

BSort (t, k+1, r, keylen, nombit+1); }

Обращение к функции BSort. // n – число ключей void BitSort (char *t, int keylen, int n) {

BSort (t, 0, n-1, keylen, 0); }

static unsigned char bits [ ] = {128, 64, 32, 16, 8, 4, 2, 1}; // record – указатель на запись, из которой выделяем один бит int GiveBit (char *record, int nombit) {

int NomByte;

int BitInByte;

NomByte = nombit / 8;

BitInByte = nombit % 8;

return (record [NomByte] & bits [BitInByte]) >> BitInByte; }

Цифровая поразрядная сортировка по принципу «сначала по младшей цифре»

Возьмем в нулевое множество все ключи с младшим битом 0, в множество с индексом 1, ключи с младшим битом 1 и т.д. Затем выполним подсчет ключей в множествах. Таким образом, получим С – массив счетчиков, в котором С [i] – это число ключей со старшей цифрой i. После подсчета ясно, что все ключи, имеющие младшую цифру 0, должны помещаться, начиная с нулевой позиции, ключи с цифрой 1 – начиная с позиции С [0], с цифрой 2 – с позиции С [0] + C [1] и т.д. Разместим ключи в соответствии с описанным правилом. Таким образом, добились разделения Ai<Ai+1. Далее повторим процесс по следующей цифре и т.д.

Рассмотрим на примере ключей в троичной системе счисления.

Дано множество ключей:

102 211 012 020 201 111 121 022

Для троичной системы счисления размерность массива счетчиков будет три. Тогда С0 будет содержать 1 (имеется только один элемент, с 0 в старшем бите – 020), С1 будет содержать 4 (211, 201, 111, 121), и, наконец, С2 содержит 3 (102, 012, 022). Расставим теперь ключи в соответствии с номерами счетчиков 0, 1, 2. Получим

020 211 201 111 121 102 012 022.

Снова повторяем процесс расщепления по следующей цифре.

C0 = 2 (201, 102); С1 = 3 (211, 111, 012); С2 = 3 (020, 121, 022). Расставляем

201 102 211 111 012 020 121 022. Последнее расщепление для последней цифры. С0 = 3 (012, 020, 022); С1 = 3 (102, 111, 121); С2 = 2 (201, 211).

Расставляем в соответствии с номерами 012 020 022 102 111 121 201 211.

Получена окончательная сортированная последовательность ключей.

Можно брать любую систему счисления. Удобно, если цифра – бит. Поэтому обычно используются либо 16-ричная (один бит – цифра), либо 256-ричная (один байт – цифра). Функция, выполняющая сортировку. #define NDIG 256

void DigitalSort(char *t, int N, int KeyLen){ // t - сортируемый массив // N - его длина

// KeyLen - число цифр в сортируемом ключе int *Count; // массив счетчиков

int Dig; // текущая цифра в ключе

int i,j; // переменные циклов

char *b; // буферная область

int *Pos; // позиции расстановки Count=(int *)calloc(NDIG, sizeof(int)); Pos=(int *)calloc(NDIG, sizeof(int)); b=calloc(N,KeyLen); // цикл по всем цифрам в ключе for(i=0; i<KeyLen; i++){ memset(Count,0, NDIG*sizeof(int)); // обнуляем массив счетчиков

for(j=0; j<N; j++){ // для каждого ключа

Dig=*(t+j*KeyLen+KeyLen-i-1); // получаем i-ю цифру j-го ключа Count[Dig]++; // считаем количество ключей с такой i-й цифрой

}

// расчет позиций, откуда будут начинаться записи с соответствующими цифрами Pos[0]=0; for(j=1; j<NDIG; j++){

Pos[j]=Pos[j-1]+Count[j-1]; }

// расстановка, в соответствии с номером позиции for(j=0; j<N; j++){ Dig=*(t+j*KeyLen+KeyLen-i-1); memcpy(b+KeyLen*Pos[Dig]++, t+j*KeyLen, KeyLen); }

memcpy(t,b,KeyLen*N); // копирование буфера обратно в t и по следующей цифре }

free(b); free(Count); free(Pos); }

Сортировки слиянием Слияние означает объединение двух или более упорядоченных таблиц в одну упорядоченную.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]