Ответ
Для создания двусвязного списка из 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;
}
Ключевые моменты реализации:
- Структура узла: Содержит данные и два указателя (
prev,next). - Добавление элемента:
- Создается новый узел.
- Если список пуст, новый узел становится и
head, иtail. - Иначе,
tail->nextсвязывается с новым узлом,newNode->prevсвязывается сtail, иtailобновляется.
- Управление памятью: Критически важно освобождать выделенную память в деструкторе, чтобы избежать утечек. В реальном коде предпочтительнее использовать
std::listили умные указатели.
Ответ 18+ 🔞
Давай разберём эту задачку про двусвязный список, но без занудства, как будто я тебе на кухне объясняю, пока чайник кипит.
Смотри, представь себе цепочку из ста человек, которые держатся за руки. Каждый знает, кто перед ним, и кто за ним. Вот это и есть наш двусвязный список. Задача — собрать такую цепочку из ста узлов, чтобы они все были связаны. Звучит просто, но если накосячить с указателями, получится не цепочка, а какая-то пиздопроебибна, где все друг друга потеряли.
Вот скелет нашего «человечка», то есть узла:
struct ListNode {
int data; // Ну, допустим, у него в кармане лежит цифра
ListNode* prev; // Он тянется левой рукой к предыдущему
ListNode* next; // А правой — к следующему
ListNode(int val) : data(val), prev(nullptr), next(nullptr) {}
};
nullptr — это когда рука висит в воздухе, никого не держит. Сначала все так и будут стоять, одиночки, ёпта.
А теперь самая мякотка — создание ста штук. Делаем класс, который будет всем этим безобразием управлять. У него есть голова (head) — первый в цепочке, и хвост (tail) — последний. Когда добавляем нового, мы его цепляем к хвосту.
Вот как это выглядит в коде, если не выёбываться:
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; // Считаем, сколько нас уже
}
И чтобы создать ровно сто штук, просто вызываем эту функцию в цикле сто раз. Ядрёна вошь, и всё!
Но самое главное, чувак, о чём все вечно забывают — это уборка за собой. Мы же new использовали, память выделяли. Если её не почистить, будет утечка, а это, блядь, как прийти в гости, насрать посреди ковра и смыться. Не комильфо. Поэтому пишем деструктор, который всё подчистит:
~DoublyLinkedList() {
clear();
}
void clear() {
ListNode* curr = head;
while (curr) {
ListNode* next = curr->next; // Запоминаем, кто следующий
delete curr; // Убиваем текущего
curr = next; // Переходим к запомненному
}
head = tail = nullptr;
count = 0;
}
Вот теперь всё чётко. Создали, потыкали, а когда объект списка умрёт (выйдет из области видимости), деструктор вызовется и подчистит всю память. Красота.
Полный код, который делает ровно то, что просили, выглядит так. Я его уже привёл выше, но ты посмотри на него теперь другими глазами — это же просто цепочка людей, которых правильно познакомили. Главное, не перепутать, кого за какую руку держать, а то будет хитрая жопа с доступом к памяти, от которой потом волосы дыбом встанут. Удачи, не облажайся.