面试的时候遇见了,在博客上先记录一下。
以下3种遍历全部使用栈stack辅助存储节点,使用C++解答。
头文件和节点定义:
#include <iostream>
#include <stack>
#include <algorithm>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x):val(x),left(nullptr), right(nullptr) {}
};
1. 前序遍历
根 左 右,最为简单,最易考察。
步骤:
1. 节点判空;
2. 非空先压入root根节点;
3. 进入循环while(),访问根节点,删除根节点,打印节点值;
4. 访问左右子树(由于栈先入后出,左子树放在栈顶)。
程序示例:
void preorder(TreeNode *root) {
// 1.判空
if (root == nullptr) return;
stack<TreeNode*> s;
// 2. 压入root
s.push(root);
while(!s.empty()) {
// 3. 直接打印temp值
TreeNode *temp = s.top();
s.pop();
cout << temp->val << " ";
// 4. 访问左右子树,由于栈的特性,先压入右子树,再弄左子树
if (temp->right) s.push(temp->right);
if (temp->left) s.push(temp->left);
}
}
2. 中序遍历
左 根 右, 保证左子树先被访问。
1. 节点判空;
2. while循环,从root开始,再来一个while,访问左子树;
3. 访问根节点,删除根节点,打印栈顶值;
4. 访问右子树,进入下一次循环。
void inorder(TreeNode *root) {
// 1.判空
if (root == nullptr) return;
stack<TreeNode *> s;
while(!s.empty() || root) {
// 2. 访问左子树
while(root) {
s.push(root);
root = root->left;
}
// 3. temp左子树已被访问,直接打印temp即可
TreeNode *temp = s.top();
s.pop();
cout << temp->val << " ";
// 4. 访问右子树
root = temp->right;
}
}
3. 后序遍历
左 右 根,注意:根一定要在右子树被标记访问后才可访问。
1. 节点判空;
2. while循环,从root开始,再来一个while,访问左子树;
3. 访问右子树,若存在且未被访问,访问;
4. 访问根节点,删除根节点,打印值。
示例程序:
void postorder(TreeNode *root) {
// 1. 判空
if (!root) return;
stack<TreeNode*> s;
TreeNode *lastVisit = nullptr;
while(!s.empty() || root) {
// 2. 访问添加左子树
while(root) {
s.push(root);
root = root->left;
}
// 3. 访问右子树
TreeNode *temp = s.top();
if (temp->right && temp->right != lastVisit) {
// 3.1 右子树未被访问,访问
root = temp->right;
} else {
// 3.2 右子树已被访问,该访问根节点值了
cout << temp->val << " ";
s.pop();
lastVisit = temp;
}
}
}
4. 测试
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);
// 1 2 4 5 3
preorder(root);
cout << endl;
// 4 2 5 1 3
inorder(root);
cout << endl;
// 4 5 2 3 1
postorder(root);
return 0;
}