目录
1.2 Definition for a binary tree node
3 Iterative DFS Method with Stack
1. Binary Tree Traversal
1.1 Order types
- Postorder: left->right->root
- Preorder: root->left->right
- Inorder:left->root->right
1.2 Definition for a binary tree node
Struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val (x), left(nullptr), right(nullptr) {}
};
2 Recursive DFS Method
- Time complexity:
, N is the number of nodes. We visit each node exactly once.
- Space complexity:
, H is the height of the tree, in the worst case H = N.
vector<int> binaryTreeTraversal(TreeNode* root)
{
vector<int> ans;
DFSHelper(root, ans);
return ans;
}
//Postorder
void DFSHelper(TreeNode* node, vector<int> &ans)
{
if(!node) return;
DFSHelper(node->left, ans);
DFSHelper(node->right, ans);
ans.push_back(node->val);
}
//Preorder
void DFSHelper(TreeNode* node, vector<int> &ans)
{
if(!node) return;
ans.push_back(node->val);
DFSHelper(node->left, ans);
DFSHelper(node->right, ans);
}
//Inorder
void DFSHelper(TreeNode* node, vector<int> &ans)
{
if(!node) return;
DFSHelper(node->left, ans);
ans.push_back(node->val);
DFSHelper(node->right, ans);
}
3 Iterative DFS Method with Stack
- Time complexity:
, N is the number of nodes. We visit each node exactly once.
- Space complexity:
, we may have to keep the entire tree in stack.
vector<int> postorderTraversal(TreeNode* root)
{
vector<int> ans;
stack<TreeNode*> todo_stk;
TreeNode* curr = root;
TreeNode* pre = nullptr;
while(curr || todo_stk.size()) {
if(curr) {
todo_stk.push(curr);
curr = curr->left;
} else {
curr = todo_stk.top();
if(curr->right && curr->right != pre) { //note
curr = curr->right;
} else {
todo_stk.pop();
ans.push_back(curr->val); //access
pre = curr;
curr = nullptr;
}
}
}
return ans;
}
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> ans;
stack<TreeNode*> todo_stk;
TreeNode* curr = root;
while(curr || todo_stk.size()) {
if(curr) {
ans.push_back(curr->val); //access
todo_stk.push(curr);
curr = curr->left;
} else {
curr = todo_stk.top();
todo_stk.pop();
curr = curr->right;
}
}
return ans;
}
vector<int> inorderTraversal(TreeNode* root)
{
vector<int> ans;
stack<TreeNode*> todo_stk;
TreeNode* curr = root;
while(curr != NULL || todo_stk.size()) {
if(curr) {
todo_stk.push(curr);
curr = curr->left;
} else {
curr = todo_stk.top();
todo_stk.pop();
ans.push_back(curr->val); //access
curr = curr->right;
}
}
return ans;
}
Another way for iterative with stack
vector<int> preorderTraversal(TreeNode* root)
{
if(!root) return {};
vector<int> ans;
stack<TreeNode*> todo_stk;
todo_stk.push(root);
while(todo_stk.size()) {
TreeNode* top = todo_stk.top();
todo_stk.pop();
ans.push_back(top->val);
if(top->right)
todo_stk.push(top->right);
if(top->left)
todo_stk.push(top->left);
}
return ans;
}
4. Morris Traversal
- Time complexity:
, N is the number of nodes. But all predecessors were visited twice.
- Space complexity:
,
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> ans;
TreeNode* curr = root;
TreeNode* prev = nullptr;
while(curr) {
if(curr->left) {
prev = curr->left;
while (prev->right && prev->right != curr)
prev = prev->right;
if(prev->right == NULL) { //first visit
ans.push_back(curr->val);
prev->right = curr;
curr = curr->left;
} else { //second visit
prev->right = nullptr;
curr = curr->right;
}
} else {
ans.push_back(curr->val);
curr = curr->right;
}
}
return ans;
}
vector<int> inorderTraversal(TreeNode* root)
{
vector<int> ans;
TreeNode* curr = root;
TreeNode* prev = nullptr;
while(curr) {
if(curr->left) {
prev = curr->left;
while (prev->right && prev->right != curr)
prev = prev->right;
if(prev->right == NULL) {
prev->right = curr;
curr = curr->left;
} else {
ans.push_back(curr->val);
prev->right = nullptr;
curr = curr->right;
}
} else {
ans.push_back(curr->val);
curr = curr->right;
}
}
return ans;
}
5 Level Traversal
5.1 Preorder Recursive method
- Time complexity:
- Space complexity:
, logN is the stack memory cost
vector<vector<int>> levelOrder(TreeNode* root)
{
vector<vector<int>> ans;
DFSHelper(root, 0, ans);
return ans;
}
void DFSHelper(TreeNode * root, int depth, vector<vector<int>> &ans)
{
if(!root) return;
if(ans.size() == depth)
ans.push_back({});
ans[depth].push_back(root->val);
DFSHelper(root->left, depth+1, ans);
DFSHelper(root->right, depth+1, ans);
}
5.2 Iterative method
- Time complexity:
- Space complexity:
, logN is the height of the tree
vector<vector<int>> levelOrder(TreeNode* root)
{
if(!root) return {};
vector<vector<int>> ans;
queue<TreeNode*> todo_q;
todo_q.push(root);
while(todo_q.size()){
int n = todo_q.size();
ans.push_back({});
for (int i = 0; i < n; i++) {
TreeNode* node = todo_q.front();
todo_q.pop();
ans.back().push_back(node->val);
if(node->left) todo_q.push(node->left);
if(node->right) todo_q.push(node->right);
}
}
return ans;
}