Модифицирующие алгоритмы. Копирование элементов

   
На этом шаге мы рассмотрим использование алгоритма copy.

   
Начиная с этого шага, мы будем рассматривать алгоритмы, модифицирующие элементы интервалов. Существуют два способа
модификации:

  • непосредственная модификация во время перебора;
  • модификация в процессе копирования из источника в приемник.

   
Некоторые модифицирующие алгоритмы поддерживают оба способа модификации элементов в интервале. В этом случае форма с
модификацией при копировании снабжается суффиксом _сору.

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

   
Все алгоритмы, использующие отдельный приемный интервал, возвращают позицию за последним скопированным элементом этого
интервала.
Копирование элементов

   
Для копирования элементов можно использовать следующие алгоритмы:

  OutputIterator
  copy (InputIterator sourceBeg, InputIterator sourceEnd, 
        Outputlterator destBeg)
  BidirectionalIterator1
  copy_backward (BidirectionalIterator1 sourceBeg,
                 BidirectionalIterator1 sourceEnd,
                 BidirectionalIterator2 destBeg)

   
Оба алгоритма копируют все элементы исходного интервала [sourceBeg,sourceEnd) в приемный интервал, начиная с
destBeg или заканчивая destEnd соответственно.

   
Алгоритмы возвращают позицию за последним скопированным элементом в приемном интервале (то есть позицию первого элемента,
который не был заменен в ходе копирования).

   
Итераторы destBeg и destEnd не могут входить в интервал [sourceBeg,sourceEnd).
Алгоритм сору() осуществляет перебор в прямом, а алгоритм copy_backward() - в обратном направлении. Данное
различие существенно только в том случае, если источник и приемник перекрываются:

  • чтобы приемник перекрывал источник с начала, используйте алгоритм сору(), то есть для алгоритма сору()
    позиция destBeg должна предшествовать позиции sourceBeg,
  • чтобы приемник перекрывал источник с конца, используйте алгоритм copy_backward(), то есть для алгоритма
    сору() позиция destBeg должна находиться за позицией sourceBeg.

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

   
Алгоритма copy_if() не существует. Чтобы скопировать только те элементы, которые удовлетворяют заданному критерию,
воспользуйтесь алгоритмом remove_copy_if().

   
Чтобы скопировать элементы в обратном порядке, воспользуйтесь алгоритмом reverse_copy(). Алгоритм
reverse_copy() работает чуть эффективнее сору() с обратными итераторами.

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

   
Примерная реализация алгоритма сору() приведена на 223 шаге.

   
Копирование всех элементов контейнера для однотипных контейнеров осуществляется оператором присваивания,
для разнотипных контейнеров - функцией assign() (смотри 199 шаг).

   
Чтобы удалить элементы в процессе копирования, используйте алгоритмы remove_copy() и remove_copy_if().

   
Чтобы модифицировать элементы в процессе копирования, используйте алгоритм transform() или replace_copy().

   
Сложность линейная (numberOfElements присваиваний).

   
В следующем примере продемонстрированы простые вызовы сору():

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

#include <vcl.h>
#include <iterator>
#include "algostuff.hpp"

#include <conio.h> //необходимо для getch()

#pragma hdrstop

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

#pragma argsused
using namespace std;

std::string ToRus(const std::string &in)
{
  char *buff = new char [in.length()+1];
  CharToOem(in.c_str(),buff);
  std::string out(buff);
  delete [] buff;
  return out;
}


int main()
{
  vector<int> coll1;
  list<int> coll2;

  INSERT_ELEMENTS(coll1,1,9);
  PRINT_ELEMENTS(coll1,"1-я коллекция:\n");

  // Копирование элементов coll1 в coll2
  //  - используем конечный итератор вставки,
  //    чтобы вместо замены производилась вставка элементов
  copy (coll1.begin(), coll1.end(),         // Источник
        back_inserter(coll2));              // Приемник

  // Вывод элементов coll2
  //  - копирование элементов в cout
  //    с использованием потокового итератора вывода
  cout << ToRus("2-я коллекция:\n");
  copy (coll2.begin(), coll2.end(),         // Источник
        ostream_iterator<int>(cout," "));   // Приемник
  cout << endl;

  // Копирование элементов coll1 в coll2 в обратном порядке
  //  - на этот раз с заменой
  copy (coll1.rbegin(), coll1.rend(),       // Источник
        coll2.begin());                     // Приемник
  PRINT_ELEMENTS(coll1,"1-я коллекция после копирования:\n");

  // Повторный вывод элементов coll2
  cout << ToRus("Повторный вывод 2-й коллекции:\n");
  copy (coll2.begin(), coll2.end(),         // Источник
        ostream_iterator<int>(cout," "));   // Приемник
  cout << endl;


  getch();
  return 0;
}

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

Текст этого примера можно взять здесь.

   
В этом примере конечный итератор вставки вставляет элементы приемный интервал. Без применения итераторов вставки алгоритм
сору() начинает замену в пустой коллекции соll2, что приводит к непредсказуемым последствиям. При использовании
потоковых итераторов вывода в качестве приемника используется стандартный выходной поток.

   
Результат выполнения программы выглядит так:


Рис.1. Результат работы приложения

   
На следующем шаге мы продолжим изучение этого вопроса.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий