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

Программирование на C / C++ / Ален И. Голуб. Правила программирования на Си и Си++ [pdf]

.pdf
Скачиваний:
291
Добавлен:
02.05.2014
Размер:
5.67 Mб
Скачать

С++ для начинающих

1082

template < class InputIterator, class Type > Type accumulate(

InputIterator first, InputIterator last, Type init );

template < class InputIterator, class Type, class BinaryOperation >

Type accumulate(

InputIterator first, InputIterator last,

Type init, BinaryOperation op );

Первый вариант accumulate() вычисляет сумму значений элементов последовательности из диапазона, ограниченного парой итераторов [first,last), с начальным значением, которое задано параметром init. Например, если дана последовательность {1,1,2,3,5,8} и начальное значение 0, то результатом работы алгоритма будет 20. Во втором варианте вместо оператора сложения к элементам применяется переданная бинарная операция. Если бы мы передали алгоритму accumulate() объект-функцию times<int> и начальное значение 1, то получили бы результат 240. accumulate() это один из численных алгоритмов; для его

#include <numeric> #include <list> #include <functional> #include <iostream.h>

/*

*выход:

*accumulate()

*работает с последовательностью {1,2,3,4}

*результат для сложения по умолчанию: 10

*результат для объекта-функции plus<int>: 10

*/

int main()

{

int ia[] = { 1, 2, 3, 4 }; list<int,allocator> ilist( ia, ia+4 );

int ia_result = accumulate(&ia[0], &ia[4], 0); int ilist_res = accumulate(

ilist.begin(), ilist.end(), 0, plus<int>() );

cout << "accumulate()\n\t"

<<"работает с последовательностью {1,2,3,4}\n\t"

<<"результат для сложения по умолчанию: "

<<ia_result << "\n\t"

<<"результат для объекта-функции plus<int>: "

<<ilist_res

<<endl;

return 0;

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

}

С++ для начинающих

1083

template < class InputIterator, class OutputIterator > OutputIterator adjacent_difference(

InputIterator first, InputIterator last, OutputIterator result );

template < class InputIterator, class OutputIterator > class BinaryOperation >

OutputIterator adjacent_difference( InputIterator first, InputIterator last,

Алгоритм adjacent_difference()

OutputIterator result, BinaryOperation op );

Первый вариант adjacent_difference() создает новую последовательность, в которой значение каждого элемента, кроме первого, равно разности между текущим и предыдущим элементами исходной последовательности. Например, если дано {0,1,1,2,3,5,8}, то первым элементом новой последовательности будет копия: 0. Вторым разность первых двух элементов исходной последовательности: 1. Третий элемент равен разности третьего и второго элементов: 1-1=0, и т.д. В результате мы получим последовательность {0,1,0,1,1,2,3}.

Во втором варианте разность соседних элементов вычисляется с помощью указанной бинарной операции. Возьмем ту же исходную последовательность и передадим объект- функцию times<int>. Как и раньше, первый элемент просто копируется. Второй элемент это произведение первого и второго элементов исходной последовательности; он тоже равен 0. Третий элемент произведение второго и третьего элементов исходной последовательности: 1 * 1 = 1, и т.д. Результат – {0,1,2,6,15,40}.

В обоих вариантах итератор OutputIterator указывает на элемент, расположенный за последним элементом новой последовательности. adjacent_difference() это один из численных алгоритмов, для его использования в программу необходимо включить заголовочный файл <numeric>.

С++ для начинающих

1084

#include <numeric> #include <list> #include <functional> #include <iterator> #include <iostream.h>

int main()

{

int ia[] = { 1, 1, 2, 3, 5, 8 };

list<int,allocator> ilist(ia, ia+6); list<int,allocator> ilist_result(ilist.size());

adjacent_difference(ilist.begin(), ilist.end(), ilist_result.begin() );

//на выходе печатается:

//1 0 1 1 2 3

copy( ilist_result.begin(), ilist_result.end(), ostream_iterator<int>(cout," "));

cout << endl;

adjacent_difference(ilist.begin(), ilist.end(), ilist_result.begin(), times<int>() );

//на выходе печатается:

//1 1 2 6 15 40

copy( ilist_result.begin(), ilist_result.end(), ostream_iterator<int>(cout," "));

cout << endl;

}

template < class ForwardIterator > ForwardIterator

adjacent_find( ForwardIterator first, ForwardIterator last );

template < class ForwardIterator, class BinaryPredicate > ForwardIterator

adjacent_find( ForwardIterator first,

Алгоритм adjacent_find()

ForwardIterator last, Predicate pred );

adjacent_find() ищет первую пару одинаковых соседних элементов в диапазоне, ограниченном итераторами [first,last). Если соседние дубликаты найдены, то алгоритм возвращает однонаправленный итератор, указывающий на первый элемент пары, в противном случае возвращается last. Например, если дана последовательность {0,1,1,2,2,4}, то будет найдена пара [1,1] и возвращен итератор, указывающий на первую единицу.

