Опубликован: 05.01.2015 | Доступ: свободный | Студентов: 2177 / 0 | Длительность: 63:16:00
Лекция 6:

Элементарные методы сортировки

Сортировка других типов данных

Большинство алгоритмов сортировки вполне можно рассматривать как упорядочение массивов чисел в числовом порядке или упорядочение символов в алфавитном порядке. Действительно, эти алгоритмы обычно не зависят от типа сортируемых элементов, и поэтому их нетрудно распространить на более общие случаи. Ранее мы подробно рассмотрели вопросы разбиения программ на отдельные независимые модули, что позволяет реализовать нужные типы данных, а также абстрактные типы данных (см. "Элементарные структуры данных" и "Абстрактные типы данных" ). В данном разделе обсуждаются способы применения этих понятий для создания реализаций, интерфейсов и клиентских программ для алгоритмов сортировки. А именно, будут рассматриваться интерфейсы для:

  • элементов или обобщенных сортируемых объектов
  • массивов элементов.

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

Программа 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, используя в качестве ключа модуль $\sqrt{x^{2}+y^{2}}$. Совет: эффективность можно повысить, игнорируя квадратный корень.

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 "Абстрактные типы данных" ). Правило упорядочивания определите самостоятельно.

Бактыгуль Асаинова
Бактыгуль Асаинова

Здравствуйте прошла курсы на тему Алгоритмы С++. Но не пришел сертификат и не доступен.Где и как можно его скаачат?

Александра Боброва
Александра Боброва

Я прошла все лекции на 100%.

Но в https://www.intuit.ru/intuituser/study/diplomas ничего нет.

Что делать? Как получить сертификат?