详解在代码注释,后序遍历比较复杂,主要因为在将某一点加入结果集时,需要判定它的左右子节点是否被访问过(已加入结果集),因此将访问过的节点值设为999,以便压栈时检查。
// 迭代先序
vector<int> preorderTraversal(TreeNode* root) {
vector<int> ret;
stack<TreeNode*> stk; // 辅助栈
while (root || !stk.empty()) {
while (root) {
ret.push_back(root->val); // 记录结果
stk.push(root);
root = root->left;
}
// 出栈
auto node = stk.top();
stk.pop();
root = node->right;
}
return ret;
}
// 迭代后序
vector<int> postorderTraversal(TreeNode* root) {
vector<int> ret;
stack<TreeNode*> stk;
while (root || !stk.empty()) {
while (root && root->val != 999) { // root不为空且未被访问过
stk.push(root);
root = root->left;
}
auto top = stk.top(); // 此时,top必然没有左子树,或者左子树被访问过
if (top->right && top->right->val != 999) {
// 没有左子树 + 有右子树,且右子树未被访问过,移动root到右子树,下一个循环开始压栈右子树里的节点
root = top->right;
} else {
// 没有左子树 + 没有右子树,或者有右子树但被访问过,当前节点加入结果集,并出栈
ret.push_back(top->val);
top->val = 999; // 标识当前节点已被访问过
stk.pop();
}
}
return ret;
}
// 迭代中序
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ret;
stack<TreeNode*> stk; // 辅助栈
while (root || !stk.empty()) { // 当root不为空时(还可以入栈)、或者栈不为空时(还可以出栈)
// (1):当有左子树时,入栈
while (root) {
stk.push(root);
root = root->left;
}
// (2):出栈,并判断出栈的节点是否有右子树
// 如果有,以右子树为root从(1)处开始新一轮循环;
// 如果没有,则继续出栈
auto tmp = stk.top();
stk.pop();
ret.push_back(tmp->val);
root = tmp->right; // 移动至右子树
}
return ret;
}