С++ для начинающих

1085

#include <algorithm> #include <vector> #include <iostream.h> #include <assert.h>

class TwiceOver { public:

bool operator() ( int val1, int val2 )

{ return val1 == val2/2 ? true : false; }

};

int main()

{

int ia[] = { 1, 4, 4, 8 };

vector< int, allocator > vec( ia, ia+4 );

int *piter;

vector< int, allocator >::iterator iter;

// piter указывает на ia[1]

piter = adjacent_find( ia, ia+4 ); assert( *piter == ia[ 1 ] );

// iter указывает на vec[2]

iter = adjacent_find( vec.begin(), vec.end(), TwiceOver() ); assert( *iter == vec[ 2 ] );

// пришли сюда: все хорошо

cout << "ok: adjacent-find() завершился успешно!\n"; return 0;

}

template < class ForwardIterator, class Type > bool

binary_search( ForwardIterator first,

ForwardIterator last, const Type &value );

template < class ForwardIterator, class Type > bool

binary_search( ForwardIterator first,

ForwardIterator last, const Type &value,

Алгоритм binary_search()

Compare comp );

binary_search() ищет значение value в отсортированной последовательности, ограниченной парой итераторов [first,last). Если это значение найдено, возвращается true, иначе false. В первом варианте предполагается, что контейнер отсортирован с помощью оператора меньше”. Во втором варианте порядок определяется указанным объектом-функцией.

С++ для начинающих

1086

#include <algorithm> #include <vector> #include <assert.h>

int main()

{

int ia[] = {29,23,20,22,17,15,26,51,19,12,35,40}; vector< int, allocator > vec( ia, ia+12 );

sort( &ia[0], &ia[12] );

bool found_it = binary_search( &ia[0], &ia[12], 18 ); assert( found_it == false );

vector< int > vec( ia, ia+12 );

sort( vec.begin(), vec.end(), greater<int>() ); found_it = binary_search( vec.begin(), vec.end(),

26, greater<int>() ); assert( found_it == true );

}

template < class InputIterator, class OutputIterator > OutputIterator

copy( InputIterator first1, InputIterator last,

Алгоритм copy()

OutputIterator first2 )

copy() копирует последовательность элементов, ограниченную парой итераторов [first,last), в другой контейнер, начиная с позиции, на которую указывает first2. Алгоритм возвращает итератор, указывающий на элемент второго контейнера, следующий за последним вставленным. Например, если дана последовательность

int ia[] = {0, 1, 2, 3, 4, 5 };

// сдвинуть элементы влево на один, получится {1,2,3,4,5,5}

{0,1,2,3,4,5}, мы можем сдвинуть элементы на один влево с помощью такого вызова: copy( ia+1, ia+6, ia );

copy() начинает копирование со второго элемента ia, копируя 1 в первую позицию, и так далее, пока каждый элемент не окажется в позиции на одну левее исходной.

С++ для начинающих

1087

#include

<algorithm>

#include

<vector>

#include

<iterator>

#include <iostream.h>

/* печатается:

0 1 1

3 5 8 13

сдвиг

массива влево на 1:

1 1 3

5 8 13 13

сдвиг

вектора влево на 2:

1 3 5

8 13 8 13

*/

 

int main()

{

int ia[] = { 0, 1, 1, 3, 5, 8, 13 }; vector< int, allocator > vec( ia, ia+7 );

ostream_iterator< int > ofile( cout, " " );

cout << "исходная последовательность элементов:\n"; copy( vec.begin(), vec.end(), ofile ); cout << '\n';

// сдвиг влево на один элемент copy( ia+1, ia+7, ia );

cout << "сдвиг массива влево на 1:\n"; copy( ia, ia+7, ofile ); cout << '\n';

// сдвиг влево на два элемента

copy( vec.begin()+2, vec.end(), vec.begin() );

cout << "сдвиг вектора влево на 2:\n";

copy( vec.begin(), vec.end(), ofile ); cout << '\n';

}

template < class BidirectionalIterator1, class BidirectionalIterator2 >

BidirectionalIterator2

copy_backward( BidirectionalIterator1 first, BidirectionalIterator1 last1,

Алгоритм copy_backward()

BidirectionalIterator2 last2 )

copy_backward() ведет себя так же, как copy(), только элементы копируются в обратном порядке: копирование начинается с last1-1 и продолжается до first. Кроме того, элементы помещаются в целевой контейнер с конца, от позиции last2-1, пока не будет скопировано last1-first элементов.

