You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于左孩子右兄弟表示法构建N叉树:文件键写入疑问

左孩子右兄弟N叉树的文件键值读写方案

嘿,先帮你指出结构体里的一个关键小bug——你的构造函数里把参数和成员变量的赋值写反了!应该是siblingsNumber = siblingsNr;而不是siblingsNr = siblingsNumber;,不然你的siblingsNumber根本没被正确初始化,后续操作肯定会出问题。先修正这个,咱们再聊文件读写的事。

1. 修正后的Node结构体

首先给你一个更健壮的结构体版本,加上析构函数防止内存泄漏,同时初始化siblings数组的元素为nullptr避免野指针:

#include <iostream>
#include <fstream>

struct Node {
    int data;
    int siblingsNumber;
    Node *LeftChild;
    Node **siblings;

    // 修正构造函数的赋值逻辑,初始化成员
    Node(int key, int siblingsNr) : data(key), siblingsNumber(siblingsNr), LeftChild(nullptr) {
        siblings = new Node*[siblingsNr];
        // 初始化所有兄弟指针为nullptr
        for (int i = 0; i < siblingsNr; ++i) {
            siblings[i] = nullptr;
        }
    }

    // 析构函数:递归释放所有子节点和兄弟节点的内存
    ~Node() {
        delete LeftChild; // 释放左孩子
        for (int i = 0; i < siblingsNumber; ++i) {
            delete siblings[i]; // 释放每个兄弟节点
        }
        delete[] siblings; // 释放兄弟数组
    }
};

2. 将树的键值写入文件

左孩子右兄弟结构适合用先序遍历来写入文件,因为先访问父节点,再遍历左子树,最后依次遍历所有兄弟节点。写入时需要记录每个节点的data和siblingsNumber,这样读取时才能正确分配兄弟数组。

写入函数实现

// 递归写入树到文件
void writeTreeToFile(Node* root, std::ofstream& outFile) {
    if (!root) return;

    // 写入当前节点的data和兄弟数量,用空格分隔
    outFile << root->data << " " << root->siblingsNumber << "\n";

    // 先写入左子树
    writeTreeToFile(root->LeftChild, outFile);

    // 依次写入每个兄弟节点
    for (int i = 0; i < root->siblingsNumber; ++i) {
        writeTreeToFile(root->siblings[i], outFile);
    }
}

// 调用示例
int main() {
    // 构建一棵示例N叉树
    Node* root = new Node(1, 0); // 根节点,无兄弟
    root->LeftChild = new Node(2, 1); // 根的左孩子,有1个兄弟
    root->LeftChild->siblings[0] = new Node(3, 0); // 节点2的兄弟节点3
    root->LeftChild->LeftChild = new Node(4, 0); // 节点2的左孩子

    // 打开文件准备写入
    std::ofstream outFile("tree_keys.txt");
    if (outFile.is_open()) {
        writeTreeToFile(root, outFile);
        outFile.close();
        std::cout << "树的键值已成功写入文件!\n";
    } else {
        std::cerr << "无法打开文件进行写入!\n";
    }

    delete root; // 释放所有内存
    return 0;
}

执行后,tree_keys.txt的内容会是:

1 0
2 1
4 0
3 0

3. 从文件读取键值构建树

读取时同样用先序遍历的递归逻辑,按照写入的顺序依次读取每个节点的data和siblingsNumber,然后创建节点、递归构建左子树和兄弟节点。

读取函数实现

// 递归从文件读取并构建树
Node* readTreeFromFile(std::ifstream& inFile) {
    int data, siblingsNr;
    // 如果文件已读完,返回nullptr
    if (!(inFile >> data >> siblingsNr)) {
        return nullptr;
    }

    // 创建当前节点
    Node* node = new Node(data, siblingsNr);

    // 先构建左子树
    node->LeftChild = readTreeFromFile(inFile);

    // 依次构建每个兄弟节点
    for (int i = 0; i < siblingsNr; ++i) {
        node->siblings[i] = readTreeFromFile(inFile);
    }

    return node;
}

// 调用示例
int main() {
    std::ifstream inFile("tree_keys.txt");
    Node* root = nullptr;

    if (inFile.is_open()) {
        root = readTreeFromFile(inFile);
        inFile.close();
        std::cout << "已从文件读取并构建树!\n";
    } else {
        std::cerr << "无法打开文件进行读取!\n";
    }

    // 验证:先序遍历打印树
    auto printTree = [](auto&& self, Node* node) -> void {
        if (!node) return;
        std::cout << node->data << " ";
        self(self, node->LeftChild);
        for (int i = 0; i < node->siblingsNumber; ++i) {
            self(self, node->siblings[i]);
        }
    };
    printTree(printTree, root); // 输出:1 2 4 3 

    delete root; // 释放内存
    return 0;
}

关键注意事项

  • 构造函数的赋值错误:一定要修正siblingsNumber = siblingsNr,否则兄弟数组的大小会是随机值,直接导致程序崩溃。
  • 内存泄漏:必须添加析构函数,递归释放所有节点和数组内存,否则会造成内存泄漏。
  • 文件格式一致性:写入和读取的格式必须严格对应,比如每个节点的两个值用空格分隔,每行一个节点,这样读取时才能正确解析。
  • 空节点处理:如果你的树中有空的左孩子或兄弟节点,写入时不会记录这些空节点,读取时会自动跳过,不需要额外处理。

内容的提问来源于stack exchange,提问作者Mareș Ștefan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:17:36