Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих (Стенли Липпман) 3-е хххх.pdf
Скачиваний:
85
Добавлен:
30.05.2015
Размер:
5.92 Mб
Скачать

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

68

int main() {

const int size = 1024; Array<String> as (size); List<int> il (size);

// ...

Array<String> *pas = new Array<String>(as);

List<int> *pil = new List<int>(il);

print (*pas);

}

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

(a)квалифицированные имена

(b)селективную директиву using

(c)механизм псевдонимов

(d)директиву using

2.8. Стандартный массив это вектор

Хотя встроенный массив формально и обеспечивает механизм контейнера, он, как мы видели выше, не поддерживает семантику абстракции контейнера. До принятия стандарта C++ для программирования на таком уровне мы должны были либо приобрести нужный класс, либо реализовать его самостоятельно. Теперь же класс массива является частью стандартной библиотеки C++. Только называется он не массив, а вектор.

Разумеется, вектор реализован в виде шаблона класса. Так, мы можем написать

vector<int> ivec(10); vector<string> svec(10);

Есть два существенных отличия нашей реализации шаблона класса Array от реализации шаблона класса vector. Первое отличие состоит в том, что вектор поддерживает как присваивание значений существующим элементам, так и вставку дополнительных элементов, то есть динамически растет во время выполнения, если программист решил воспользоваться этой его возможностью. Второе отличие более радикально и отражает существенное изменение парадигмы проектирования. Вместо того чтобы поддержать большой набор операций-членов, применимых к вектору, таких, как sort(), min(), max(), find()и так далее, класс vector предоставляет минимальный набор: операции сравнения на равенство и на меньше, size() и empty(). Более общие операции, перечисленные выше, определены как независимые обобщенные алгоритмы.

Для использования класса vector мы должны включить соответствующий заголовочный файл.

#include <vector>

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

69

// разные способы создания объектов типа vector vector<int> vec0; // пустой вектор

const int size = 8; const int value = 1024;

//вектор размером 8

//каждый элемент инициализируется 0 vector<int> vec1(size);

//вектор размером 8

//каждый элемент инициализируется числом 1024 vector<int> vec2(size,value);

//вектор размером 4

//инициализируется числами из массива ia

int ia[4] = { 0, 1, 1, 2 }; vector<int> vec3(ia,ia+4);

// vec4 - копия vec2

vector<int> vec4(vec2);

Так же, как наш класс Array, класс vector поддерживает операцию доступа по индексу.

#include <vector>

Вот пример перебора всех элементов вектора: extern int getSize();

void mumble()

{

int size = getSize(); vector<int> vec(size);

for (int ix=0; ix<size; ++ix) vec[ix] = ix;

// ...

}

Для такого перебора можно также использовать итераторную пару. Итератор это объект класса, поддерживающего абстракцию указательного типа. В шаблоне класса vector определены две функции-члена begin() и end(), устанавливающие итератор соответственно на первый элемент вектора и на элемент, который следует за последним. Вместе эти две функции задают диапазон элементов вектора. Используя итератор,

#include <vector>

предыдущий пример можно переписать таким образом: extern int getSize();

void mumble()

{

int size = getSize(); vector<int> vec(size);

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

70

vector<int>::iterator iter = vec.begin();

for (int ix=0; iter!=vec.end(); ++iter, ++ix) *iter = ix;

// ...

}

Определение переменной iter

vector<int>::iterator iter = vec.begin();

инициализирует ее адресом первого элемента вектора vec. iterator определен с помощью typedef в шаблоне класса vector, содержащего элементы типа int. Операция

инкремента

++iter

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

*iter

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

алгоритмы поиска: find(), find_if(), search(), binary_search(), count(), count_if();

алгоритмы сортировки и упорядочения: sort(), partial_sort(), merge(), partition(), rotate(), reverse(), random_shuffle();

алгоритмы удаления: unique(), remove();

численные алгоритмы: accumulate(), partial_sum(), inner_product(), adjacent_difference();

алгоритмы генерации и изменения последовательности: generate(), fill(), transform(), copy(), for_each();

алгоритмы сравнения: equal(), min(), max().

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

sort ( ivec.begin(), ivec.end() );

Чтобы применить алгоритм sort() только к первой половине вектора, мы напишем:

sort ( ivec.begin(), ivec.begin() + ivec.size()/2 );

Роль итераторной пары может играть и пара указателей на элементы встроенного массива. Пусть, например, нам дан массив:

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

71

int ia[7] = { 10, 7, 9, 5, 3, 7, 1 };

Упорядочить весь массив можно вызовом алгоритма sort():

sort ( ia, ia+7 );

Так можно упорядочить первые четыре элемента:

sort ( ia, ia+4 );

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

#include <algorithm>

Ниже приведен пример программы, использующей разнообразные алгоритмы в применении к объекту типа vector:

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

 

72

#include <vector>

 

 

#include <algorithm>

 

 

#include <iostream>

 

 

int ia[ 10 ] = {

 

 

51, 23, 7, 88, 41, 98, 12, 103, 37, 6

 

};

 

 

int main()

 

 

{

 

 

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

end_it = vec.end();

vector<int>::iterator

it = vec.begin(),

cout << "Начальный массив: ";

 

for ( ; it != end_it; ++ it ) cout << *it << ' ';

cout << "\n";

 

 

// сортировка массива

 

 

sort( vec.begin(), vec.end() );

 

cout << "упорядоченный массив: ";

 

it = vec.begin(); end_it = vec.end();

 

for ( ; it != end_it; ++ it ) cout << *it << ' ';

cout << "\n\n";

 

 

int search_value;

cout << "Введите значение для поиска: "; cin >> search_value;

// поиск элемента vector<int>::iterator found;

found = find( vec.begin(), vec.end(), search_value );

if ( found != vec.end() )

cout << "значение найдено!\n\n"; else cout << "значение найдено!\n\n";

// инвертирование массива reverse( vec.begin(), vec.end() );

cout << "инвертированный массив: "; it = vec.begin(); end_it = vec.end();

for ( ; it != end_it; ++ it ) cout << *it << ' '; cout << endl;

}

Стандартная библиотека С++ поддерживает и ассоциативные массивы. Ассоциативный массив это массив, элементы которого можно индексировать не только целыми числами, но и значениями любого типа. В терминологии стандартной библиотеки ассоциативный массив называется отображением (map). Например, телефонный справочник может быть представлен в виде ассоциативного массива, где индексами

#include <map>

служат фамилии абонентов, а значениями элементов телефонные номера:

#include <string>

#include "TelephoneNumber.h"

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

73

map<string, telephoneNum> telephone_directory;

(Классы векторов, отображений и других контейнеров в подробностях описываются в главе 6. Мы попробуем реализовать систему текстового поиска, используя эти классы. В главе 12 рассмотрены обобщенные алгоритмы, а в Приложении приводятся примеры их использования.)

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

Упражнение 2.22

string pals[] = {

"pooh", "tiger", "piglet", "eeyore", "kanga" };

(a)vector<string> svec1(pals,pals+5);

(b)vector<int> ivec1(10);

(c)vector<int> ivec2(10,10);

(d)vector<string> svec2(svec1);

(e)vector<double> dvec;

Поясните результаты каждого из следующих определений вектора:

Упражнение 2.23

Напишите две реализации функции min(), объявление которой приведено ниже. Функция должна возвращать минимальный элемент массива. Используйте цикл for и

перебор элементов с помощью

индекса

template <class elemType>

итератора

elemType min (const vector<elemType> &vec);