Лекции.Орг


Поиск:




Категории:

Астрономия
Биология
География
Другие языки
Интернет
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Механика
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Транспорт
Физика
Философия
Финансы
Химия
Экология
Экономика
Электроника

 

 

 

 


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




Обобщенные алгоритмы STL разделяются на четыре большие категории в соответствии с их семантикой. Неизменяющие алгоритмы над последовательностями работают с контейнерами без модификации их содержимого, в то время как изменяющие алгоритмы над последовательностями обычно модифицируют содержимое контейнеров, с которыми они имеют дело. Связанные с сортировкой алгоритмы включают алгоритмы сортировки и слияния, алгоритмы бинарного поиска и операции над множествами, работающие с упорядоченными последовательностями. Наконец, имеется небольшой набор обобщенных числовых алгоритмов. Неизменяющие алгоритмы над последовательностями — это алгоритмы, которые непосредственно не модифицируют контейнеры, с которыми работают. Они включают алгоритмы для поиска элементов в последовательностях, проверки равенства и пересчета элементов последовательности. Это алгоритмы f in d, a d ja c e n t_ f in d, co u n t, f o r _ e a c h, m ism atch, e q u a l и

s e a r c h. Алгоритм a d j a c e n t_ f in d выполняет сканирование последовательности в поисках пары смежных одинаковых элементов. Когда такая пара найдена, алгоритм возвращает итератор, указывающий на первый элемент пары. Алгоритм c o u n t представляет собой неизменяющий алгоритм, сканирующий последовательность для подсчета количества элементов, равных определенному значению. Обобщенный алгоритм f o r _ e a c h применяет функцию f к каждому элементу последовательности. Алгоритмы m ism atch и e q u a l используются для сравнения двух диапазонов. Каждый из них получает три параметра-итератора: f i r s t l, l a s t l и f i r s t 2. Алгоритм e q u a l возвращает tr u e, если элементы в соответствующих позициях f i r s t l + / и f i r s t 2 + i иравны для всех позиций f i r s t l + iиз диапазона [ f i r s t l; l a s t l), и f a ls e в противном случае. Алгоритм m ism atch возвращает пару итераторов (тип p a ir),11 f i r s t l + in f i r s t 2 + i, которые представляют собой первые позиции последовательностей, где найдены неодинаковые элементы. Если неодинаковых элементов в соответствующих позициях не обнаружено, возвращается пара итераторов l a s t l и f i r s t 2 + (l a s t l - f i r s t l). Для двух данных диапазонов обобщенный алгоритм s e a r c h находит первую позицию в первом диапазоне, с которой вторая позиция входит в первую в качестве подпоследовательности. Этот алгоритм обобщает функции поиска подстрок наподобие библиотечной функции С strstr.

Пример 5.4. Иллюстрация применения обобщенного алгоритма f in d i f

иех05-04.срр" 97а =

#include <iostream>

#include <algorithm>

#include <cassert>

#include <vector>

using namespace std;

// Определение типа унарного предиката:

class GreaterThanSO {

public:

bool operator()(int x) const { return x > 50; }

};

int main()

{

cout << "Иллюстрация применения обобщенного "

<< "алгоритма find_if." << endl;

// Создание вектора со значениями

// 0, 1, 4, 9, 16,..., 144:

vector<int> vectorl;

for (int i = 0; i < 13; ++i)

vectorl.push_back(i * i);

vector<int>::iterator where;

where = find_if(vectorl.begin(), vectorl.e nd(),

GreaterThanSO());

assert (*where == 64);

cout << " -- Ok." << endl;

return 0;

}

Пример 5.5. Иллюстрация применения обобщенного алгоритма

adj a c e n t f in d

"ех05-05.срр" 976 =

#include <iostream>

#include <string>

#include <algorithm>

#include <cassert>

#include <functional>

#include <deque>

using namespace std;

int main()

{

cout << "Иллюстрация применения обобщенного "

<< "алгоритма adjacent_find." << endl;

deque<string> player(5);

deque<string>::iterator i;

// Инициализация дека:

player[0] = "Pele";

player[1] = "Platini";

player[2] = "Maradona";

player[3] = "Maradona";

player[4] = "Rossi";

// Поиск первой пары одинаковых последовательных имен:

i = adjacent_find(player.begin(), player.e n d ());

assert (*i == "Maradona" && *(i+l) == "Maradona");

// Поиск первого имени, лексикографически большего,

// чем следующее за ним:

i = adjacent_find(player.begin(), player.e n d (),

greater<string>());

assert (*i == "Platini" && *(i+l) == "Maradona");

cout << " -- Ok." << endl;

return 0;

}

Изменяющие алгоритмы модифицируют содержимое контейнеров, с которыми работают.

Например, алгоритм u n iq u e удаляет все последовательные дублирующиеся элементы из последовательности. Другие алгоритмы из этой категории копируют, заполнят, генерируют, замещают и т.п. элементы последовательных контейнеров, с которыми работают.

