Как создать и связать 100 элементов в двусвязном списке на C++?

«Как создать и связать 100 элементов в двусвязном списке на C++?» — вопрос из категории Алгоритмы и структуры данных, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для создания двусвязного списка из 100 элементов нужно последовательно создавать узлы и устанавливать связи next (следующий) и prev (предыдущий) между ними. Вот практическая реализация на C++ с использованием сырых указателей и с учетом управления памятью.

Полный пример:

#include <iostream>

struct ListNode {
    int data;
    ListNode* prev; // Указатель на предыдущий узел
    ListNode* next; // Указатель на следующий узел

    ListNode(int val) : data(val), prev(nullptr), next(nullptr) {}
};

class DoublyLinkedList {
    ListNode* head;
    ListNode* tail;
    size_t count;
public:
    DoublyLinkedList() : head(nullptr), tail(nullptr), count(0) {}

    ~DoublyLinkedList() { // Деструктор для очистки памяти
        clear();
    }

    void push_back(int value) {
        ListNode* newNode = new ListNode(value);
        if (!head) { // Если список пуст
            head = tail = newNode;
        } else { // Добавление в конец
            tail->next = newNode;
            newNode->prev = tail;
            tail = newNode;
        }
        ++count;
    }

    void createListOf100() {
        for (int i = 1; i <= 100; ++i) {
            push_back(i); // Создаем узлы со значениями от 1 до 100
        }
    }

    void traverseForward() const {
        for (ListNode* curr = head; curr != nullptr; curr = curr->next) {
            std::cout << curr->data << " ";
        }
        std::cout << std::endl;
    }

    void traverseBackward() const {
        for (ListNode* curr = tail; curr != nullptr; curr = curr->prev) {
            std::cout << curr->data << " ";
        }
        std::cout << std::endl;
    }

    void clear() {
        ListNode* curr = head;
        while (curr) {
            ListNode* next = curr->next;
            delete curr;
            curr = next;
        }
        head = tail = nullptr;
        count = 0;
    }

    size_t size() const { return count; }
};

int main() {
    DoublyLinkedList list;
    list.createListOf100();

    std::cout << "List size: " << list.size() << std::endl; // 100
    std::cout << "Forward traversal (first 5): ";
    // Для демонстрации выведем только начало
    DoublyLinkedList tempList;
    for (int i = 1; i <= 5; ++i) tempList.push_back(i);
    tempList.traverseForward(); // 1 2 3 4 5

    // Деструктор `list` автоматически освободит всю память
    return 0;
}

Ключевые моменты реализации:

  1. Структура узла: Содержит данные и два указателя (prev, next).
  2. Добавление элемента:
    • Создается новый узел.
    • Если список пуст, новый узел становится и head, и tail.
    • Иначе, tail->next связывается с новым узлом, newNode->prev связывается с tail, и tail обновляется.
  3. Управление памятью: Критически важно освобождать выделенную память в деструкторе, чтобы избежать утечек. В реальном коде предпочтительнее использовать std::list или умные указатели.