Чтение онлайн

на главную - закладки

Жанры

Linux программирование в примерах
Шрифт:

Все процедуры разделяют общий лейтмотив; данные управляются через указатели

void*
, а сортировку осуществляют предоставленные пользователем функции. Обратите также внимание, что эти API применяются к данным в памяти. Структуры сортировки и поиска в файлах значительно более сложны и выходят за рамки вводного руководства, подобного данному. (Однако, команда
sort
хорошо работает для текстовых файлов; см. справочную страницу для sort(1). Сортировка двоичных файлов требует написания специальной программы.)

Поскольку ни один алгоритм не работает

одинаково хорошо для всех приложений, имеются несколько различных наборов библиотечных процедур для сопровождения искомых коллекций данных. Данная глава рассматривает лишь один простой интерфейс для поиска. Другой, более развитый интерфейс описан в разделе 14.4 «Расширенный поиск с использованием двоичных деревьев». Более того, мы намеренно не объясняем лежащие в основе алгоритмы, поскольку данная книга об API, а не об алгоритмах и структурах данных. Важно понять, что API можно рассматривать как «черные ящики», выполняющие определенную работу без необходимости понимания подробностей их работы.

6.2.1. Сортировка:

qsort

Сортировка выполняется с помощью

qsort
:

#include <stdlib.h> /* ISO С */

void qsort(void *base, size_t nmemb, size_t size,

 int (*compare)(const void*, const void*));

Название

qsort
происходит от алгоритма машинного поиска Хоара Quicksort (C.A.R. Hoare's Quicksort algorithm), который использовался в первоначальной реализации Unix. (Ничто в стандарте POSIX не требует использования этого алгоритма для
qsort
. Реализация GLIBC использует высоко оптимизированную комбинацию Quicksort и Insertion Sort.)

qsort
сортирует массивы произвольных объектов. Она работает, перетасовывая непрозрачные участки памяти из одного места массива в другой и полагаясь на то, что вы, программист, предоставите функцию сравнения, которая позволяет определить относительное расположение одного элемента массива относительно другого. Аргументы следующие:

void *base

Адрес начала массива.

size_t nmemb

Общее число элементов в массиве.

size_t size

Размер каждого элемента массива. Лучший способ получения этого значения — оператор С

sizeof
.

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

Возможно устрашающее объявление указателя функции. Оно говорит, что «

compare
указывает на функцию, которая принимает два параметра '
const void*
' и возвращает
int
».

Большая часть работы заключается в написании соответствующей функции сравнения. Возвращаемое значение должно имитировать соответствующее значение

strcmp
: меньше нуля, если первое значение «меньше» второго, ноль, если они равны, и больше нуля, если первое значение «больше» второго. Именно функция сравнения определяет значения «больше» и «меньше» для всего, что вы сравниваете. Например, для сравнения двух значений
double
мы могли бы использовать эту функцию:

int dcomp(const void *d1p, const void *d2p) {

 const double *d1, *d2;

 d1 = (const double*)d1p; /*
Привести указатели к нужному типу */

 d2 = (const double*)d2p;

 if (*d1 < *d2) /* Сравнить и вернуть нужное значение */

return -1;

 else if (*d1 > *d2)

return 1;

 else if (*d1 == *d2)

return 0;

 else

return -1; /* NaN сортируется до действительных чисел */

}

Это показывает общий стереотип для функций сравнения: привести тип аргументов от

void*
к указателям на сравниваемый тип, а затем вернуть результат сравнения.

Для чисел с плавающей точкой простое вычитание, подобное '

return *d1 - *d2
', не работает, особенно если одно значение очень маленькое или одно или оба значения являются специальными значениями «не число» или «бесконечность». Поэтому нам приходится осуществлять сравнение вручную, принимая во внимание нечисловое значение (которое даже не равно самому себе!)

6.2.1.1. Пример: сортировка сотрудников

Для более сложных структур требуются более сложные функции. Например, рассмотрите следующую (довольно тривиальную)

struct employee
:

struct employee {

char lastname[30];

char firstname[30];

long emp_id;

time_t start_date;

};

Мы могли бы написать функцию для сортировки сотрудников по фамилии, имени и идентификационному номеру:

int emp_name_id_compare(const void *e1p, const void *e2p) {

 const struct employee *e1, *e2;

 int last, first;

 e1 = (const struct employee*)e1p; /* Преобразовать указатели */

 e2 = (const struct employee*)e2p;

 if ((last = strcmp(e1->lastname, e2->lastname)) != 0)

/* Сравнить фамилии */

return last; /* Фамилии различаются */

 /* фамилии совпадают, сравнить имена */

 if ((first = strcmp(e1->firstname, e2->firstname)) != 0)

/* Сравнить имена */

return first; /* Имена различаются */

 /* имена совпадают, сравнить номера ID */

 if (e1->emp_id < e2->emp_id) /* Сравнить ID сотрудника */

return -1;

 else if (e1->emp_id == e2->emp_id)

Поделиться:
Популярные книги

Свадьба по приказу, или Моя непокорная княжна

Чернованова Валерия Михайловна
Любовные романы:
любовно-фантастические романы
5.57
рейтинг книги
Свадьба по приказу, или Моя непокорная княжна

Сборник коротких эротических рассказов

Коллектив авторов
Любовные романы:
эро литература
love action
7.25
рейтинг книги
Сборник коротких эротических рассказов

Отец моего жениха

Салах Алайна
Любовные романы:
современные любовные романы
7.79
рейтинг книги
Отец моего жениха

Вадбольский

Никитин Юрий Александрович
1. Вадбольский
Фантастика:
попаданцы
5.00
рейтинг книги
Вадбольский

Бастард Императора. Том 7

Орлов Андрей Юрьевич
7. Бастард Императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 7

Повелитель механического легиона. Том VIII

Лисицин Евгений
8. Повелитель механического легиона
Фантастика:
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Повелитель механического легиона. Том VIII

В зоне особого внимания

Иванов Дмитрий
12. Девяностые
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
В зоне особого внимания

Таня Гроттер и магический контрабас

Емец Дмитрий Александрович
1. Таня Гроттер
Фантастика:
фэнтези
8.52
рейтинг книги
Таня Гроттер и магический контрабас

Бастард Императора. Том 2

Орлов Андрей Юрьевич
2. Бастард Императора
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бастард Императора. Том 2

Кодекс Крови. Книга ХI

Борзых М.
11. РОС: Кодекс Крови
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Кодекс Крови. Книга ХI

Третий

INDIGO
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий

Возвышение Меркурия. Книга 16

Кронос Александр
16. Меркурий
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 16

Идеальный мир для Лекаря 9

Сапфир Олег
9. Лекарь
Фантастика:
боевая фантастика
юмористическое фэнтези
6.00
рейтинг книги
Идеальный мир для Лекаря 9

Потусторонний. Книга 1

Погуляй Юрий Александрович
1. Господин Артемьев
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Потусторонний. Книга 1