Рацеев С.М. Программирование на языке Си
.pdfПриложение 5. СОРТИРОВКА С УСЛОВИЕМ
Часто возникают задачи, когда требуется отсортировать не весь массив, а только те его элементы, которые обладают некоторым свойством Q (например, четные элементы, положительные и т.д.), при этом элементы, не обладающие свойством Q, должны остаться на своих местах и сохранить прежний порядок.
В этом случае можно использовать алгоритмы сортировок из приложения 2 с некоторыми модификациями, не меняющими принцип самих алгоритмов. Общая схема является такой. Пусть a – некоторый массив размера n, в котором требуется упорядочить элементы со свойством Q. Обозначим через m количество таких элементов массива a (со свойством Q), при этом очевидно, что 0≤ m ≤ n. Введем дополнительный (динамический) целочисленный массив индексов ind размера m, в который запишем индексы всех элементов массива a, обладающих свойством Q.
Например, пусть массив a состоит из элементов 20, -10, 30, - 20, 10 и требуется упорядочить только положительные элементы (то есть свойство Q заключается в том, чтобы быть положительным числом и после упорядочивания по возрастанию только положительных чисел массив a должен принять такой вид : 10, -10, 20, -20, 30). Тогда массив индексов ind будет состоять из трех элементов
(m=3) и иметь такой вид: ind[0] = 0, ind[1] = 2, ind[2] = 4.
После того, как массив ind сформирован, можно использовать сортировки из приложения 2, в которых упорядочиваются ровно m элементов массива a с использованием такой индексации:
a[ind[0]], a[ind[1]],…,a[ind[m-1]].
1. Сортировка с условием на базе пузырьковой сортировки
#define N 10
/* подсчет количества элементов, обладающих свойством Q */ int Count(const double *a, const int n)
{
int i, count;
for(i = count = 0; i < n; i++)
331
if (Q(a[i])) count++;
return count;
}
/* сортировка пузырьком элементов со свойством Q */ int BubbleSort(double *a, const int n)
{
int i, j, r, flag, *ind, m; double buf;
/* вычисляем количество элементов со свойством Q: */ m = Count(a, n);
ind = (int *)malloc(m * sizeof(int)); /* заполняем массив ind: */
for(i = j = 0; i < n; i++) if (Q(a[i]))
ind[j++] = i;
/* сортируем элементы со свойством Q */ r = m;
do
{
flag = 0;
for(i = 1; i < r; i++)
if (a[ind[i]] < a[ind[i-1]])
{
buf = a[ind[i]]; a[ind[i]] = a[ind[i-1]]; a[ind[i-1]] = buf;
flag = 1;
}
r--; }while(flag); free(ind);
return m; /* возвращаем количество элементов со свойством Q */
}
int main()
332
{
double a[N];
…/* заполняем массив a */
/* сортируем элементы массива a со свойством Q: */ BubbleSort(a, N);
}
2. Сортировка с условием на базе быстрой сортировки
#define N 10
/* подсчет количества элементов, обладающих свойством Q */ int Count(const double *a, const int n)
{
int i, count;
for(i = count = 0; i < n; i++) if (Q(a[i]))
count++; return count;
}
/* быстрая сортировка массива a через массив ind */ void QuickSort (double *a, int *ind, int left, int right)
{
int i, j; double x, buf; i = left;
j = right;
x = a[ind[(left + right)/2]]; do
{
while (a[ind[i]] < x) i++;
while (x < a[ind[j]]) j--;
if (i <= j)
333
{
buf = a[ind[i]]; a[ind[i]] = a[ind[j]]; a[ind[j]] = buf; i++;
j--;
}
} while( i <= j);
if (left < j) QuickSort (a, ind, left, j);
if (right > i) QuickSort (a, ind, i, right);
}
int main()
{
double a[N];
int i, j, m, *ind = NULL;
…/* заполняем массив a */
/* вычисляем количество элементов со свойством Q: */ m = Count(a, N);
if (m > 0)
{
ind = (int *)malloc(m * sizeof(int)); for(i = j = 0; i < N; i++)
if (Q(a[i])) ind[j++] = i;
QuickSort(a, ind, 0, m - 1); free(ind);
}
return 0;
}
3.Сортировка с условием двоичных файлов
Впараграфе «Двоичные файлы» был рассмотрен пример с созданием и выводом двоичного файла, содержащего сведения о работниках некоторой организации: фамилия работника, год рождения, заработная плата. Предположим, что требуется отсортировать
334
не все записи в файле по какому-либо полю, а только те из них, которые обладают некоторым свойством Q, а остальные записи должны остаться на своем месте. Например, может потребоваться отсортировать по году рождения самых высокооплачиваемых работников. Отсортируем все записи в файле по году рождения, которые обладают свойством Q. Опять же, для ускорения алгоритма используем динамический массив, в который выгрузим весь файл. В качестве алгоритма сортировки используем пузырьковую сортировку, которая легко может быть трансформирована в любой другой алгоритм.
#include<stdio.h> struct WORKER
{
char name[20]; int year;
float earnings; };
/* размер файла в байтах */ long Size(char *fileName)
{
FILE *f; long n;
if ((f = fopen(fileName, "rb")) == NULL) return -1;
fseek(f, 0, SEEK_END); n = ftell(f);
fclose(f); return n;
}
/* количество записей в файле, обладающих свойством Q */ long Count(struct WORKER *a, long n)
{
long i, count = 0; for(i = 0; i < n; i++)
335
if(Q(a[i]))
count++; return count;
}
/* сортировка файла с условием на основе пузырьковой сортировки */
int SortFile(char *fileName)
{
FILE *f;
struct WORKER *a; /* динамический массив структур */ struct WORKER buf;
long n, m, i, j, r;
long *ind; /* динамический массив индексов */ int flag;
if ((f = fopen(fileName, "r+b")) == NULL) return 1;
/* вычисляем количество записей в файле */ n = Size(fileName)/sizeof(struct WORKER);
/* выделяем память для динамического массива a */
a = (struct WORKER *)malloc(n * sizeof(struct WORKER));
/* проверяем успешность выделения памяти и пытаемся выгрузить файл в массив */
if (a == NULL || fread(a, sizeof(struct WORKER), n, f) != n)
{
fclose(f); return 2;
}
/* вычисляем количество записей в файле, обладающих свойством Q */
m = Count(a, n);
/* выделяем память для динамического массива ind */ ind = (long *)malloc(m * sizeof(long));
/* проверяем успешность выделения памяти */ if (ind == NULL)
{
fclose(f);
336
free(a); return 3;
}
/* записываем индексы элементов массива a, обладающих свойством Q */
for(i = j = 0; i < n; i++) if(Q(a[i]))
ind[j++] = i;
/* сортируем элементы массив a, обладающие свойством Q, через массив индексов ind */
r = m; do
{
flag = 0;
for(i = 1; i < r; i++)
if (a[ind[i-1]].year > a[ind[i]].year)
{
buf = a[ind[i]]; a[ind[i]] = a[ind[i-1]]; a[ind[i-1]] = buf; flag = 1;
}
r--; }while(flag);
/* устанавливаем файловый указатель в начало файла */ rewind(f);
/* записываем отсортированный массив в файл */ fwrite(a, sizeof(struct WORKER), n, f);
free(a);
free(ind);
fclose(f); return 0;
}
4. Сортировка с условием линейного списка на базе пузырьковой сортировки
#include<stdio.h>
#include<stdlib.h>
337
typedef struct ELEMENT
{
int data;
struct ELEMENT *next; } ELEMENT;
/* подсчет количества элементов, обладающих свойством Q*/ int Count(ELEMENT *head)
{
int count = 0; ELEMENT *q;
for(q = head->next; q != NULL; q = q->next) if (Q(q->data))
count++; return count;
}
/* сортировка списка с условием на базе пузырькового метода */ void SortList(ELEMENT *head)
{
ELEMENT *q, **ind; long m, i, r;
int flag, buf;
m = Count(head);
ind = (ELEMENT **)malloc(m * sizeof(ELEMENT *)); for(i = 0, q = head->next; q != NULL; q = q->next)
if (Q(q->data)) ind[i++] = q;
r = m; do
{
flag = 0;
for(i = 1; i < r; i++)
if (ind[i-1]->data > ind[i]->data)
{
buf = ind[i]->data; ind[i]->data = ind[i-1]->data;
338
ind[i-1]->data = buf; flag = 1;
}
r--; }while(flag); free(ind);
}
int main( )
{
ELEMENT *head;
…/* создание списка */ SortList(head);
return 0;
}
5. Сортировка с условием линейного списка на базе быстрой сортировки
/* подсчет количества элементов, обладающих свойством Q*/ int Count(ELEMENT *head)
{
int count = 0; ELEMENT *q;
for(q = head->next; q != NULL; q = q->next) if (Q(q->data))
count++; return count;
}
/* быстрая сортировка списка через массив ind */ void QuickSort (ELEMENT **ind, int left, int right)
{
int i, j, x, buf; i = left;
j = right;
339
x = ind[(left + right)/2]->data; do
{
while (ind[i]->data < x) i++;
while (x < ind[j]->data) j--;
if (i <= j)
{
buf = ind[i]->data; ind[i]->data = ind[j]->data; ind[j]->data = buf;
i++; j--;
}
} while( i <= j);
if (left < j) QuickSort (ind, left, j);
if (right > i) QuickSort (ind, i, right);
}
int main()
{
ELEMENT *head, *q, **ind; int i, m;
…/* создание списка */ m = Count(head);
ind = (ELEMENT **)malloc(m * sizeof(ELEMENT *)); for(i = 0, q = head->next; q != NULL; q = q->next)
if (Q(q->data)) ind[i++] = q;
QuickSort(ind, 0, m - 1); free(ind);
return 0;
}
340