不能直接用 std::to_string 序列化指针值,因其返回不可重现的内存地址,无法反序列化还原结构;正确做法是按层序遍历(bfs)序列化节点值与 null 占位符,以保留树的层级和空缺关系。

为什么不能直接用 std::to_string 序列化指针值
二叉树序列化本质是把内存中不连续的节点结构,转成线性、可存储/传输的字符串。有人尝试对每个 TreeNode* 调用 std::to_string,结果得到的是地址数字(如 "140735822123008"),这在反序列化时完全无法还原原始结构——不同进程、甚至同一进程多次运行,地址都不可重现。真正要序列化的不是地址,而是节点值 + 结构关系。
按层序列化(BFS)天然适合表达树的层级与空缺:用 null 占位能明确反映某一层某个位置“本该有节点但实际为空”,这是重建左右子树的关键依据。
如何用 BFS 实现带 null 占位的层序序列化
核心是模拟层序遍历过程,但不跳过空节点;遇到 nullptr 仍入队,并在输出中记为 "null"。需注意终止条件:当队列中只剩 nullptr 时,后续所有 null 都是冗余的,应截断(否则序列无限长)。
- 使用
std::queue<treenode></treenode>辅助遍历 - 每轮取队首,若非空则记录
std::to_string(node->val),并将左右子指针入队;若为空则记录"null",左右子也入队(继续向下探测) - 维护一个
has_non_null标志,在某次出队后发现队列已空或全为nullptr,就停止追加"null" - 最终用逗号拼接,首尾不加空格,例如:
"1,2,3,null,null,4,5"
反序列化时如何避免 stoi 遇到 "null" 崩溃
std::stoi("null") 会抛 std::invalid_argument 异常,必须提前判断字符串内容。更稳妥的做法是:对每个 token 先比对是否等于 "null",是则跳过建节点,否则再调用 stoi。
- 用
std::stringstream或std::getline拆分字符串,得到std::vector<:string></:string> - 第一个 token 构造根节点;后续 token 按 BFS 顺序依次填充左、右子节点
- 用
std::queue<treenode></treenode>缓存已创建但尚未配齐子节点的父节点 - 每次从队列取一个父节点,下一个 token 给左子,再下一个给右子;若 token 是
"null",对应子指针设为nullptr,不入队
为什么反序列化后不能直接用 == 比较两棵树是否相等
TreeNode* 是指针,root1 == root2 只比较地址是否相同,而非结构与值是否一致。测试序列化/反序列化是否正确,必须写递归比较函数:
bool isEqual(TreeNode* a, TreeNode* b) {
if (!a && !b) return true;
if (!a || !b) return false;
return a->val == b->val && isEqual(a->left, b->left) && isEqual(a->right, b->right);
}
另外注意:C++ 中动态分配的节点必须手动 delete,尤其在单元测试频繁构造-销毁时,漏删会导致内存泄漏;建议用智能指针或确保每个测试用例末尾清理。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