Обобщенные алгоритмы сору и co p y _ b ack w ard используются для копирования элементов из одного диапазона в другой. Вызов copy(firstl/ lastl, first2) копирует элементы из диапазона [ f i r s t l; l a s t l) в [ f i r s t 2; l a s t 2) и возвращает итератор la s t2, где la s t2 == f i r s t 2 + (l a s t l - f i r s t l). Алгоритм работает в прямом направлении, копируя исходные элементы в порядке f i r s t l, f i r s t l + 1,..., l a s t l - 1,

так что целевой диапазон может перекрываться с исходным, если последний не содержит f i r s t 2. Так, например, со р у может использоваться для сдвига диапазона на одну позицию влево, но не вправо. Обратное верно для алгоритма copy_backw ard: c°py_backward(firstl, lastl, last2) который копирует элементы из диапазона [ f i r s t l; l a s t l) в диапазон [ f i r s t 2; l a s t 2) и возвращает f i r s t 2, где f i r s t 2 == la s t2 - (l a s t l - f i r s t l). Он работает в обратном направлении, копируя исходные элементы в порядке l a s t l - 1, l a s t l - 2,..., f i r s t l. Таким образом, копирование выполняется корректно, если исходный диапазон не содержит l a s t 2.

Пример 5.10. Демонстрация использования обобщенных алгоритмов сору И copy backward

"ех05- 1 0.срр" 104 =

#include <iostream>

#include <cassert>

#include <algorithm>

#include <vector>

#include <string>

#include <iostream>

using namespace std;

int main()

{

cout << "Демонстрация использования обобщенных "

<< "алгоритмов сору и copy_backward." << endl;

string s ("abcdefghihklmnopqrstuvwxyz");

vector<char> vectorl(s.begin(), s.end());

vector<char> vector2(vectorl.size());

// Копирование vectorl в vector2:

copy(vectorl.begin(), vectorl.e nd(),

vector2.begin());

assert (vectorl == vector2);

// Сдвиг содержимого vectorl влево на 4 позиции:

copy(vectorl.begin() + 4, vectorl.e nd(),

vectorl.begin());

assert (string(vectorl.begin(), vectorl.end()) ==

string("efghihklmnopqrstuvwxyzwxyz"));

// Сдвиг его же вправо на 2 позиции:

copy_backward(vectorl.begin(), vectorl.e nd() - 2,

vectorl.e nd());

assert (string(vectorl.begin(), vectorl.end()) ==

string("efefghihklmnopqrstuvwxyzwx"));

cout << " -- Ok." << endl;

return 0;

}

Первый пример copy выполняет копирование содержимого v e c to r l в v e c to r 2. Второй пример иллюстрирует копирование перекрывающихся диапазонов, сдвигая содержимое v e c to r l влево на четыре позиции. Обратите внимание, что после копирования первые четыре символа, ab ed, оказываются потеряны, а последние четыре, wxyz, повторяются в конце дважды. Пример co p y _ b ack w ard выполняет сдвиг на две позиции вправо; такой сдвиг нельзя выполнить при помощи алгоритма сору. В этом случае первые два символа, e f, повторяются в начале строки, а последние два, yz, будут утеряны. Алгоритмы f i l l и f i l l _ n помещают копии данного значения во все позиции диапазона. Вызов fill(first, last, value) помещает l a s t - f i r s t копий v a lu e в [ f i r s t; l a s t). Вызов fill_n(first, n, value) помещает n копий v a lu e в [ f i r s t; f i r s t + n). Алгоритм g e n e r a te заполняет диапазон [ f i r s t; l a s t) значениями, которые возвращают l a s t - f i r s t последовательных вызовов функции g en (третий параметр алгоритма g e n e r a te). Предполагается, что g en не получает никаких аргументов. Обобщенный алгоритм ran d o m _ sh u f f le случайным образом переставляет элементы из диапазона [ f i r s t; l a s t), используя для этого функцию, генерирующую псевдослучайные числа. Перестановки, получающиеся при применении алгоритма ran d o m _ sh u f f le, имеют приблизительно равномерное распределение, т.е. вероятность каждой из N\ перестановок диапазона размером N приблизительно равна \/N\. Обобщенный алгоритм remove удаляет из диапазона те элементы, которые равны определенному значению. Этот алгоритм устойчивый, т.е. он сохраняет относительный порядок остающихся элементов последовательности. Обобщенный алгоритм r e p la c e заменяет элементы в диапазоне, равные некоторому заданному значению, другим значением. Обобщенный алгоритм r o t a t e выполняет циклический сдвиг диапазона. Вызов r o t a t e (f i r s t, m iddle, la s t) циклически сдвигает элементы в диапазоне [ f i r s t; l a s t) влево на m id d le - f i r s t позиций. STL предоставляет три обобщенных алгоритма сортировки,— s o r t, p a r t i a l s o r t и s ta b le _ s o r t. Каждый сортирует последовательность с произвольным доступом и размещает результат в том же контейнере, с которым работает. Алгоритм p a r tia l_ _ s o r t требует константного количества дополнительной памяти, s o r t — логарифмического. Они оба по сути являются алгоритмами, работающими “на месте”, в то время как алгоритм s ta b le _ s o r t может потребовать линейного количества дополнительной памяти. В STL входят четыре обобщенных числовых алгоритма: a c c u m u la te, p a r tia l_ s u m, a d ja c e n t_ d if f e r e n c e и in n e r _ j? r o d u c t. В этом разделе мы рассмотрим примеры ис­

