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

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

.pdf
Скачиваний:
0
Добавлен:
06.09.2026
Размер:
2 Мб
Скачать
71
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);
72
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);
73
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 возвращает итератор на найденный элемент
или на конец контейнера, если элемент не найден.
Для работы с ассоциативными контейнерами очень важны методы работы с
диапазонами.
74
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 возвращает итератор на элемент, ключ
когорого больше, чем аргумент.
75
Для работы с отображением нужно подключить библиотеку #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>. Для задания элементов отображения и поиска в нем
используется переопределенный оператор индексации.
76
Адаптеры
Для создания из базовых контейнеров специализированных применяются
конструкции, называемые адаптерами контейнеров. Они предоставляют более
простой интерфейс. В библиотеке STL представлено три специализированных
контейнера: стек, очередь и очередь с приоритетом. В стек данные добавляются
и читаются с одного конца, в очередь добавляются в конец, читаются с начала.
В очередь с приоритетом
добавляются с начала, читаются в строгом
соответствии с величиной хранящегося значения. Приоритет имеют данные с
наибольшими значениями. Таким образом, очередь с приоритетом
автоматически сортирует данные.
Для реализации адаптеров могут использоваться различные
последовательные контейнеры, хотя дек используется более часто. Для
использования нужно подключать соответствующую библиотеку.
stack<deque<int>> Stack;
Алгоритмы
Алгоритм – это функция, которая производит некоторые действия над
элементами контейнера. Алгоритмы не являются методами класса и даже не
являются дружественными функциями. Алгоритмы – независимые шаблоны
функций. Их можно использовать также с массивами и вашими собственными
контейнерами (предполагается, что в класс включены некоторые базовые
функции). Ниже представлены некоторые типичные алгоритмы.
Алгоритм Назначение
find Возвращает первый элемент с указанным
значением
count Считает коли чест во элементов с указанным
значением
equal Сравнивает содержимое двух контейнеров
77
Алгоритм Назначение
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;
}
78
Пример сортировки контейнера:
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";
}
//--------------------------------------------------------------
79
Пример использования предиката:
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];
80
// 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 };
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]