【问题标题】:C++ Remove last comma when printing AVL tree elementsC++ 打印 AVL 树元素时删除最后一个逗号
【发布时间】:2021-06-19 04:12:35
【问题描述】:

我知道有人问过类似的问题,但我似乎无法通过递归调用的函数找到打印的答案。我正在尝试打印 AVL 树的前序、后序和中序遍历,并递归地实现了这些函数。

void inOrder(Node* root)
{
    if(root != nullptr) {
        inOrder(root->left);
        cout << root->data << ", ";
        inOrder(root->right);
    }
}

除最后一个值外,数据应以逗号分隔,但我不知道该怎么做。我已经进行了研究,但在递归遍历 AVL 树时找不到任何似乎适用的东西。这是可能的还是我应该在没有递归的情况下实现这些功能?

【问题讨论】:

  • 你不想在最后一个节点之后写逗号。现在你只需要弄清楚最后一个节点是什么以及如何检测它。
  • @Someprogrammerdude 通常更容易检测到第一个节点而不是最后一个节点。因此,您通常会在第一个元素之前而不是在最后一个元素之后跳过分隔符。
  • 如果你想在你的遍历中打印一个节点之外的其他事情会发生什么?如果您是这样考虑的,那么您可能会考虑以稍微不同的方式实现遍历代码,而不是在遍历中硬编码特定操作(例如打印)。
  • @deW1 可能有多个带有nullptr 右分支的树节点。这样的节点在迭代中可能不是最终的。
  • @AndreySemashev 是的,我忘了它是一棵树

标签: c++ recursion avl-tree


【解决方案1】:

我通常用于此类事情的模式是使用我在循环中更改的分隔符指针。第一次迭代是"",所以不打印任何内容,并且每次后续迭代都打印分隔符。对于您的递归情况,它将作为参数传递,如下所示:

void inOrder(Node* root, char ** sep)
{
    if(root != nullptr) {
        inOrder(root->left, sep);
        cout << **sep << root->data;
        *sep = ", ";
        inOrder(root->right, sep);
    }
}

这样称呼:

char * sep = "";
inOrder(root, &sep);

循环看起来好多了。主要优点是每个循环中没有 if/else 分支,只是一个快速的指针分配来更新分隔符。

【讨论】:

    【解决方案2】:

    制作一个内部实现函数,维护一个标志,指示要输出的数据项是否是第一个。然后在输出前为除第一个以外的所有项目添加逗号。

    void inOrderImpl(Node* root, bool& first)
    {
        if(root != nullptr) {
            inOrderImpl(root->left, first);
            if (first)
                first = false;
            else
                cout << ", ";
            cout << root->data;
            inOrderImpl(root->right, first);
        }
    }
    
    void inOrder(Node* root)
    {
        bool first = true;
        inOrderImpl(root, first);
    }
    

    【讨论】:

      【解决方案3】:

      正如我的评论所建议的,编写代码以执行任何 BST 遍历的一种雄心勃勃(更好)的方法是使用更通用的方法:

      template <typename Fn>
      void inOrder(Node* root, Fn& func)
      {
          if(root != nullptr) 
          {
              inOrder(root->left, func);
              func(root);
              inOrder(root->right, func);
          }
      }
      

      因此,鉴于上述情况,您基本上可以做任何事情,因为将使用 root 的当前值调用 func

      那么这对我们有什么帮助?现在考虑以下几点:

      struct TreePrinter
      { 
         bool initial = true; 
         void operator()(Node *root)
         {
           if ( initial )
              initial = false;
           else
              std::cout << ",";
          std::cout << root->data;
         }
      };   
      

      上面是一个覆盖operator()的类。这允许我们将 this 传递给遍历函数,而遍历函数只是调用它。

      请注意,initial 是在 TreePrinter 对象中设置的状态。

      那么就是这样实现的:

      TreePrinter tp;
      Node root;
      //...
      inOrder(&root, tp);
      

      这是live example using a dummy BST

      所以你不仅可以只打印一个逗号,还可以提供任何可调用的对象(函数指针、函数对象、lambda 等),基本上可以使用传入的root 来做任何需要做的事情。

      【讨论】:

        猜你喜欢
        • 2019-03-19
        • 2021-10-25
        • 1970-01-01
        • 1970-01-01
        • 2015-08-05
        • 1970-01-01
        • 2017-09-13
        • 1970-01-01
        • 2021-10-02
        相关资源
        最近更新 更多