二叉树的后序遍历是一种深度优先遍历算法,其遍历顺序为:左子树 -> 右子树 -> 根节点。非递归实现后序遍历通常使用一个辅助栈来模拟递归过程。
当然是一个C++二叉树非递归后序遍历算法:
#include <iostream>
#include <stack>
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
void PostorderTraversal(TreeNode* root) {
if (!root) return;
std::stack<TreeNode*> stack;
TreeNode* current = root;
TreeNode* lastVisited = nullptr;
while (current != nullptr || !stack.empty()) {
if (current != nullptr) {
stack.push(current);
current = current->left; // 先左子树
}
else {
// 当current为nullptr且栈不为空时,处理栈顶元素
current = stack.top();
if (current->right != nullptr && current->right != lastVisited) {
// 如果当前节点有右子树,且右子树未被访问
current = current->right; // 转向右子树
}
else {
// 当前节点的左右子树都已访问完毕
stack.pop(); // 弹出当前节点
std::cout << current->val << " "; // 打印当前节点的值
lastVisited = current; // 更新lastVisited为当前节点
current = nullptr; // 重置current,准备下一次循环
}
}
}
}
int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);
std::cout << "Postorder traversal of the binary tree is: ";
PostorderTraversal(root);
// 释放分配的内存(实际应用中应更彻底地释放所有节点的内存)
delete root->left->left;
delete root->left->right;
delete root->left;
delete root->right;
delete root;
return 0;
}
这个算法的关键点是:
- 使用一个
std::stack
来存储待访问的节点。 - 使用一个
current
指针来遍历树,初始指向根节点。 - 使用一个
lastVisited
指针来记录上一个访问的节点,以便在后序遍历中正确地访问和打印节点。 - 循环继续,直到
current
为nullptr
且栈为空。 - 在循环中,首先尝试访问左子树。
- 如果
current
为nullptr
,检查栈顶节点的右子树是否未被访问(即不是lastVisited
节点),如果是,则访问右子树。 - 如果当前节点的右子树已经被访问,或者没有右子树,则从栈中弹出当前节点,打印它的值,并将
lastVisited
更新为当前节点。
这个算法避免了之前提到的逻辑问题,确保了每个节点只被访问一次,并且按照后序遍历的正确顺序(左 -> 右 -> 当前)来访问。同时,它还确保了在访问完节点后,将 current
设置为 nullptr
,避免已经访问过的节点再次被处理。