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

return a[*(const int *)p1] - a[*(const int *)p2];

}

int main()

{

int i, ind[N];

…/* заполнение массива a */ for(i = 0; i < N; i++)

ind[i] = i;

qsort(ind, N, sizeof(*ind), compare); return 0;

}

4. Сортировка двумерных массивов

Пусть a[M][N] – некоторая матрица. На множестве строк данной матрицы (a[0], a[1],…,a[M-1]) определим числовую функцию F. Например, функция F может возвращать значение первого элемента строки (F(a[i]) = a[i][0]), сумму элементов строки (F(a[i]) = a[i][0] + a[i][1] + … + a[i][N-1]) и т.д. Задача состоит в том, чтобы упорядочить строки матрицы таким образом, чтобы последовательность F(b[0]), F(b[1]),…, F(b[M-1]) была неубывающей, где символом b обозначена новая матрица, полученная из матрицы a путем перестановки строк.

Для решения данной задачи имеется несколько подходов. Вопервых, можно действительно переставлять строки матрицы a, но для матриц с большим значением числа N (число столбцов) это неэффективно. Во-вторых, можно завести массив индексов int ind[M] ={0, 1,…, M-1} и переставлять в нем элементы таким образом, что-

бы последовательность F(a[ind[0]]), F(a[ind[1]]),…, F(a[ind[M-1]])

удовлетворяла условию задачи. При этом матрица a останется без изменений, а обращение к “новой” матрице b будет происходить следующим образом:

a[ind[i]][j], 0 ≤ i < M, 0 ≤ j < N.

Такой подход для одномерных массивов мы уже рассматривали выше. Поэтому (для разнообразия) остановимся на третьем подхо-

319

де (сопряженным со вторым), который заключается в рассмотрении дополнительного массива указателей int *pa[M], где pa[i] содержит адрес i-ой строки матрицы a, i = 0,…,M-1.

Изначально массив pa инициализируется следующим обра-

зом:

for(i = 0; i < M; i++) pa[i] = a[i];

Затем с помощью алгоритма быстрой сортировки происходит преобразование массива указателей pa так, чтобы последовательность F(pa[0]), F(pa[1]),…, F(pa[M-1]) удовлетворяла начальному условию. В алгоритме ниже в качестве функции F выступает функция, которая возвращает первый элемент строки. Поэтому вместо записи F(pa[i]) будем использовать запись * pa[i].

#include<stdio.h>

#define M 5 /* Число строк матрицы */ #define N 10 /* Число столбцов матрицы */

/* вывод матрицы на экран через массив индексов pa */ void Print(int *pa[], int m, int n)

{

int i, j;

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

{

for (j = 0; j < n; j++) printf("%5d", pa[i][j]);

printf("\n");

}

}

/* сортировка массива pa по первым элементам массива a: */ void QuickSort (int *pa[], int left, int right)

{

int i, j, *buf; int x;

i = left;

320

j = right;

x = *pa[(left + right)/2]; do

{

while (*pa[i] < x) i++;

while (x < *pa[j]) j--;

if (i <= j)

{

buf = pa[i]; pa[i] = pa[j]; pa[j] = buf; i++;

j--;

}

} while( i <= j);

if (left < j) QuickSort (pa, left, j); if (right > i) QuickSort (pa, i, right);

}

int main()

{

int i, a[M][N], /* исходная матрица */

*pa[M]; /* массив указателей */ …/* инициализация матрицы a */

/* инициализация массива индексов pa: */ for(i = 0; i < M; i++)

pa[i] = a[i];

/* вывод исходной матрицы a: */ Print(pa, M, N);

/* сортировка элементов массива указателей pa */ QuickSort(pa, 0, M-1);

/* вывод упорядоченной матрицы по первым элементам строк: */

Print(pa, M, N); return 0;

}

321

5. Сортировка строк

