Здравствуйте прошла курсы на тему Алгоритмы С++. Но не пришел сертификат и не доступен.Где и как можно его скаачат? |
Элементарные методы сортировки
Сортировка других типов данных
Большинство алгоритмов сортировки вполне можно рассматривать как упорядочение массивов чисел в числовом порядке или упорядочение символов в алфавитном порядке. Действительно, эти алгоритмы обычно не зависят от типа сортируемых элементов, и поэтому их нетрудно распространить на более общие случаи. Ранее мы подробно рассмотрели вопросы разбиения программ на отдельные независимые модули, что позволяет реализовать нужные типы данных, а также абстрактные типы данных (см. "Элементарные структуры данных" и "Абстрактные типы данных" ). В данном разделе обсуждаются способы применения этих понятий для создания реализаций, интерфейсов и клиентских программ для алгоритмов сортировки. А именно, будут рассматриваться интерфейсы для:
- элементов или обобщенных сортируемых объектов
- массивов элементов.
Тип данных " элемент " позволяет использовать программы сортировки для любых типов данных, для которых определены необходимые базовые операции. Такой подход позволяет эффективно создавать реализации как для простых, так и для абстрактных типов данных. Интерфейс " массив " менее критичен для нашей задачи; мы используем его в качестве примера работы с многомодульной программой, которая имеет дело с несколькими типами данных. Здесь будет рассмотрена только одна (примитивная) реализация интерфейса массива.
Программа 6.6 является клиентской программой с теми же обобщенными возможностями, что и функция main из программы 6.1, но с дополнительным кодом для работы с массивами и элементами, инкапсулированными в отдельных модулях. Это позволяет, в частности, тестировать различные программы сортировки на различных типах данных путем замены одних модулей на другие, не внося при этом никаких изменений в клиентскую программу. Программа 6.6 обращается также к интерфейсу, где описаны операции exch и compexch, используемые в реализациях алгоритмов сортировки. Можно было бы включить их в интерфейс Item.h, однако реализации в программе 6.1 имеют легко понятную семантику при определенных операциях = и <, поэтому проще содержать их в одном модуле, которым могут пользоваться все реализации сортировки для всех типов элементов. Чтобы завершить реализацию, необходимо вначале точно определить интерфейсы с типами массива и элемента.
Программа 6.6. Драйвер сортировки массивов
Данный драйвер для основных алгоритмов сортировки массивов использует три явных интерфейса: (1) для типа данных, который инкапсулирует операции для обобщенных элементов; (2) несколько более высокий уровень для функций exch и compexch, используемых в реализациях; и (3) для функций, которые инициализируют и выводят (а также сортируют!) массивы. Такое разбиение драйвера на модули позволяет без каких-либо изменений применять каждую реализацию сортировки для упорядочения различных типов данных, совместно использовать реализации операций обмена и сравнения-обмена, а также компилировать функции для массивов отдельно (возможно, для их использования в других драйверах).
#include <stdlib.h> #include "Item.h" #include "exch.h" #include "Array.h" main(int argc, char *argv[]) { int N = atoi(argv[1]), sw = atoi(argv[2]); Item *a = new Item[N]; if (sw) rand(a, N); else scan(a, N); sort(a, 0, N-1); show(a, 0, N-1); }
Интерфейс программы 6.7 определяет примеры высокоуровневых операций, которые могут понадобиться при работе с массивами. Необходима возможность инициализировать массив либо случайными ключами, либо ключами из стандартного ввода, необходима возможность сортировать элементы (естественно!), и необходима возможность вывода содержимого массива. Это лишь несколько примеров; в конкретном приложении может понадобиться определить и другие операции (примером подобного интерфейса может служить класс Vector из библиотеки стандартных шаблонов). Программа 6.7 позволяет подставлять различные реализации разных операций без внесения изменений в клиентскую программу, которая использует этот интерфейс — в данном случае, в функцию main программы 6.6. Реализациями функции sort могут служить различные рассматриваемые нами реализации сортировок. В программе 6.8 приведены простые реализации других функций. Модульная организация позволяет подставлять другие реализации, нужные в конкретных приложениях. Например, может понадобиться реализация функции show, которая выводит только часть массива при тестировании работы на очень больших массивах.
Подобным же образом, чтобы иметь возможность работать с конкретными типами элементов и ключей, мы определим их типы и объявим все необходимые операции над ними в отдельном интерфейсе, а затем приведем реализации этих операций, определенных в этом интерфейсе. Например, пусть имеется некоторое бухгалтерское приложение, где целочисленный ключ соответствует номеру счета клиента, а число с плавающей точкой — балансу счета этого клиента. Программа 6.9 представляет собой пример интерфейса, который определяет тип данных для подобных приложений. Код этого интерфейса объявляет операцию <, которая нужна для сравнения ключей, а также функции, которые генерируют случайные ключи, считывают ключи и выводят значения ключей. В программе 6.10 содержатся реализации функций для данного простого примера. Разумеется, эти реализации можно приспособить под конкретные приложения.
Программа 6.7. Интерфейс для типа данных " массив "
Данный интерфейс Array.h определяет высокоуровневые функции для массивов абстрактных элементов: инициализация случайными значениями, инициализация значениями из стандартного ввода, вывод содержимого и сортировку содержимого.
template <class Item> void rand(Item a[], int N); template <class Item> void scan(Item a[], int &N); template <class Item> void show(Item a[], int l, int r); template <class Item> void sort(Item a[], int l, int r);
Программа 6.8. Реализация типа данных " массив "
Данный код представляет собой реализацию функций, определенных в программе 6.7. Здесь используются типы данных и базовые функции для работы с ними, которые определены в отдельном интерфейсе (см. программу 6.9).
#include <iostream.h> #include <stdlib.h> #include "Array.h" template <class Item> void rand(Item a[], int N) { for (int i = 0; i < N; i++) rand(a[i]); } template <class Item> void scan(Item a[], int &N) { for (int i = 0; i < N; i++) if (!scan(a[i])) break; N = i; } template <class Item> void show(Item a[], int l, int r) { for (int i = l; i <=r; i++) show(a[i]); cout << endl; }
Программа 6.9. Пример интерфейса для типа данных " элемент "
Файл Item.h, включенный в программу 6.6, дает определение типа данных для сортируемых элементов. В этом примере элементами являются небольшие записи, состоящие из целочисленных ключей и информации в виде числа с плавающей точкой. Мы объявляем, что перегруженная операция < будет реализована отдельно, равно как и три функции: scan (считывает Item в свой аргумент), rand (сохраняет случайный Item в своем аргументе) и show (выводит Item).
typedef struct record { int key; float info; } Item; int operator<(const Item&, const Item&); int scan(Item&); void rand(Item&); void show(const Item&);
Программа 6.10. Пример реализации типа данных " элемент "
Этот код является реализацией перегруженной операции < и функций scan, rand и show, которые объявлены в программе 6.9. Поскольку записи представляют собой небольшие структуры, в функции exch можно использовать встроенный оператор присваивания, не беспокоясь о затратах на копирование элементов.
#include <iostream.h> #include <stdlib.h> #include "Item.h" int operator<(const Item& A, const Item& B) { return A.key < B.key; } int scan(Item& x) { return (cin >> x.key >> x.info) != 0; } void rand(Item& x) { x.key = 100 0*(1.0*rand()/RAND MAX); x.info = 1.0*rand()/RAND MAX; } void show (const Item& x) { cout << x.key << " " << x.info << endl; }
Например, тип Item может быть абстрактным типом данных, определенным в виде класса С++, а ключи могут быть функциями-членами класса, а не членами структуры. Такие АТД рассматриваются в "Таблицы символов и деревья бинарного поиска" .
Программы 6.6—6.10 вместе с любыми подпрограммами сортировки (без изменений) из разделов 6.2—6.6, выполняют проверку сортировки на небольших записях. Написав подобные интерфейсы и реализации для других типов данных, мы сможем применять наши реализации для сортировки различных видов данных — таких как комплексные числа (см. упражнение 6.50), векторы (см. упражнение 6.55) или полиномы (см. упражнение 6.56) — без каких-либо изменений в кодах программ сортировки. Для более сложных типов элементов придется написать более сложные интерфейсы и реализации, однако эта задача полностью отделена от вопросов построения алгоритмов сортировки, которые нас здесь интересуют. Одни и те же механизмы можно задействовать для большинства методов сортировки, которые рассмотрены в данной главе, а также будут изучаться в лекциях 7—9 . В разделе 6.10 мы подробно проанализируем одно существенное исключение — оно дает начало целому семейству важных алгоритмов сортировки, которые должны иметь совсем другое оформление; о них речь пойдет в "Поразрядная сортировка" .
Рассмотренный в этом разделе подход находится где-то посередине между программой 6.1 и готовым к практическому применению полностью абстрактным набором реализаций вместе с проверкой ошибок, управлением памятью и даже более универсальными возможностями. Подобные вопросы оформления приобретают все большую актуальность в некоторых современных областях программирования и приложений. Ряд вопросов придется оставить без ответа — ведь наша основная цель заключается в том, чтобы, рассматривая сравнительно простые механизмы, продемонстрировать широкую применимость наших реализаций сортировок.
Упражнения
6.49. Напишите версии программ 6.9 и 6.10, в которых вместо функций scan и show используются перегруженные операции << и >>, а также измените программу 6.8, чтобы учесть изменения в интерфейсе.
6.50. Напишите интерфейс и реализацию для обобщенного типа данных элемента, который позволит сортировать комплексные числа х + iy, используя в качестве ключа модуль . Совет: эффективность можно повысить, игнорируя квадратный корень.
6.51. Напишите интерфейс, который определяет абстрактный тип данных первого класса для обобщенных элементов (см. раздел 4.8 "Абстрактные типы данных" ), и реализацию, в которой, как и в предыдущем упражнении, элементами являются комплексные числа. Протестируйте полученную программу с помощью программ 6.3 и 6.6.
6.52. Добавьте в тип данных массива в программах 6.8 и 6.7 функцию check, которая проверяет, упорядочен ли массив.
6.53. Добавьте в тип данных массива в программах 6.8 и 6.7 функцию testinit, которая генерирует тестовые данные с распределениями, похожими на приведенные на рис. 6.13. У этой функции должен быть целочисленный аргумент, через который клиентская программа сможет задать нужное распределение.
6.54. Измените программы 6.7 и 6.8, чтобы реализовать абстрактный тип данных. (Ваша реализация должна размещать массив в памяти и сопровождать его так, как в реализациях стеков и очередей из "Элементарные структуры данных" )
6.55. Напишите интерфейс и реализацию для обобщенного типа данных элемента, чтобы известные методы сортировки могли упорядочивать многомерные векторы из d целых чисел по первой компоненте, векторы с равными первыми компонентами по второй компоненте, векторы с равными первыми и вторыми компонентами по третьей компоненте и т.д.
6.56. Напишите интерфейс и реализацию для обобщенного типа данных элемента, чтобы известные методы сортировки могли упорядочивать полиномы (см. раздел 4.9 "Абстрактные типы данных" ). Правило упорядочивания определите самостоятельно.