Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
+ООП_Навч_посібник.doc
Скачиваний:
7
Добавлен:
01.07.2025
Размер:
6.58 Mб
Скачать

22.3. Робота з векторами

Одним з контейнерів найширшого призначення є вектор. Клас vector підтримує динамічний масив, який у разі потреби може збільшувати свій розмір. Як уже зазначалося вище, у мові програмування C++ розмір масиву фіксується під час компілювання. І хоча це найефективніший спосіб реалізації масивів, він водночас є і тим самим обмежувачем, оскільки розмір масиву не можна змінювати у процесі виконання програми. Ця проблема розв'язується за допомогою вектора, який у міру потреби забезпечує виділення додаткового об'єму пам'яті. Незважаючи на те, що вектор – це динамічний масив, проте, для доступу до його елементів можна використовувати стандартне позначення індексації масивів.

Вектори є динамічними масивами.

Ось як виглядає шаблонна специфікація для класу vector:

template <class myType, class Allocator = allocator<myType>> class vector

У цьому записі myType – тип даних, що зберігається, а елемент Allocator означає розподільник пам'яті, який за замовчуванням використовує стандартний розподільник. Клас vector має такі конструктори:

explicit vector(const Allocator &a = Allocator());

explicit vector(size_type num|, const myType &val = myType(),

const Allocator &a = Allocator());

vector(const vector<myType, Allocator> &ob);

template <class InIter> vector(InIter start, InIter end,

const Allocator &a = Allocator());

Перша форма конструктора призначена для створення порожнього вектора. Друга створює вектор, який містить num "елементів із значенням val", причому значення val може бути встановлено за замовчуванням. Третя форма дає змогу створити вектор, який містить ті самі елементи, що і заданий вектор ob. Четверта призначена для створення вектора, який містить елементи у діапазоні, заданому параметрами-ітераторами start і end.

Заради досягнення максимальної гнучкості та переносності будь-який об'єкт, який призначено для зберігання у векторі, повинен визначатися конструктором за замовчуванням. Окрім того, він повинен визначати операції "<" і "==". Деякі компілятори можуть зажадати визначення і інших операторів порівняння. (З причини існування різних реалізацій для отримання точної інформації про вимоги, що пред'являються Вашим компілятором, необхідно звернутися до документації, що додається до нього.) Всі вбудовані типи автоматично задовольняють ці вимоги.

Незважаючи на те, що наведений вище синтаксис шаблону виглядає достатньо "масивним", у оголошенні вектора немає нічого складного. Розглянемо декілька прикладів:

vector<int> iv; // Створення вектора нульової довжини для

// зберігання int-значень.

vector<char> cv(5); // Створення 5-елементного вектора для

// зберігання char-значень.

vector<char> cv(5, 'x'); // Ініціалізація 5-елементного

// char-вектора.

vector<int> iv2(iv); // Створення int-вектора на основі

// int-вектора iv.

Для класу vector визначено такі оператори порівняння: ==, <, <=, !=, > і >=.

Для вектора також визначено оператор індексації "[]", який дає змогу отримати доступ до елементів вектора за допомогою стандартного запису з використанням індексів. Функції-члени, визначені у класі vector, перераховані в табл|. 22.2. Найважливішими з них є size(), begin(), end(), push_back(), insert() і erase(). Дуже корисна функція size(), яка повертає поточний розмір вектора, оскільки вона дає змогу визначити розмір вектора у процесі виконання програми.

Необхідно пам'ятати! Вектори у разі потреби збільшують свій розмір, тому потрібно мати можливість визначати його величину під час роботи програми, а не тільки під час компілювання.

Табл. 22.2. Функції-члени, визначені у класі vector

Функція-член

Опис

template <class InIter>

void assign(InIter start,

InIter end);

Поміщає у вектор послідовність, що визначається параметрами start і end

void assign(size_type num,

const myType &val);

Поміщає у вектор num елементів із значенням val

reference at(size_type i); const_reference at(size_type i) const;

Повертає посилання на елементи, які задаються параметром i

reference back();

const_reference back() const;

Повертає посилання на останній елемент у векторі

iterator begin();

const_iterator begin() const;

Повертає ітератор для першого елемента у векторі

size_type capacity() const;

Повертає поточну місткість вектора, або кількість елементів, яка може зберігатися у векторі до того, як виникне потреба у виділенні додаткової пам'яті

void clear();

Видаляє всі елементи з вектора

bool empty() const;

Повертає істинне значення, якщо використовуваний вектор порожній, і помилкове значення інакше

const_iterator end() const; iterator end();

Повертає ітератор для кінця вектора

iterator erase(iterator i);

Видаляє елемент, яка адресується ітератором і; повертає ітератор для елемента, розташованого після видаленого

iterator erase(iterator start, iterator end);

Видаляє елементи у діапазоні, що задається параметрами start і end; повертає ітератор для елемента, розташованого за останнім видаленим елементом

reference front();

const_reference front() const;

Повертає посилання на перший елемент у векторі

allocator_type get_allocator() const;

Повертає розподільник пам'яті вектора

iterator insert(iterator i,

const myType &val = myType());

Вставляє значення val безпосередньо перед елементом, заданим параметром i; повертає ітератор для цього елемента

void insert(iterator i,

size_type num,

const myType &val);

Вставляє num копій значення val безпосередньо перед елементом, заданим параметром i

template <class InIter>

void insert(iterator i,

InIter start, InIter end);

Вставляє у вектор послідовність елементів, що визначаються параметрами start і end, безпосередньо перед елементом, заданим параметром i

size_type max_size() const;

Повертає максимальну кількість елементів, яку може містити вектор

reference operator[](

size_type i) const;

const_reference operator[](

size_type i) const;

Повертає посилання на елементи, які задаються параметром i

void pop_back();

Видаляє останній елемент у векторі

void push_back(const myType &val);

Додає у кінець вектора елемент, значення якого задане параметром val

reverse_iterator rbegin(); const_reverse_iterator rbegin() const;

Повертає реверсивний ітератор для кінця вектора

reverse_iterator rend(); const_reverse_iterator rend() const;

Повертає реверсивний ітератор для початку вектора

void reserve(size_type num);

Встановлює місткість вектора, що дорівнює значенню, не меншому від заданого num

void resize(size_type num,

myType val = myType());

Встановлює розмір вектора, що дорівнює значенню, заданому параметром num. Якщо вектор для цього потрібно подовжити, то в його кінець додаються елементи із значенням, що задається параметром val

size_type size() const;

Повертає поточну кількість елементів у векторі

void swap(deque<myType, Allocator> &ob);

Виконує обмін елементами зухвалого вектора і вектора ob

Функція begin() повертає ітератор, який вказує на початок вектора. Функція end() повертає ітератор, який вказує на кінець вектора. Як вже пояснювалося вище, ітератори подібні до покажчиків, і за допомогою функцій begin() і end() можна отримати ітератори початку і кінця вектора відповідно.

Функція push_back() поміщає задане значення у кінець вектора. У разі потреби довжина вектора збільшується так, щоб він міг прийняти новий елемент. За допомогою функції insert() можна додавати елементи у середину вектора. Окрім того, вектор можна ініціалізувати. У будь-якому випадку, якщо вектор містить елементи, то для доступу до них і їх модифікації можна використовувати засіб індексації масивів. А за допомогою функції erase() можна видаляти елементи з вектора.

Розглянемо короткий приклад, який ілюструє базову поведінку вектора.

Код програми 22.1. Демонстрація базової поведінки вектора

#include <iostream> // Для потокового введення-виведення

#include <vector> // Для роботи контейнерним класом "Вектор"

using namespace std; // Використання стандартного простору імен

int main()

{

vector<int> vek; // Створення вектора нульової довжини

unsigned int i;

// Відображаємо початковий розмір вектора vek.

cout << "Розмір = " << vek.size() << endl;

/* Поміщаємо значення у кінець вектора, і розмір

вектора за потреби збільшуватиметься. */

for(i=0; i<10; i++) vek.push_back(i);

// Відображаємо поточний розмір вектора vek.

cout << "Новий розмір = " << vek.size() << endl;

// Відображаємо вміст вектора.

cout << "Поточний вміст:\n";

for(i=0; i<vek.size(); i++) cout << vek[i] << " ";

cout << endl;

/* Поміщаємо у кінець вектора нові значення, і розмір

вектора за потреби збільшуватиметься. */

for(i=0; i<10; i++) vek.push_back(i + 10);

// Відображаємо поточний розмір вектора vek.

cout << "Новий розмір = " << vek.size() << endl;

// Відображаємо новий вміст вектора.

cout << "Новий вміст:\n";

for(i=0; i<vek.size(); i++) cout << vek[i] << " ";

cout << endl;

// Змінюємо вміст вектора.

for(i=0; i<vek.size(); i++) vek[i] = vek[i] + vek[i];

// Відображаємо вміст вектора.

cout << "Вміст подвоєно:\n";

for(i=0; i<vek.size(); i++) cout << vek[i] << " ";

cout << endl;

getch(); return 0;

}

Результати виконання цієї програми є такими:

Розмір = 0

Новий розмір = 10

Поточний вміст:

0 1 2 3 4 5 6 7 8 9

Новий розмір =20

Новий вміст:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Вміст подвоєно:

0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38

Розглянемо уважно код цієї програми. У функції main() створюється вектор vek для зберігання int-елементів. Оскільки під час його створення не було передбачено ніякої ініціалізації, то вектор vek вийшов порожнім, а його місткість дорівнює нулю. Іншими словами, ми створили вектор нульової довжини. Це підтверджується викликом функції-члена класу size(). Потім, використовуючи функцію-члена push_back(), у кінець цього вектора ми поміщаємо 10 елементів, що примушує вектор збільшитися в розмірі, щоб розмістити нові елементи. Тепер розмір вектора став таким, що дорівнює 10. Звернемо Вашу увагу на те, що для відображення вмісту вектора vek використовується стандартний запис індексації масивів. Після цього у вектор додаються ще 10 елементів, і вектор vek автоматично збільшується в розмірі, щоб і їх прийняти на зберігання. Нарешті, використовуючи знову-таки стандартний запис індексації масивів, ми змінюємо значення елементів вектора vek.

Зверніть також увагу на те, що для керування циклами, які використовуються для відображення вмісту вектора vek і його модифікації, як ознака їх завершення застосовується значення розміру вектора, що отримується за допомогою функції vek.size(). Одна з переваг векторів перед масивами полягає у тому, що у нас є змога дізнатися поточний розмір вектора, який у певних ситуаціях є дуже корисним засобом.