一个binary tree有三种traversal的方式:preorder / inorder / postorder。我们分别来说:
1. Preorder
所谓preorder,就是处理任何children之前,先处理parent。比如leetcode上,Binary Tree Preorder Traversal 这道题中提供的例子:
For example:
Given binary tree {1,#,2,3}
,
1 \ 2 / 3
return [1,2,3]
.
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void preorderTraversalHelper(TreeNode *root, vector<int> &result) {
if (!root) return;
result.push_back(root->val);
preorderTraversalHelper(root->left, result);
preorderTraversalHelper(root->right, result);
}
vector<int> preorderTraversal(TreeNode *root) {
vector<int> result;
preorderTraversalHelper(root, result);
return result;
}
};
这道题也可以不用递归实现,难度比用递归稍微大一点:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode *root) {
vector<int> result;
if (!root) return result;
std::stack<TreeNode*> qu;
qu.push(root);
while (!qu.empty()) {
TreeNode * current = qu.top();
qu.pop();
result.push_back(current->val);
if (current->right) qu.push(current->right);
if (current->left) qu.push(current->left);
}
return result;
}
};
用直觉就可以知道,应该会用到queue或者stack这种数据结构。
2. Inorder
所谓inorder,就是先左边,然后parent,然后右边这样的顺序。同样地,可以用非常相似的方法来进行递归:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void inorderTraversalHelper(TreeNode *root, vector<int> &result) {
if (!root)
return;
inorderTraversalHelper(root->left, result);
result.push_back(root->val);
inorderTraversalHelper(root->right, result);
}
vector<int> inorderTraversal(TreeNode *root) {
vector<int> result;
inorderTraversalHelper(root, result);
return result;
}
};
可以看到,就是把push_back和两个递归call的位置变了一下而已。
同样,这道题也可以用非递归的方法解决:
class Solution {
public:
vector<int> inorderTraversal (TreeNode *root) {
stack<TreeNode*> s;
vector<int> result;
if (!root) return result;
TreeNode* current = root;
bool done = false;
while (!done) {
if (current) {
s.push(current);
current = current->left;
}
else if (s.empty()) done = true;
else {
current = s.top();
s.pop();
result.push_back(current->val);
current = current->right;
}
}
}
};
3. Postorder
如果已经看到这里了,你应该能猜到postorder是什么意思了。所谓postorder,就是先左child;再右child;再parent。那么毫不意外地,可以用递归实现:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void postorderTraversalHelper(TreeNode *root, vector<int> &result) {
if (!root)
return;
postorderTraversalHelper(root->left, result);
postorderTraversalHelper(root->right, result);
result.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode *root) {
vector<int> result;
postorderTraversalHelper(root, result);
return result;
}
};
也同样毫不意外地,可以用非递归实现。不幸的是,这个iterative solution是三者中最难的一个。如图:
比如我们看D, C, E这三个nodes组成的subtree。如果是postorder,那也就是说,要先C, 再E,最后D。换句话说,当我traversal到D的时候,我发现它有两个children,所以我就要先进行children:这个过程是是从上到下的;而当C结束的时候,我们再回到D,发现还有E,那么从C结束到D的过程是从左下到上的;E结束之后,再回到D,发现已经没有children了,所以输出D,那么从E到D的过程是从右下到上的。所以一共有三种情况:从上到下;从左下到上;从右下到上。如何区分这三种情况呢?我们使用两个pointers,一个curr,一个prev。如果curr是prev的孩子,那么就说明是从上到下;如果prev是curr的left child,那么就说明是从左下到上;如果prev是curr的right child,那么就说明是从右下到上。代码如下:
void postOrderTraversalIterative(BinaryTree *root) {
if (!root) return;
stack<BinaryTree*> s;
s.push(root);
BinaryTree *prev = NULL;
while (!s.empty()) {
BinaryTree *curr = s.top();
// we are traversing down the tree
if (!prev || prev->left == curr || prev->right == curr) {
if (curr->left) {
s.push(curr->left);
} else if (curr->right) {
s.push(curr->right);
} else {
cout << curr->data << " ";
s.pop();
}
}
// we are traversing up the tree from the left
else if (curr->left == prev) {
if (curr->right) {
s.push(curr->right);
} else {
cout << curr->data << " ";
s.pop();
}
}
// we are traversing up the tree from the right
else if (curr->right == prev) {
cout << curr->data << " ";
s.pop();
}
prev = curr; // record previously traversed node
}
}