Например, если дана последовательность {0,1,2,3,4,5}, мы можем скопировать последние три элемента (3,4,5) на место первых трех (0,1,2), установив first равным адресу значения 0, last1 адресу значения 3, а last2 адресу значения 5. Тогда

С++ для начинающих

1088

элемент 5 попадает на место элемента 2, элемент 4 – на место 1, а элемент 3 – на место

 

 

 

#include <algorithm>

 

 

 

 

 

 

#include <vector>

 

 

 

#include <iterator>

 

 

 

#include <iostream.h>

 

 

 

class print_elements {

 

 

 

public:

 

 

 

void operator()( string elem ) {

 

 

 

cout << elem

 

 

 

<< ( _line_cnt++%8 ? " " : "\n\t" );

 

 

 

}

 

 

 

static void reset_line_cnt() { _line_cnt = 1; }

 

 

 

private:

 

 

 

static int _line_cnt;

 

 

 

};

 

 

 

int print_elements::_line_cnt = 1;

 

 

 

/* печатается:

 

 

 

исходный список строк:

 

 

 

The light untonsured hair grained and hued like

 

 

 

pale oak

 

 

 

после copy_backward( begin+1, end-3, end ):

 

 

 

The light untonsured hair light untonsured hair grained

 

 

 

and hued

 

 

 

*/

 

 

 

int main()

 

 

 

{

 

 

 

string sa[] = {

 

 

 

"The", "light", "untonsured", "hair",

 

 

 

"grained", "and", "hued", "like", "pale", "oak" };

 

 

 

vector< string, allocator > svec( sa, sa+10 );

 

 

 

cout << "исходный список строк:\n\t";

 

 

 

for_each( svec.begin(), svec.end(), print_elements() );

 

 

 

cout << "\n\n";

 

 

 

copy_backward( svec.begin()+1, svec.end()-3, svec.end() );

 

 

 

print_elements::reset_line_cnt();

 

 

 

cout << "после copy_backward( begin+1, end-3, end ):\n";

 

 

 

for_each( svec.begin(), svec.end(), print_elements() );

 

 

 

cout << "\n";

 

0. В результате получим последовательность {3,4,5,3,4,5}.

 

 

 

}

 

 

 

 

 

 

 

Алгоритм count()

С++ для начинающих

1089

template < class InputIterator, class Type > iterator_traits<InputIterator>::distance_type count( InputIterator first,

InputIterator last, const Type& value );

count() сравнивает каждый элемент со значением value в диапазоне, ограниченном парой итераторов [first,last), с помощью оператора равенства. Алгоритм возвращает число элементов, равных value. (Отметим, что в имеющейся у нас

реализации стандартной библиотеки поддерживается более ранняя спецификация count().)

С++ для начинающих

1090

#include <algorithm> #include <string> #include <list> #include <iterator>

#include <assert.h> #include <iostream.h> #include <fstream.h>

/*********************************************************************** * прочитанный текст:

Alice Emma has long flowing red hair. Her Daddy says

when the wind blows through her hair, it looks almost alive,

like a fiery bird in flight. A beautiful fiery bird, he tells her, magical but untamed. "Daddy, shush, there is no such thing,"

she tells him, at the same time wanting him to tell her more. Shyly, she asks, "I mean, Daddy, is there?"

************************************************************************

*программа выводит:

*count(): fiery встречается 2 раз(а)

************************************************************************

*/

int main()

{

ifstream infile( "alice_emma" ); assert ( infile != 0 );

list<string,allocator> textlines;

typedef list<string,allocator>::difference_type diff_type; istream_iterator< string, diff_type > instream( infile ),

eos;

copy( instream, eos, back_inserter( textlines ));

string search_item( "fiery" );

/*************************************************************

********

*примечание: ниже показан интерфейс count(), принятый в

*стандартной библиотеке. В текущей реализации библиотеки

*от RogueWave поддерживается более ранняя версия, в которой

*типа distance_type еще не было, так что count()

*возвращала результат в последнем аргументе

*

*вот как должен выглядеть вызов:

*typedef iterator_traits<InputIterator>::

*distance_type dis_type;

*

*dis_type elem_count;

*elem_count = count( textlines.begin(), textlines.end(),

*search_item );

**************************************************************

*********

int elem_count = 0; list<string,allocator>::iterator

ibegin = textlines.begin(), iend = textlines.end();

// устаревшая форма count()

count( ibegin, iend, search_item, elem_count );

cout << "count(): " << search_item

<< " встречается " << elem_count << " раз(а)\n";

С++ для начинающих

1091

}

template < class InputIterator, class Predicate > iterator_traits<InputIterator>::distance_type count_if( InputIterator first,

Алгоритм count_if()

InputIterator last, Predicate pred );

count_if() применяет предикат pred к каждому элементу из диапазона, ограниченного парой итераторов [first,last). Алгоритм сообщает, сколько раз предикат оказался равным true.