C++ 在打印 AVL 树元素时删除最后一个逗号
C++ Remove last comma when printing AVL tree elements
我知道有人问过类似的问题,但我似乎找不到通过递归调用的函数进行打印的答案。我正在尝试打印 AVL 树的前序、后序和中序遍历,并递归地实现了这些功能。
即
void inOrder(Node* root)
{
if(root != nullptr) {
inOrder(root->left);
cout << root->data << ", ";
inOrder(root->right);
}
}
除最后一个值外,数据应以逗号分隔打印,但我不确定该怎么做。我已经进行了研究,但在递归遍历 AVL 树时找不到任何似乎适用的东西。这是可能的还是我应该在没有递归的情况下实现这些功能?
做一个内部实现函数,维护一个flag,表示要输出的数据项是否是第一个。然后为除第一个以外的所有项目在输出前加上逗号。
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);
}
我通常用于此类事情的模式是使用我在循环中更改的分隔符指针。第一次迭代是 ""
,所以什么都不打印,随后的每次迭代都打印分隔符。对于您的递归情况,它将作为参数传递,如下所示:
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 分支,只是一个快速的指针赋值来更新分隔符。
正如我的评论所建议的那样,编写执行任何 BST 遍历的代码的一种雄心勃勃(且更好)的方法是使用更通用的方法:
template <typename Fn>
void inOrder(Node* root, Fn& func)
{
if(root != nullptr)
{
inOrder(root->left, func);
func(root);
inOrder(root->right, func);
}
}
鉴于以上内容,您基本上可以做任何事情,因为 func
将使用 root
的当前值调用。
那么这对我们有什么帮助呢?现在考虑以下内容:
struct TreePrinter
{
bool initial = true;
void operator()(Node *root)
{
if ( initial )
initial = false;
else
std::cout << ",";
std::cout << root->data;
}
};
以上是覆盖了 operator()
的 class。这样我们就可以把this传递给遍历函数,遍历函数直接调用即可。
请注意 initial
是在 TreePrinter
对象中设置的状态。
然后是这样实现的:
TreePrinter tp;
Node root;
//...
inOrder(&root, tp);
这里是live example using a dummy BST.
所以你不仅可以打印一个逗号,还可以提供任何可调用对象(函数指针、函数对象、lambda 等),基本上可以使用传入的 root
来做任何需要做的事情完成。
我知道有人问过类似的问题,但我似乎找不到通过递归调用的函数进行打印的答案。我正在尝试打印 AVL 树的前序、后序和中序遍历,并递归地实现了这些功能。
即
void inOrder(Node* root)
{
if(root != nullptr) {
inOrder(root->left);
cout << root->data << ", ";
inOrder(root->right);
}
}
除最后一个值外,数据应以逗号分隔打印,但我不确定该怎么做。我已经进行了研究,但在递归遍历 AVL 树时找不到任何似乎适用的东西。这是可能的还是我应该在没有递归的情况下实现这些功能?
做一个内部实现函数,维护一个flag,表示要输出的数据项是否是第一个。然后为除第一个以外的所有项目在输出前加上逗号。
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);
}
我通常用于此类事情的模式是使用我在循环中更改的分隔符指针。第一次迭代是 ""
,所以什么都不打印,随后的每次迭代都打印分隔符。对于您的递归情况,它将作为参数传递,如下所示:
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 分支,只是一个快速的指针赋值来更新分隔符。
正如我的评论所建议的那样,编写执行任何 BST 遍历的代码的一种雄心勃勃(且更好)的方法是使用更通用的方法:
template <typename Fn>
void inOrder(Node* root, Fn& func)
{
if(root != nullptr)
{
inOrder(root->left, func);
func(root);
inOrder(root->right, func);
}
}
鉴于以上内容,您基本上可以做任何事情,因为 func
将使用 root
的当前值调用。
那么这对我们有什么帮助呢?现在考虑以下内容:
struct TreePrinter
{
bool initial = true;
void operator()(Node *root)
{
if ( initial )
initial = false;
else
std::cout << ",";
std::cout << root->data;
}
};
以上是覆盖了 operator()
的 class。这样我们就可以把this传递给遍历函数,遍历函数直接调用即可。
请注意 initial
是在 TreePrinter
对象中设置的状态。
然后是这样实现的:
TreePrinter tp;
Node root;
//...
inOrder(&root, tp);
这里是live example using a dummy BST.
所以你不仅可以打印一个逗号,还可以提供任何可调用对象(函数指针、函数对象、lambda 等),基本上可以使用传入的 root
来做任何需要做的事情完成。