Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Алгоритмические языки и программирование. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
12.08.2026
Размер:
997 Кб
Скачать

for (unsigned int j = 0; j < 5; ++j){

 

List2.push_back (Arr2[j]);

// List2: 15, 20, 25, 30, 35

}

 

 

List1.reverse();

// reverse List1: 10 20 30 40

List1.merge (List2);

// merge List2 into List1

List1.unique();

// remove duplicate 20 and 30

int size = List1.size();

 

 

while (!List1.empty()){

 

 

cout << List1.front() << ' ';

// read item from front

List1.pop_front();

// pop item off front

}

 

 

return 0;

 

 

}

Метод reverse меняет порядок следования элементов на обратный, метод merge сливает вместе элементы двух списков и сохраняет их в List1, метод unique находит рядом стоящие одинаковые элемены и оставляет только один из них.

Последним последовательным контейнером является дек, который представляет собой сочетание стека и очереди и позволяет добавлять элементы как в начало, так и в конец. Нужно добавить библиотеку #include <deque>.

int main(){ deque<int> Deq;

Deq.push_back(30);

// push items on back

Deq.push_back(40);

 

Deq.push_back(50);

 

Deq.push_front(20);

// push items on front

Deq.push_front(10);

 

71

Deq[2] = 33;

// change middle item

for (int j = 0; j < Deq.size(); ++j){

cout << Deq[j] << ' ';

// display items

}

 

 

return 0;

 

 

}

Ассоциативные контейнеры

Данные располагаются не последовательно, ключ используется для доступа к данным.

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

Контейнеры множество и отображение сопоставляют один ключ одному значению. Контейнеры мультимножество и мультиотображение позволяют хранить несколько ключей для одного значения.

Для работы со множеством и мультимножеством нужно подключать библиотеку #include <set>, для работы с отображением и мультиотображением – #include <map>. Для работы со строками используется библиотека #include <string>.

int main(){

string names[] = {"Juanita", "Robert", // array of string objects "Mary", "Amanda", "Marie"};

// initialize set to array

set<string, less<string>> nameSet(names, names+5);

72

nameSet.insert("Yvette");

// insert more names

nameSet.insert("Larry");

 

nameSet.insert("Robert");

// no effect; already in set

nameSet.insert("Barry");

 

nameSet.erase("Mary");

// erase a name

// display size of set

 

cout << "\nSize=" << nameSet.size() << endl; // iterator to set

set<string, less<string>> :: iterator

iter = nameSet.begin(); // display members of set while (iter != nameSet.end()){

cout << *iter++ << '\n';

}

// get name from user

cout << "\nEnter name to search for: "; string searchName;

cin >> searchName;

// find matching name in set set<string, less<string>> :: iterator

iter1 = nameSet.find(searchName); if (iter1 == nameSet.end()){

cout << "The name " << searchName << " is NOT in the set.";

}

else{

cout << "The name " << *iter1 << " IS in the set.";

}

return 0;

}

Для контейнера set существуют методы добавления и удаления элементов, а также поиска элемента. Метод find возвращает итератор на найденный элемент или на конец контейнера, если элемент не найден.

Для работы с ассоциативными контейнерами очень важны методы работы с диапазонами.

73

int main(){

set<string, less<string>> organic; // set of string objects organic.insert("Curine"); // insert organic compounds organic.insert("Xanthine");

organic.insert("Curarine");

organic.insert("Melamine");

organic.insert("Cyanimide");

organic.insert("Phenol");

organic.insert("Aphrodine");

organic.insert("Imidazole");

organic.insert("Cinchonine");

organic.insert("Palmitamide");

organic.insert("Cyanimide");

set<string, less<string>> :: iterator

iter = organic.begin(); // display set while (iter != organic.end()){

cout << *iter++ << '\n';

}

string lower, upper; // display entries in range cout << "\nEnter range (example C Czz): ";

cin >> lower >> upper;

iter = organic.lower_bound(lower);

while (iter != organic.upper_bound(upper)){ cout << *iter++ << '\n';

}

return 0;

}

Метод lower_bound берет в качестве аргумента значение того же типа, что и ключ. Он возвращает итератор на элемент, ключ которого не меньше, чем значение аргумента. Метод upper_bound возвращает итератор на элемент, ключ когорого больше, чем аргумент.

74

Для работы с отображением нужно подключить библиотеку #include <map>.

int main(){

string states[] = { "Wyoming", "Colorado", "Nevada", "Montana", "Arizona", "Idaho"}; unsigned int pops[] = { 470, 2890, 800, 787, 2718, 944 };

map<string, int, less<string>> mapStates; string name;

unsigned int pop;

unsigned int Size = sizeof(states)/sizeof(states[0]); for (unsigned int j = 0; j < Size; ++j){

name = states[j];

 

//get data from arrays

pop = pops[j];

 

 

mapStates[name] = pop;

//put it in map

}

 

 

cout << "Enter state: ";

//get state from user

cin >> name;

 

 

pop = mapStates[name];

 

//find population

cout << "Population: " << pop << ",000\n";

cout << endl;

//display entire map

map<string, int, less<string>> :: iterator iter;

for (iter = mapStates.begin(); iter != mapStates.end(); ++iter){ cout << (*iter).first << ' ' << (*iter).second << ",000\n";

}

return 0;

}

В примере для описания отображения используется три шаблонных аргумента. Первый задает тип ключа (название штата), второй – значение (население), третьим аргументом задаем порядок. Мы хотим, чтобы названия штатов выводились в алфавитном порядке, поэтому третьим аргументом передаем less<string>. Для задания элементов отображения и поиска в нем используется переопределенный оператор индексации.

75

Адаптеры

