Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Рацеев С.М. Программирование на языке Си.pdf
Скачиваний:
369
Добавлен:
23.03.2016
Размер:
1.65 Mб
Скачать

return *(const double *)p1 - *(const double *)p2;

}

Таким образом, программа сортировки массива примет такой вид:

<stdlib.h> #define N 100

int compare(const void *p1, const void *p2)

{

return *(const double *)p1 - *(const double *)p2;

}

int main()

{

double a[N];

…/* заполняем массив a */

qsort(a, N, sizeof(*a), compare); /* сортируем массив a */ return 0;

}

Заметим, что встроенная функция быстрой сортировки qsort() работает в разы медленнее функции QuickSort(), представленной выше, поэтому в алгоритмах ниже, где будет использоваться модификация алгоритма быстрой сортировки, будем приводить в первую очередь функцию QuickSort().

6. Сортировка подсчетом

Сортировка подсчетом является специализированным алгоритмом, который работает невероятно быстро, если элементами данных являются целые числа со значениями, занимающими относительно узкий диапазон. Большая скорость сортировки подсчетом достигается за счет того, что при этом не применяются операции сравнения.

310

Пусть a – массив целых чисел, состоящий из n элементов. Обозначим через min и max соответственно минимальный и максимальный элементы массива a. Тогда значения элементов a[0], a[1], ..., a[п-1] массива a будут принадлежать множеству {min, min+1, ..., max}, мощность которого не превосходит значения m = max min + 1. То есть в массиве a имеется не более m различных элементов.

Сортировку подсчетом начнем с создания массива count размерности m, в котором элемент count[i] будет содержать количество вхождений элемента min+i в массиве a, где i = 0, 1, …, m-1. То есть count[0] будет содержать количество элементов массива a, равных значению min, элемент count[1] – количество элементов массива a, равных значению min+1 и т.д.

После того как массив count будет заполнен, начинаем перезаписывать элементы в массиве a. Сначала запишем count[0] элементов со значением min, затем count[1] элементов со значением min+1 и т.д. После чего будем иметь отсортированный массив a:

Сложность алгоритма W(n,m) = O(n+m).

int CountSort(int *a, const int n)

{

int *count, m, i, j, k, min, max; count = NULL;

/* первым делом ищем минимальное и максимальное значения массива a

*/

min = max = a[0]; for (i = 0; i < n; i++) if (a[i] < min)

min = a[i];

else if (a[i] > max) max = a[i];

311

m = max - min + 1; /* размерность массива count */ /* создаем динамический массив count, все элементы

которого изначально равны нулю

*/

count = (int *)calloc(m, sizeof(int)); if (count == NULL)

return 0;

/* подсчитываем количество вхождений каждого элемента в массиве a

*/

for (i = 0; i < n; i++) count[a[i] - min]++;

/* перезаписываем элементы в массиве a */ k = 0;

for (i = 0; i < m; i++)

for (j = 0; j < count[i]; j++) a[k++] = i + min;

free(count); return 1;

}

Предположим, что требуется отсортировать массив, состоящий, в общем случае, из структур, по целочисленному ключевому полю. Например, рассмотрим n-элементный массив INFO a[n], каждый элемент которого является структурой

typedef struct {

int key; /* ключевое поле */ char name[50]; /* строка */

} INFO;

Задачей является отсортировать массив a по ключевому полю key, если заранее известно, что множество всех значений, которые могут храниться в данном поле, имеет "относительно" узкий диапазон.

312

Так как наш массив содержит не только целые элементы, то в явном виде сортировку подсчетом мы применить не можем. Немного модернизируем алгоритм сортировки подсчетом. Пусть min и max – соответственно минимальный и максимальный элементы ключевого поля key массива a. Как и ранее, сначала создадим динамический массив count размера m = max min + 1 и заполним его таким образом, чтобы элемент count[i] был равен количеству ключевых элементов массива a, равных значению min+i, i = 0, 1, …, m- 1.

После того, как заполнение массива count будет завершено, преобразуем элементы данного массива следующим образом:

count[i] = count[i - 1] + count[i], i = 1,2,…,m-1.

Теперь значение count[i] означает количество элементов массива a, ключевые поля которых имеют значения меньше или равные числу min+i, i = 0, 1, …, m-1.

typedef struct { int key;

char name[50]; } INFO;

/* поиск минимального и максимального значений */ void Min_Max(INFO *a, int n, int *min, int *max)

{

int i;

*min = *max = a[0].key; for (i = 1; i < n; i++)

if (a[i].key < *min) *min = a[i].key;

else if (a[i].key > *max) *max = a[i].key;

}

/* Сортировка подсчетом. Результат записывается в массив b. */ int CountSort(INFO *a, INFO *b, int n)

{

int *count, min, max, m, i;

313

Min_Max(a, n, &min, &max); m = max - min + 1;

count = (int *)calloc(m, sizeof(int)); if (count == NULL)

return 0;

for(i = 0; i < n; i++) count[a[i].key - min]++;

for(i = 1; i < m; i++) count[i] += count[i-1];

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

{

b[count[a[i].key - min] - 1] = a[i]; count[a[i].key - min]--;

}

free(count); return 1;

}

314