std::list in C++ з прикладом

⚡ Розумний підсумок

std::list in C++ — це контейнер послідовностей, реалізований у вигляді двозв'язаного списку, що дозволяє швидку вставку та видалення в будь-якій позиції, зберігаючи елементи в несуміжній пам'яті та підтримуючи двонаправлений послідовний доступ замість випадкового доступу.

  • 🔗 Двозв'язаний список: Кожен елемент зберігає посилання на свій попередній та наступний вузол, тому дані std::list зберігаються в несуміжній пам'яті.
  • Швидке вставлення та видалення: Додавання або видалення елемента у відомій позиції відбувається за постійний час, на відміну від вектора, який зміщує елементи.
  • 🚫 Без випадкового доступу: Досягнення елементів здійснюється послідовним обходом з будь-якого кінця, тому індексація, така як list[3], недоступна.
  • 🧩 Конструктори: Конструктори за замовчуванням, заповнення, діапазону, копіювання, переміщення та списку ініціалізаторів будують std::list по-різному.
  • 🛠️ Функції членів: Функції push_front(), push_back(), insert(), erase(), size(), reverse() та merge() керують вмістом списку.
  • 🤖 Допомога AI: GitHub Copilot та подібні помічники створюють скам'якування оголошень std::list, ітераторів, а також вставляють або видаляють логіку з короткого коментаря.

std::list in C++

Що таке std::list?

In C++, std::list посилається на контейнер сховища. std::list дозволяє вставляти та видаляти елементи з будь-якого місця. std::list реалізовано як подвійно зв'язаний список. Це означає, що до даних списку можна отримати доступ двонаправлено та послідовно.

Список стандартної бібліотеки шаблонів не підтримує швидкий довільний доступ, але підтримує послідовний доступ з усіх напрямків.

Ви можете розкидати елементи списку по різних фрагментах пам’яті. Інформація, необхідна для послідовного доступу до даних, зберігається в контейнері. Під час виконання std::list може розширюватися та звужуватися з обох кінців. Внутрішній розподільник автоматично виконує вимоги до сховища.

Ці риси викликають практичне питання: коли насправді варто звернутися до списку?

Навіщо використовувати std::list?

Ось причини використання std::list:

  • std::list працює краще порівняно з іншими контейнерами послідовностей, такими як масиви та вектори.
  • Вони мають кращу продуктивність у вставлянні, переміщенні та вилученніtracелементи з будь-якого положення.
  • std::list також краще працює з алгоритмами, які інтенсивно виконують такі операції.

Зрозумівши причини, наступним кроком є ​​синтаксис оголошення одиниці.

Синтаксис списку

Щоб визначити std::list, нам потрібно імпортувати файл заголовка. Ось синтаксис визначення std::list:

template < class Type, class Alloc =allocator<T> > class list;

Ось опис наведених вище параметрів:

  • T – Визначає тип елемента, що міститься. Ви можете замінити T будь-яким типом даних, навіть типами, визначеними користувачем.
  • Alloc – Визначає тип об'єкта розподільника пам'яті. За замовчуванням використовується шаблон класу розподільника. Він залежить від значення та використовує просту модель розподілу пам'яті.

Приклад 1

#include <algorithm>
#include <iostream>
#include <list>
int main() {
	std::list<int> my_list = { 12, 5, 10, 9 };

	for (int x : my_list) {
		std::cout << x << '\n';
	}
}

вихід:

Вивід прикладу створення та ітерації std::list

Ось скріншот коду:

C++ код, що створює std::list та виводить його за допомогою циклу for

Code Пояснення:

  1. Включіть файл заголовка алгоритму, щоб використовувати його функції.
  2. Включіть файл заголовка iostream, щоб використовувати його функції.
  3. Включіть файл заголовка списку, щоб використовувати його функції.
  4. Виклик функції main(). Логіку програми слід додати в тіло цієї функції.
  5. Створіть список із назвою my_list із набором із 4 цілих чисел.
  6. Використовувати для петлі створити змінну циклу x. Ця змінна буде використовуватися для ітерації по елементах списку.
  7. Роздрукуйте значення списку на консолі.
  8. Кінець тіла циклу for.
  9. Кінець тіла функції main().

C++ Список функцій

Ось типові функції std::list:

функція Опис
вставити () Ця функція вставляє новий елемент перед позицією, на яку вказує ітератор.
відсунути() Ця функція додає новий елемент у кінець списку.
push_front() Він додає новий елемент на початку списку.
pop_front() Він видаляє перший елемент списку.
розмір () Ця функція визначає кількість елементів списку.
фронт() Щоб визначити перші пункти списку.
назад() Щоб визначити останній пункт списку.
зворотний() Він перевертає елементи списку.
merge () Він об’єднує два відсортовані списки.

