【问题标题】:Insert nodes in expression trees在表达式树中插入节点
【发布时间】:2013-06-20 14:13:29
【问题描述】:

我正在尝试使用二叉树评估表达式。树有这样的特点:

  • 每个节点都有零个、一个或两个子节点。
  • 只有包含运算符的节点可以有子节点。
  • 所有叶节点必须是数字。
  • 为简单起见,唯一允许的运算符是*+

类似那些:

这是我的树类:

class ExpressionTree {
    struct Node {
        std::string data;

        Node *leftChild, *rightChild;

        Node(std::string d): data(d), leftChild(NULL), rightChild(NULL) {}
    } *root;
    uint tsize;
public:
    ExpressionTree(): root(NULL), tsize(0) {}
    Node* treeRoot() { return root; }
    void insert(std::string s);
};

这是我的插入函数:

void insert(std::string s) {
    if (root == NULL) {
        root = new Node(s);
        ++tsize;
    } else {
        Node* current = root;
        while (true) {
            if (is_operator(current->data)) {
                if (current->leftChild == NULL) {
                    current->leftChild = new Node(s);
                    ++tsize;
                    return;
                } else if (current->rightChild == NULL) {
                    current->rightChild = new Node(s);
                    ++tsize;
                    return;
                } else {
                    if (is_operator(current->leftChild->data)) {
                        current = current->leftChild;
                        continue;
                    } else if (is_operator(current->rightChild->data)) {
                        current = current->rightChild;
                        continue;
                    } else {
                        std::cout << "Error: only nodes who hold operators"
                                  << " can have children." << std::endl;
                        return;
                    }
                }
            }
        }
    }
}

问题出在这个函数上。我从一个在二叉搜索树中插入节点的函数开始编写它,但它不起作用。当我运行一个简单的主程序(使用insert(),一次添加第二棵树的节点)时,它崩溃而没有返回任何错误,只有一个要求检查在线解决方案的Windows 7对话框em>。

我认为主要问题是它没有检查树的所有元素,而只检查一个分支,因此它以非法方式附加新节点。不幸的是,我不知道如何解决这个问题。

希望这个问题不要太具体。

注意:is_operator() 接受一个字符串,如果是 ++,则返回 true,否则返回 false。

【问题讨论】:

  • “它会崩溃而不返回任何错误,只有一个要求检查在线解决方案的 Windows 7 对话框”您是否通过调试器运行了您的程序?您可以更准确地了解崩溃的来源。
  • Overflowh:关于这个问题有什么消息吗?
  • @Dr_Sam:嗯,不全是好消息。插入函数现在可以加载图像左侧的小树(我将 else 添加到主 if 以检查嵌套中的错误)。问题在于加载第一棵树(更大的树)。我不知道插入算法是否没有遍历树的所有分支,或者我是否以错误的方式插入值。我添加了一个 print() 函数来检查树是否正确加载。无论如何,现在这个问题被标记为“过于本地化”(我想知道谁决定了多少是“太”),所以它不再重要了。

标签: c++ list expression-trees


【解决方案1】:

我认为我发现了两个问题。

(A)

假设您尝试进入图片右侧的树。您已经在顶部输入了*,在下面输入了*+。您还输入了7121

现在你想输入12,这就是你的代码失败的地方。

根是一个运算符,两个孩子都不为空,所以你进入“else”子句并将左孩子视为当前位置。但是这部分已经被填满了!所以你将无法在那里插入任何东西。

但不确定这是唯一的错误,因为您应该会看到显示的错误消息。

(B)

我认为,如果您从树的数字开始(而不是使用运算符),则在尝试插入叶子时会进入无限循环并且看不到显示的消息(如果总是失败,则第一个)

【讨论】:

    【解决方案2】:

    可以解决问题,为类添加跟踪每个节点的 parent 节点的可能性。这里是新类:

    class ExpressionTree {
        struct Node {
        std::string data;
    
            Node *leftChild, *rightChild;
            Node* parent; // +
    
            Node(std::string d, Node* p):
            data(d), leftChild(NULL), rightChild(NULL), parent(p) {}
        } *root;
    uint tsize;
    public:
        ExpressionTree(): root(NULL), tsize(0) {}
        Node* treeRoot() { return root; }
        void insert(std::string s);
    };
    

    与前一个的唯一区别是添加了另一个Node* 数据成员。这将存储指向父节点的指针,从而可以向后遍历树。

    insert() 函数也需要一些修改。这里是:

    void insert(std::string s) {
        if (root == NULL) {
            root = new Node(s, NULL);
            ++tsize;
        } else {
            Node* current = root;
            while (true) {
                if (is_operator(current->data)) {
                    if (current->leftChild == NULL) {
                        current->leftChild = new Node(s, current);
                        ++tsize;
                        return;
                    } else if (current->rightChild == NULL) {
                        current->rightChild = new Node(s, current);
                        ++tsize;
                        return;
                    } else {
                        if (is_operator(current->leftChild->data)) {
                            current = current->leftChild;
                            continue;
                        } else if (is_operator(current->rightChild->data)) {
                            current = current->rightChild;
                            continue;
                        } else {
                            current = current->parent->rightChild; // +
                            continue;
                        }
                    }
                } else {
                    std::cout << "Error: only nodes who hold operators "
                              << "can have children." << std::endl;
                    return;
                }
            }
        }
    }
    

    与之前版本的不同之处在于:在while 内的主if 中添加了一个else 语句,以在所有叶节点都是数字的情况下中断循环(这意味着它们不能有子节点) [1] 以及前一个 else 的替换(由 // + 指定),其赋值使 光标 向后移动到当前光标的父节点。

    此外,构造函数Node() 也进行了修改:每次创建新节点时,都会将其与其父节点链接,并传递父节点的指针和第二个参数。

    最后一件事。插入元素的顺序是从上到下从左到右。例如,在问题中的第一棵树之后,必须按以下顺序插入元素:*, +, *, 7, 121, 12, +, 9, 3


    [1] 由 Dr_Sam 建议。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-03
      • 2020-09-29
      • 1970-01-01
      • 2013-10-20
      • 1970-01-01
      • 2017-03-24
      • 1970-01-01
      相关资源
      最近更新 更多