Для создания из базовых контейнеров специализированных применяются конструкции, называемые адаптерами контейнеров. Они предоставляют более простой интерфейс. В библиотеке STL представлено три специализированных контейнера: стек, очередь и очередь с приоритетом. В стек данные добавляются

ичитаются с одного конца, в очередь добавляются в конец, читаются с начала.

Вочередь с приоритетом добавляются с начала, читаются в строгом соответствии с величиной хранящегося значения. Приоритет имеют данные с наибольшими значениями. Таким образом, очередь с приоритетом автоматически сортирует данные.

Для реализации адаптеров могут использоваться различные последовательные контейнеры, хотя дек используется более часто. Для использования нужно подключать соответствующую библиотеку.

stack<deque<int>> Stack;

Алгоритмы

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

Алгоритм

Назначение

 

 

find

Возвращает первый элемент с указанным

 

значением

 

 

count

Считает количество элементов с указанным

 

значением

 

 

equal

Сравнивает содержимое двух контейнеров

 

 

76

Алгоритм

Назначение

 

 

 

 

 

 

search

Ищет последовательность

значений

в

 

контейнере

 

 

 

 

 

 

copy

Копирует последовательность

значений

из

 

одного контейнера в другой

 

 

 

 

 

swap

Обменивает значения двух контейнеров

 

 

 

 

iter_swap

Обменивает последовательности значений

 

 

 

 

fill

Копирует значение во множество ячеек

 

 

 

 

sort

Сортирует значения в указанном порядке

 

 

 

 

merge

Сливает две последовательности значений

 

 

 

accumulate

Возвращает сумму элементов в заданном

 

диапазоне

 

 

 

 

for_each

Выполняет заданную функцию для каждого

 

элемента контейнера

 

 

 

 

 

 

Для работы с алгоритмами нужно использовать библиотеку #include <algorithm>. Алгоритм find принимает в качестве параметров диапазон поиска и значение.

int main(){

int arr[] = { 11, 22, 33, 44, 55, 66, 77, 88 };

int* ptr = find(arr, arr+8, 33); //find first 33

cout << "First object with value 33 found at offset " << (ptr-arr) << endl; return 0;

}

Пример подсчета количества встреч заданного элемента в контейнере: int main(){

int arr[] = { 33, 22, 33, 44, 33, 55, 66, 77 };

int n = count(arr, arr+8, 33); //count number of 33's cout << "There are " << n << " 33's in arr." << endl; return 0;

}

77

Пример сортировки контейнера: int main(){

int arr[] = {45, 2, 22, -17, 0, -30, 25, 55}; unsigned int Size = sizeof(arr) / sizeof(arr[0]);

sort (arr, arr + Size);

// sort the numbers

for (unsigned int j = 0; j < Size; ++j){

// display sorted array

cout << arr[j] << ' ';

}

return 0;

}

Пример слияния двух контейнеров в один: int main(){

int src1[] = { 2, 3, 4, 6, 8 }; int src2[] = { 1, 3, 5 };

int dest[8];

//merge src1 and src2 into dest

merge (src1, src1 + 5, src2, src2 + 3, dest); for (int j = 0; j < 8; ++j){ // display dest

cout << dest[j] << ' ';

}

return 0;

}

Некоторые алгоритмы имеют версию с окончанием _if. Они принимают дополнительный параметр, который является функцией или функтором. Он возвращает логические значения и называется предикатом.

Пример предиката: //--------------------------------------------------------------

bool isDon (const string &name){ // predicate return name == "Don";

}

//--------------------------------------------------------------

78

Пример использования предиката: int main(){

string names[] = { "George", "Estelle", "Don", "Mike", "Bob" }; string* ptr = find_if (names, names+5, isDon);

if (ptr == names+5){

cout << "Don is not on the list.\n";

}

else{

cout << "Don is element "

<<(ptr-names)

<<" on the list.\n";

}

return 0;

}

//--------------------------------------------------------------------

void inches_to_cm(double in){ // convert and display as centimeters cout << (in * 2.54) << ' ';

}

//--------------------------------------------------------------------

int main(){

double inches[] = { 3.5, 6.2, 1.0, 12.75, 4.33 }; // array of inches values // output as centimeters

for_each(inches, inches+5, inches_to_cm); return 0;

}

//-------------------------------------------------------------------

double inches_to_cm(double in){ // convert inches to centimeters return (in * 2.54); // return result

}

//-------------------------------------------------------------------

int main(){

double inches[] = { 3.5, 6.2, 1.0, 12.75, 4.33 }; double centi[5];

79

// transform into array centi[]

transform(inches, inches+5, centi, inches_to_cm);

for (int j = 0; j < 5; ++j){ // display array centi[] cout << centi[j] << ' ';

}

return 0;

}

Итераторы

Итераторы – это сущности, напоминающие указатели. Они используются для получения доступа к элементам контейнера и для последовательного продвижения по контейнеру от элемента к элементу (этот процесс называется итерацией). К итератору можно применить перегруженный оператор инкремента ++, после чего итератор сдвигается на следующий элемент, и оператор разыменования *, после чего можно получить доступ к значению элемента.

Существует три основных типа итератора: прямые, двунаправленные, со случайным доступом. Прямой итератор может проходить по контейнеру только в прямом направлении. Двунаправленный может двигаться в прямом и обратном направлении, для чего используется оператор декремента “–“. Итератор со случайным доступом может двигаться в любом направлении и перескакивать на любое количество элементов.

Существует также два специализированных вида итератора. Это входной итератор, который может указывать на устройство ввода (cin или входной файл) и последовательно считывает элементы, и выходной, который указывает на устройство вывода и выводит элементы.

Пример вывода элементов списка: int main(){

int arr[] = { 2, 4, 6, 8 };

80

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]