← Назад к вопросам
Как сериализовать двунаправленный список?
1.7 Middle🔥 151 комментариев
#Структуры данных и алгоритмы
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Сериализация двунаправленного списка
Двунаправленный список (doubly linked list) содержит указатели как на следующий, так и на предыдущий элемент. При сериализации основная сложность — это циклические ссылки и необходимость восстановить обе связи при десериализации.
Подходы к сериализации
1. Сериализация только значений (рекомендуемый подход)
Сохраняем только данные элементов в порядке обхода, восстанавливаем связи при десериализации:
// Сериализация
void serializeDoublyList(const DoublyLinkedList& list, std::ofstream& file) {
int count = list.size();
file.write(reinterpret_cast<char*>(&count), sizeof(count));
for (const auto& node : list) {
int value = node->data;
file.write(reinterpret_cast<char*>(&value), sizeof(value));
}
}
// Десериализация
void deserializeDoublyList(DoublyLinkedList& list, std::ifstream& file) {
int count;
file.read(reinterpret_cast<char*>(&count), sizeof(count));
for (int i = 0; i < count; ++i) {
int value;
file.read(reinterpret_cast<char*>(&value), sizeof(value));
list.insertBack(value);
}
}
2. JSON сериализация (для обмена данными)
Идеален для JSON API и человеко-читаемого формата:
#include <nlohmann/json.hpp>
using json = nlohmann::json;
json serializeDoublyListJSON(const DoublyLinkedList& list) {
json j = json::array();
for (const auto& node : list) {
j.push_back({
{"value", node->data},
{"index", std::distance(list.begin(),
std::find(list.begin(), list.end(), node))}
});
}
return j;
}
DoublyLinkedList deserializeDoublyListJSON(const json& j) {
DoublyLinkedList list;
for (const auto& item : j) {
list.insertBack(item["value"].get<int>());
}
return list;
}
3. Сохранение структуры с индексами
Если нужна максимальная верность (например, для позиций):
struct SerializedNode {
int data;
int nextIndex; // -1 if nullptr
int prevIndex; // -1 if nullptr
};
void serializeStructured(const DoublyLinkedList& list, std::ofstream& file) {
std::vector<SerializedNode> nodes;
int index = 0;
auto* current = list.getHead();
std::unordered_map<Node*, int> nodeToIndex;
// Первый проход: собираем индексы
while (current) {
nodeToIndex[current] = index++;
current = current->next;
}
// Второй проход: сохраняем данные
current = list.getHead();
while (current) {
SerializedNode sn;
sn.data = current->data;
sn.nextIndex = current->next ? nodeToIndex[current->next] : -1;
sn.prevIndex = current->prev ? nodeToIndex[current->prev] : -1;
nodes.push_back(sn);
current = current->next;
}
int count = nodes.size();
file.write(reinterpret_cast<char*>(&count), sizeof(count));
for (const auto& node : nodes) {
file.write(reinterpret_cast<char*>(&node), sizeof(node));
}
}
Ключевые моменты
- Избегай сохранения указателей напрямую — адреса памяти не сохраняются между сеансами
- Обход только в одном направлении — достаточно для восстановления всей структуры
- Проверь целостность — при десериализации убедись, что связи восстановлены корректно
- Производительность — сохранение только значений быстрее и компактнее
Лучшая практика
Для большинства случаев используй первый подход (сохранение только значений) — это просто, надёжно и эффективно. Сложные варианты нужны только при специфических требованиях (восстановление позиций, кэширование структуры и т.д.).