Конструктори

Ось список Функції надані файл заголовка:

  • Конструктор за замовчуванням std::list::list() - створює порожній список із нульовими елементами.
  • Конструктор заповнення std::list::list() - створює список із n елементів і присвоює значення нуль (0) кожному елементу.
  • Конструктор діапазону std::list::list() - створює список із багатьма елементами в діапазоні від першого до останнього.
  • Конструктор копіювання std::list::list() - створює список із копією кожного елемента, що міститься в існуючому списку.
  • Конструктор переміщення std::list::list() - створює список з елементами іншого списку за допомогою семантики переміщення.
  • Конструктор списку ініціалізатора std::list::list() – створює список з елементами іншого списку за допомогою семантики переміщення.

Приклад 2

#include <iostream>
#include <list>
using namespace std;
int main(void) {
	list<int> l;
	list<int> l1 = { 10, 20, 30 };
	list<int> l2(l1.begin(), l1.end());
	list<int> l3(move(l1));  
	cout << "Size of list l: " << l.size() << endl;
	cout << "List l2 contents: " << endl;
	for (auto it = l2.begin(); it != l2.end(); ++it)
	      cout << *it << endl;
	cout << "List l3 contents: " << endl;
	for (auto it = l3.begin(); it != l3.end(); ++it)
		cout << *it << endl;
	return 0;
}

вихід:

Вивід прикладу конструкторів std::list

Ось скріншот коду:

C++ код, що демонструє конструктори std::list за замовчуванням, range та move

Code Пояснення:

  1. Включіть файл заголовка iostream, щоб використовувати його функції.
  2. Включіть файл заголовка списку, щоб використовувати його функції.
  3. Включіть простір імен std у код, щоб використовувати його класи без його виклику.
  4. Виклик функції main(). Логіку програми слід додати в тіло цієї функції.
  5. Створіть порожній список з іменем l.
  6. Створіть список із назвою l1 із набором із 3 цілих чисел.
  7. Створіть список під назвою l2 з усіма елементами списку під назвою l1 від початку до кінця.
  8. Створіть список під назвою l3, використовуючи семантику переміщення. Список l3 матиме той самий вміст, що й список l2.
  9. Надрукуйте розмір списку з назвою l на консолі поряд з іншим текстом.
  10. Надрукуйте текст на консолі.
  11. Створіть ітератор з іменем it і використовуйте його для повторення елементів списку з іменем l2.
  12. Вивести на консоль елементи списку з іменем l2.
  13. Надрукуйте текст на консолі.
  14. Створіть ітератор з іменем it і використовуйте його для повторення елементів списку з іменем l3.
  15. Вивести на консоль елементи списку з іменем l3.
  16. Після успішного завершення програма повинна повернути значення.
  17. Кінець тіла функції main().

Властивості контейнерів

Ось список властивостей контейнера:

властивість Опис
Послідовність Контейнери послідовності впорядковують свої елементи в строгій лінійній послідовності. Доступ до елементів здійснюється за їхньою позицією в послідовності.
Двозв'язний список Кожен елемент містить інформацію про те, як знайти попередні та наступні елементи. Це забезпечує постійний час для операцій вставки та видалення.
Розподільник Об’єкт розподільника використовується для динамічної зміни розміру сховища.

Вставлення в список

Існують різні функції, які ми можемо використовувати для вставки значень у список. Давайте продемонструємо це:

Приклад 3

#include <algorithm>
#include <iostream>
#include <list>
int main() {
	std::list<int> my_list = { 12, 5, 10, 9 };
	my_list.push_front(11);
	my_list.push_back(18);
	auto it = std::find(my_list.begin(), my_list.end(), 10);
	if (it != my_list.end()) {
		my_list.insert(it, 21);
	}
	for (int x : my_list) {
		std::cout << x << '\n';
	}
}

вихід:

Вивід після вставки елементів у std::list

Ось скріншот коду:

C++ код з використанням push_front, push_back та вставки в std::list

Code Пояснення:

  1. Включіть файл заголовка алгоритму, щоб використовувати його функції.
  2. Включіть файл заголовка iostream, щоб використовувати його функції.
  3. Включіть файл заголовка списку, щоб використовувати його функції.
  4. Виклик функції main(). Логіку програми слід додати в тіло цієї функції.
  5. Створіть список із назвою my_list із набором із 4 цілих чисел.
  6. Вставте елемент 11 на початку списку з назвою my_list.
  7. Вставте елемент 18 у кінець списку з назвою my_list.
  8. Створіть його ітератор і за допомогою нього знайдіть елемент 10 зі списку my_list.
  9. Використовуйте оператор if, щоб визначити, чи знайдено вищевказаний елемент чи ні.
  10. Вставте елемент 21 перед елементом вище, якщо він знайдений.
  11. Кінець тіла оператора if.
  12. Використовуйте цикл for, щоб створити змінну циклу x. Ця змінна буде використовуватися для перебору елементів списку.
  13. Роздрукуйте значення списку на консолі.
  14. Кінець тіла петлі for.
  15. Кінець тіла функції main().

