Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
SHPORS~1.doc
Скачиваний:
2
Добавлен:
01.04.2025
Размер:
201.73 Кб
Скачать

29. Узагальнені алгоритми та бібліотека стандартних шаблонів. Ітератори.

Итераторы – это то, что удерживает контейнеры и алгоритмы вместе. Итератор – это чистая абстракция. Итератор абстрагирует понятие указателя на элемент последовательности. Ключевые концепции итератора: “текущий элемент” (* и ->), «указатель на след элемент» (++) и равенство (==). Каждая последовательность (массив, вектор, список и т.д.) имеет свой вид итератора. Итераторные классы и функции объявлен в пространстве имен std в заголовочном файле <iterator>.

Итератор не явл обычным указателем. Итератор, указывающий на какой-то элемент, наз действительным и через него можно получить доступ к элементу (*,[],->). Итератор м/б недействителен потому, что 1. не был инициализирован; 2. указывает на контейнер, кот изменил свои размеры; 3. контейнер уничтожен; 4. итератор обозначает конец последовательности. Конец последовательности – это итератор, указывающий на воображаемый объект, следующий за последним элементом в последовательности.

Stl-стандартна бібліотека шаблонів.Побудова контейнерів: розм. інтерфейс, багатофцнкціон; мінім. интурфейс +узагальнені алгоритми. Розглянемо приклад програми з використанням stl.

void main() {int ar[10]={0,1,2,3,4,5,6,7,8,9}; int * where_ar; find(ar,ar+10,7); list<int> l; for (int i=0; i<-9; i++) l.insert (l.end(),i); list<int>::iterator where_l; where_find(l.begin(), l.end(),7); cout<<”where_ar=”<<*where_ar; cout<<”wfere_l=”<<*where_l;}

Ітератор-об”єкт-покажчик за допомогою якого можно перебирати елементи контейнера. Для ітераторів допустимі операціі ++ -- == != і т.д.. Ітератори прифмають зн-ня в скалярному діапазоні. Наведемо приклад використання ітераторів.

template<class InputIterator, class T> inputIterator find (inputIterator first, inputIterator last, const t&value) {while ((first!=last)&&(*first!=value) first++; return first; }.

30. Використання стандартних контейнерів. Об”єкти-функції.

Многие вычисления подрразумевают создание наборов объектов в различных формах и обработку таких наборов. Например, чтение символов в строку и вывод строки. Класс, главной целью которого является хранение объектов, наз контейнером. Для иллюстрации наиболее полезных контейнеров, рассмотрим пример: телефонная книга.

Вектор. Основные данные (имя, номер) – стандартный масив пар. Но встроенные массивы имеют фиксированный размер. Стандартная библиотека предосталяет вектора (vector), которые сами позаботятся об этом.

struct Entry{string name; int number;}; vector <Entry> phone_book(1000); void add_entries(int n) {phone_book.resize(phone_book.size()+n);}

Обычными операциями явл включение и удаление номеров. Поэтому список (list) – более подходящая структура для представления справочника. list<Entry> phone_book; . Индексирование не применяется.

Каждый контейнер стандартной библиотеки снабжен функциями begin() и end(), которые возвращают итераторы на первый элемент и элемент, следующий за последним. Пользователю нет необходимости точно знать тип итератора стандартного контейнера. Тип итератора явл частью определения контейнера и на него можно сослаться по имени.

Тип map явл контейнером для хранения пар величин. Например, map<string,int>phone_book;. map также наз ассоциативным массивом, или словарем. Будучи проиндексован по значению первого типа (наз ключем), map возвращает соответствующее значение второго типа (значение, или отображенный тип). Например: void print_entry(const string&s){ if (int i=phone_book[s]) cout<<s<<’ ’<<i<<’\n’;. Если ключа s не найдено, возвращается значение по умолчанию (0).

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

vector<T> - вектор переменного размера, list<T> - двусвязный список, queue<T> - очередь, stack<T> - стек, deque<T> - очередь с двумя концами, priority_queue<T> - очередь, отсортированная по значению, set<T> - множество, multiset<T> - мн-во, в кот одно значение может встречаться несколько раз, map<key,val> - ассоциативный массив, multimap<key,val> - ***, в кот ключ может встречаться несколько раз.

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

В С++ самый простой и очевидный способ охарактеризовать действие – написать функцию. Однако, если действие нужно отложить, если оно требует собственных данных, должно комбинироваться с другими действиями и т.п., то часто хочется оформить его в виде класса, который мог бы выполнить желаемое действие, а также предоставить другие услуги. Очевидным примером такого действия явл объект-функция, использующийся со стандартными алгоритмами, а также манипуляторы, применяемые с потоками iostream. В первом случае собственно действие выполняется применяющимся оператором.

Обычная форма класса-действия – это просто класс, содержащий только одну виртуальную функцию: class Action {public: virtual int do+it(int)=0; virtual ~Action(){};};.

С таким классом мы можем написать код – скажем, меню, - который сможет хранить действия для последующего выполнения, не используя указатели на функции, не имея информации о вызываемых объектах и даже не зная имен вызываемых операций. Например: class Write_file:public Action{ File&f; public: int do_it(int){return f.write().succeed();}}; class Error_response:public Action {//ответ на ошибку; string message; public: int do_it(int);}; int Error_response::do_it(int) {…} Action* actions[]={ //действия; new Write_file(f); new Error_response(“Вам снова не повезло”); //…}.

Пользователь класса Action может совершенно ничего не знать о производных классах, таких как Write_file и Error_response.

При робрті з контейнерами (массиви, стекі, черги, списки…) використ. такі об”єктні ф-іі for_each(ar,ar+10,PrintElem) ; Розпишемо PrintElem.

void PrintElem(int value){cout<<value}.Приклад з використ for_each. template<class InsertIterator,class t>;for_each(InputIterator first, InputIterator last) void (*f)(int value) {while (first!=last); f(*first++)}, викликається для кожного елем. Має такий прототип for_each(l.begin,l.last, PrintElem).розглянемо таку задачу: існує 2 контейнера (масив, список). Якщо елем. більше порога то виконується деяка дія, інакше-ні.

cout<<for_each(ar,ar+10,BI)<<endl; void BI(int value) {return value>1}.Розглянемо ще ф-ю find_if. У даному випадку запис where_ar=find_if(ar,ar+10,BI(n)) невірний, бо параметр треба обчислювати до виклику find_if. існує вирішення проблеми – перевантажимо дужки і BI зробимо ім”ям класу для якого перевантажимо ().

class c {bool (*F)(int testvаl) int testval; public bool (*)() operator()(int val)/*повертає зн-ня покажчика на ф-ю*/ c(bool(*ff)(int n))::f(ff){};

class BI {int testval; public: BI(int n)::testval(*){}}; bool operator (void val) {return val testval}/ Пертворимо ф-ю BI в тип (*f)(int testval) для цього operator bool(*)(int){return * this /* або bool (*)(int)*} Тепер перекреслене можливо.

5

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