пользования каждого из этих алгоритмов. Обобщенный алгоритм a c c u m u la te суммирует значения из указанного диапазона.

 

49. Функциональные объекты STL. Простые функциональные объекты. Стандартные функциональные объекты. Связыватели std::bind.

Функциональный объект представляет собой любую сущность, которая может быть применена к нулю или большему количеству элементов для получения значения и/или изменения состояния вычислений. В программировании на C++ любая обычная функция отвечает этому определению, но ему же отвечает и объект любого класса (или структуры), который перегружает оператор вызова функции o p e r a to r ().Приведем пример работы функциональных объектов с двумя аргументами функции. Определим шаблонный класс PairSelect, содержащий функцию печати, которая выводит меньший элемент пары в соответствии с определенным нами отношением «меньше чем», задаваемым параметром шаблона. Также в виде параметра шаблона мы зададим тип элементов пары. Следующая программа использует два отношения упорядочения. Они реализованы в виде бинарных предикатов, то есть функций, которые имеют два аргумента и возвращают логическое значение. Наш первый бинарный предикат, LessThan, является шаблоном, поэтому он применим к любому типу, для которого определен оператор < Второй предикат, CompareLastDigits,является обычным, не шаблонным, функциональным классом, который практически совпадает с функциональным классом, определенным в последнем разделепредыдущей главы, только результат его вызова равен true,если последняя цифра первого аргумента меньше, чем у второго, и false - в противном случае.

// funobj3.cpp: Функция operator!) как

// бинарный предикат.

#include <iostream.h>

template <class T>

struct LessThan {

bool operator()(const T &x, const T &y)const

{ return x < y;

}

};

struct CompareLastDigits {

bool operator()(int x, int y)const

{ return x % 10 < у % 10;

}

};

Функциональные объекты 141

template <class Т, class Compare>

class PairSelect {

public:

PairSelect(const T &x, const T &y): a(x), b(y){}

void PrintSmaller()const

{ cout << (Compare()(a, b)? a: b) «endl;

}

private:

Т а, b;

};

int main()

{ PairSelect<double, LessThan<double> > P (123.4, 98.7);

P.PrintSmaller(); // Вывод: 98.7

PairSelect<int, CompareLastDigits> Q (123, 98);

Q.PrintSmaller(); // Вывод: 123

return 0;

}

Эта программа сначала выводит значение 98.7, потому что оно меньше другого элемента объекта Q - 123.4. После этого она выводит 123, поскольку последняя цифра этого числа - 3 - меньше, чем последняя цифра числа 98. Одно из главных преимуществ заключается в том, что объекты, в отличие от обычных функций, могут хранить дополнительную информацию, которая затем может использоваться обобщенными алгоритмами или контейнерами. Связыватель (binder) применяется для преобразования бинарного функционального объекта в унарный путем связывания аргумента с некоторым определенным значением. В STL это достигается с помощью использования привяжи,которая является одним из видов адаптера функции. Чтобы превратить бинарный предикат в унарный, привязав его второй аргумент, мы используем привязку bind2nd.В нашем примере требуется использовать выражение bind2nd(less<int>(), 100) чтобы указать, что мы хотим считать только значения, меньшие 100. Следующая программа показывает, как это все работает // binder.срр: Использование адаптера bind2nd для подсчета, сколько из элементов массива меньше, чем 100.

♦include <iostream>

♦include <algorithm>

♦include <functional>

using namespace std;

int main()

{ int a [10] = {800, 3, 4, 600, 5, 6, 800, 71, 100, 2},

n = 0;

n = count_if(a, a + 10, bind2nd(less<int>(), 100));

cout << n «endl; // Вывод: 6

return 0;

}

Для п р и вязы ван и я первого аргумента сущ ествует п р и вязка bindXst. К примеру, заменим условие х < 100 эквивалентным условием 100 > х Этого можно добиться, привязав первый операнд у выражения у > х к значению 100. Следовательно, программа binder.срр выдаст тот же результат, если мы заменим вызов c o u n t if на следующий: n = count_if(a, а + 10, bindlst(greater<int>(), 100));

 

 





Поделиться с друзьями:


Дата добавления: 2016-07-29; Мы поможем в написании ваших работ!; просмотров: 757 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Студент всегда отчаянный романтик! Хоть может сдать на двойку романтизм. © Эдуард А. Асадов
==> читать все изречения...

4565 - | 4250 -


© 2015-2026 lektsii.org - Контакты - Последнее добавление

Ген: 0.01 с.