思路就是直接使用二叉树的经典二级结论, 第一次遍历到就输出即为前序, 第二次为中序, 第三次为后序.

#include <iostream>
#include <stack>

struct Node {
Node *lchild, *rchild;
int data;
int times;
Node(int d) : data(d), lchild(nullptr), rchild(nullptr), times(-1){}
};

void func(Node* root) {
std::stack<Node*> s;
s.push(root);

Node* p = nullptr;
while (!s.empty()) {
p = s.top();
++p->times;

if (p->times == 2) {
s.pop();
}
else if (p->times == 1) {
if (p->rchild) s.push(p->rchild);
}
else {
if (p->lchild) s.push(p->lchild);
std::cout << p->data << " ";
}

}
}

int main() {
Node* root = new Node(0);
Node* l = root->lchild = new Node(1);
Node* r = root->rchild = new Node(2);
l->lchild = new Node(3);
l->rchild = new Node(4);
r->lchild = new Node(5);
r->rchild = new Node(6);

func(root);
return 0;
}

作为优化, 可以专门开一个mark数组来记录栈中元素被访问的次数, 而非在node节点添加一个新的数据成员.

‍之前一直纠结到底怎么方便地模拟递归. 递归相比正常地循环, 我看了其他人的代码, 区别就在于循环是一次性入栈左右节点, 而递归是左左左左左, 右右右右右, 中间, 这样的模式. 所以正解应该是: 用一个额外的存储空间来记录当前节点被访问的次数, 从而实现每次循环只入栈一个节点. 不过这种模式无法直接迁移到别的递归函数中. 在别的递归函数中会改变的地方是, 它们不一定是使用times来判断, 而是使用别的标准. 然而想出这种模式后, 我认为很多递归函数都可以以此为启发来实现非递归版本. 只要搞清楚判断即可.