Елементи, які входять до списку, можна так само легко видалити.

Видалення зі списку

Ви можете видаляти елементи зі списку. Функція erase() дозволяє видалити елемент або діапазон елементів зі списку.

  • Щоб видалити окремий елемент, ви просто передаєте одну цілу позицію. Елемент буде видалено.
  • Щоб видалити діапазон, потрібно передати початковий та кінцевий ітератори. Давайте продемонструємо це.

Приклад 4

#include <algorithm>
#include <iostream>
#include <list>
using namespace std;
int main() {
	std::list<int> my_list = { 12, 5, 10, 9 };
	cout << "List elements before deletion: ";
	for (int x : my_list) {
		std::cout << x << '\n';
	}
	list<int>::iterator i = my_list.begin();
	my_list.erase(i);
	cout << "\nList elements after deletion: ";
	for (int x : my_list) {
		std::cout << x << '\n';
	}
	return 0;
}

вихід:

Вивід після видалення елемента зі std::list

Ось скріншот коду:

C++ код з використанням функції erase на std::list

Code Пояснення:

  1. Включіть файл заголовка алгоритму, щоб використовувати його функції.
  2. Включіть файл заголовка iostream, щоб використовувати його функції.
  3. Включіть файл заголовка списку, щоб використовувати його функції.
  4. Включіть простір імен std у нашу програму, щоб використовувати його класи без його виклику.
  5. Виклик функції main(). Логіку програми слід додати в тіло цієї функції.
  6. Створіть список із назвою my_list із набором із 4 цілих чисел.
  7. Надрукуйте текст на консолі.
  8. Використовуйте цикл for, щоб створити змінну циклу x. Ця змінна буде використовуватися для перебору елементів списку.
  9. Роздрукуйте значення списку на консолі.
  10. Кінець тіла циклу for.
  11. Створіть ітератор i, який вказує на перший елемент списку.
  12. Використовуйте функцію erase(), на яку вказує ітератор i.
  13. Надрукуйте текст на консолі.
  14. Використовуйте цикл for, щоб створити змінну циклу x. Ця змінна буде використовуватися для перебору елементів списку.
  15. Роздрукуйте значення списку на консолі. Це відбувається після видалення.
  16. Кінець тіла циклу for.
  17. Після успішного завершення програма повинна повернути значення.
  18. Кінець тіла функції main().

Поширені запитання

std::vector зберігає елементи в безперервній пам'яті з довільним доступом O(1), тоді як std::list — це двозв'язаний список, що забезпечує O(1) вставок або видалення будь-де. Виберіть vector для індексації, а list для частих вставок посередині.

Ні. std::list не має оператора довільного доступу, тому list[2] не компілюється. Ви досягаєте елемента, ітеруючи від begin() або end() по одному вузлу за раз, що вимагає лінійного часу O(n) для глибокої позиції.

std::list — це двозв'язний список, який переміщується в обох напрямках і підтримує push_back. std::forward_list — це однозв'язний список, який переміщується лише вперед, використовує менше пам'яті на вузол і не надає size() або reverse ітераторів.

Викличте функцію-член my_list.sort(), яка виконується приблизно за N log N та стабільно зберігає рівні елементи. Алгоритм std::sort не працюватиме, оскільки йому потрібні ітератори з довільним доступом. Передайте std::greater до sort() для упорядкування за спаданням.

Вставка або видалення вузла займає константний час O(1) після того, як ви утримуєте ітератор на позиції, оскільки змінюються лише сусідні вказівники. Пошук цієї позиції першим шляхом обходу все ще коштує O(n) часу.

Так. std::list не є множиною, тому він вільно зберігає повторювані значення. Кожне push_back, push_front або insert додає новий вузол незалежно від існуючого вмісту. Використовуйте std::set, коли вам потрібно відхилити дублікати елементів.

Так. Копілот GitHub записує оголошення std::list, цикли ітераторів та вставляє або видаляє виклики з короткого коментаря або назви функції. Часто пропонується std::vector, коли безперервне сховище краще підходить для завдання.

Помічники ШІ-кодування автоматично завершують код STL-контейнера, позначають неправильне використання ітератора, конвертують std::list у std::vector та пояснюють компроміси складності. Вони пришвидшують вивчення STL, хоча кожна пропозиція все ще потребує перегляду.

Підсумуйте цей пост за допомогою: