Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП.doc
Скачиваний:
77
Добавлен:
07.03.2016
Размер:
1.78 Mб
Скачать

10.2.3 Списки (list)

Список не надає довільного доступу до своїх елементів, зате вставка і видалення виконуються за постійний час. Клас list реалізований в STL у вигляді двохзв’язного списку, кожен вузол якого містить посилання на подальший і попередній елементи. Тому операції інкремента і декремента для ітераторів списку виконуються за постійний час, а пересування на n вузлів вимагає часу, пропорційного n. Після виконання операцій вставки та видалення значення всіх ітераторів і посилань залишаються дійсними. Список підтримує конструктори, операцію привласнення, функцію копіювання, операції порівняння та ітератори, аналогічні векторам і чергам.

Доступ до елементів списків обмежується наступними методами:

reference front();

const_reference front() const;

reference back();

const_reference back() const;

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

void push_front(const Т& value);

void pop_front();

void push_back(const T& value);

void pop_back();

Крім того, діє решта всіх методів для зміни об'єктів list, аналогічні векторам і чергам:

iterator insert(iterator position, const Т& value);

void insert(iterator position,size_type n,const T&value);

template <class InputIter>

void insert(iterator position, Inputlter first,

InputIter last);

iterator erase(iterator position);

iterator erase(iterator first , iterator last);

void swap();

void clear();

Для списку не визначена функція capacity, оскільки пам'ять під елементи відводиться в міру необхідності. Можна змінити розмір списку, видаливши або додавши елементи в кінець списку (аналогічно двосторонній черзі):

void resize(size_type sz, Т с = Т());

Окрім перерахованих, для списків визначено декілька специфічних методів. Зчеплення списків (splice) призначене для переміщення елементів з одного списку в іншій без перерозподілу пам'яті, тільки за рахунок зміни вказівок:

void splice(iterator position, list<T>& x):

void splice(iterator position, list<T>& x, iterator i );

void splice(iterator position, list<T>& x,

iterator first , iterator last);

Обидва списки повинні містити елементи одного типу. Перша форма функції вставляє в список перед елементом, позиція якого вказана першим параметром, всі елементи списку, вказаного другим параметром, наприклад:

list <int> L1, L2;

...

// Формування списків

L1.splice(L1.begin() + 4, L2);

Другий список залишається порожнім. Не можна вставити список в самого себе. Друга форма функції переносить елемент, позицію якого визначає третій параметр, із списку х в список, який викликає функцію. Допускається переносити елемент в межах одного списку. Третя форма функції аналогічним чином переносить із списку в список декілька елементів. Їх діапазон задається третім і четвертим параметрами функції. Якщо для одного і того ж списку перший параметр знаходиться в діапазоні між третім і четвертим, результат не визначений. Приклад:

#include <iostream>

#include <list>

using namespace std;

Void main()

{

list<int> L1;

list<int>::iterator i, j, k;

int m;

for (m = 0; m<5; m++)L1.push_back(m + 1);

for (m = 12; m<14; m++)L1.push_back(m);

cout << "Початковий список:";

for (i = L1.begin(); i != L1.end();++i)

cout << *i << " ";

cout << endl;

i = L1.begin(); i++;

k = L1.end();

j = --k; k++; j -- ;

L1.splice( i, L1, j , k);

cout << "Список після зчеплення:";

for ( i = L1.begin(); i != L1.end(); ++i)

cout << *i << " ";

}

Результат роботи програми:

Початковий список: 1 2 3 4 5 12 13

Список після зчеплення: 1 12 13 2 3 4 5

Для ітераторів списків не визначені операції складання і віднімання, тобто не можна написати j = k 1, тому довелося скористатися допустимими для ітераторів списків операціями інкремента і декремента. У загальному випадку для пошуку елементу в списку використовується функція find().

Для видалення елементу по його значенню застосовується функція remove:

void remove(const Т& value);

Якщо елементів із значенням value в списку декілька, всі вони будуть видалені. Можна видалити із списку елементи, що задовольняють деякій умові.

Для цього використовується функція remove_if():

template <class Predicate>

void remove_if(Predicate pred);

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

Для впорядковування елементів списку використовується метод sort:

void sort();

template <class Compare> void sort(Compare comp);

У першому випадку список сортується за збільшенням елементів (відповідно до визначення операції < для елементів), в другому – відповідно до функціонального об'єкту Compare. Функціональний об'єкт має значення true, якщо два передаваних йому значення повинні при сортуванні залишитися в попередньому порядку, та false – навпаки. Порядок проходження елементів, що мають однакові значення, зберігається. Час сортування пропорційний N*log2n, де N – кількість елементів в списку.

Метод unique() залишає в списку тільки перший елемент з кожної серії тих, що йдуть підряд однакових елементів. Перша форма методу має наступний формат:

void unique();

Друга форма методу unique() використовує як параметр бінарний предикат, що дозволяє задати власний критерій видалення елементів списку. Предикат має значення true, якщо критерій дотриманий, і false – в іншому випадку. Аргументи предиката мають тип елементів списку:

template <class BinaryPredicate>

void unique(BinaryPredicate binary_pred);

Для злиття списків призначений метод merge():

void merge(list<T>& x);

template <class Compare>

void merge(list<T>& x, Compare comp);

Обидва списки мають бути впорядковані (у першому випадку відповідно до визначення операції < для елементів, в другому – відповідно до функціонального об'єкту Compare). Результат – впорядкований список. Якщо елементи в списку, який викликає функцію та в списку-параметрі збігаються, першими розташовуватимуться елементи із списку, який викликає функцію.

Метод reverse() призначений для зміни порядку проходження елементів списку на зворотній:

void reverse();

Приклад.

#include <iostream>

#include <list>

using namespace std;

void show (const char *str, const list<int> &L)

{

cout << str <<":"<< endl;

for (list<int>::const_iterator i = L.begin();

i != L.end(); ++i)

cout << *i <<" ";

cout << endl;

}