Рассмотрим алгоритмы сортировки строк. При этом задача состоит в том, чтобы выделить слова из введенной строки и расположить их в лексикографическом порядке на основе ASCII кодов символов. В качестве основы возьмем очень быстрые алгоритмы выделения всех слов из строки, приведенные в параграфе 8.7, а в качестве сортировки используем алгоритм быстрой сортировки (QuickSort), где сравнение слов будет происходить с помощью функции strcmp из библиотеки <string.h>.

Случай 1. Если слова в строке разделены символами ‘\0’ (см. случай 1 параграфа 8.7), то можно определить массив указателей, содержащий адреса выделенных слов. В этом случае сортируются ссылки на данные слова.

#include <stdio.h> #include <string.h>

#define DELIMITERS " .,:;?!\n\t" /* символы-разделители */ #define SIZE 100 /* максимальный размер массива указаателей */

#define N 1024 /* размер строки */

/* сортировка строк на основе быстрой сортировки */ void QuickSortWords (char *a[], int left, int right)

{

int i, j;

char *x, *buf; i = left;

j = right;

x = a[(left + right)/2]; do

{

while (strcmp(x, a[i]) > 0) i++;

while (strcmp(x, a[j]) < 0) j--;

if (i <= j)

{

322

buf = a[i]; a[i] = a[j]; a[j] = buf; i++; j--;

}

} while( i <= j);

if (left < j) QuickSortWords (a, left, j); if (right > i) QuickSortWords (a, i, right);

}

int main( )

{

char sentence[N]; /* строка-предложение */ char *pstr[SIZE]; /* маасив указателей */ int i, j, flag[256] = {0}, n;

fgets(sentence, N, stdin);

for (i = 0; DELIMITERS[i]; i++) flag[DELIMITERS[i]] = 1;

for (i = 0; sentence[i] && flag[sentence[i]]; i++) sentence[i] = '\0';

n = 0;

/* выделяем слова в строке sentence и адреса слов записываем в массив pstr:

*/

while (sentence[i])

{

pstr[n++] = &sentence[i];

while (sentence[i] && !flag[sentence[i]]) i++;

j = i;

while (sentence[i] && flag[sentence[i]]) i++;

sentence[j] = '\0';

}

/* сортируем слова в строке через массив ссылок pstr: */

QuickSortWords(pstr, 0, n - 1);

/* выводим слова в лексикографическом порядке */ for(i = 0; i < n; i++)

puts(pstr[i]);

323

return 0;

}

Случай 2. Если слова выделяются из строки-предложения путем копирования слов в динамические строки (см. случай 2 параграфа 8.7), то адреса этих динамических строк будем сохранять в массиве ссылок pstr, а потом сортировать с помощью функции QuickSortWords (из предыдущего случая) не сами строки, а их адреса.

#include <stdio.h> #include <stdlib.h> #include <string.h>

#define DELIMITERS " .,:;?!\n\t" /* символы-разделители */ #define SIZE 100 /* максимальный размер массива указаателей */

#define N 1024 /* размер строки */

int main( )

 

{

 

char sentence[N];

/* исходная строка */

char *pstr[SIZE];

int n, i, j, flag[256] = {0};

for (i = 0; DELIMITERS[i]; i++) flag[DELIMITERS[i]] = 1;

fgets(sentence, N, stdin);

for (i = 0; sentence[i] && flag[sentence[i]]; i++)

;

n = 0;

while (sentence[i])

{

j = i;

while (sentence[i] && !flag[sentence[i]]) i++;

/* выделяем память для очередного слова: */ pstr[n] = (char *)malloc((i - j + 1) * sizeof(char)); /* копируем очередное слово: */ strncpy(pstr[n], &sentence[j], i - j);

324

pstr[n][i - j] = '\0'; n++;

while (sentence[i] && flag[sentence[i]]) i++;

}

/* функция QuickSortWords прописана в случае 1 */

QuickSortWords(pstr, 0, n - 1);

/* выводим слова в лексикографическом порядке */ for(i = 0; i < n; i++)

puts(pstr[i]); return 0;

}

325