用递归方法实现二叉树的先序遍历、中序遍历和后序遍历很简单:
class Solution {
public:
vector<int> preOrder;
vector<int> preorderTraversal(TreeNode *root) { // 先序遍历,4ms,484k
if(root == nullptr)
return preOrder;
preorder(root);
return preOrder;
}
void preorder(TreeNode *root){
preOrder.push_back(root->val);
if(root->left != nullptr)
preorder(root->left);
if(root->right != nullptr)
preorder(root->right);
}
};
class Solution {
public:
vector<int> inOrder;
vector<int> inorderTraversal(TreeNode *root) { // 中序遍历,2ms,484k
if(root == nullptr)
return inOrder;
inorder(root);
return inOrder;
}
void inorder(TreeNode *root){
if(root->left != nullptr)
inorder(root->left);
inOrder.push_back(root->val);
if(root->right != nullptr)
inorder(root->right);
}
};
class Solution {
public:
vector<int> postOrder;
vector<int> postorderTraversal(TreeNode *root) { // 后序遍历,4ms,612k
if(root == nullptr)
return postOrder;
postorder(root);
return postOrder;
}
void postorder(TreeNode *root){
if(root->left != nullptr)
postorder(root->left);
if(root->right != nullptr)
postorder(root->right);
postOrder.push_back(root->val);
}
};
非递归方法,利用栈实现。
class Solution {
public:
vector<int> preOrder;
vector<int> preorderTraversal(TreeNode *root) { // 先序遍历,4ms,488k
if(root == nullptr)
return preOrder;
preorder(root);
return preOrder;
}
void preorder(TreeNode *root){ // 先访问根节点,再逐个访问左孩子,并将每个节点压入栈中,左孩子访问完即可取栈顶节点访问其右孩子
stack<TreeNode *> s;
TreeNode *pTemp = root;
while(pTemp!=nullptr || !s.empty()){
while(pTemp!=nullptr){
preOrder.push_back(pTemp->val); // 先访问根节点
s.push(pTemp); // 节点压入栈中,访问完左孩子再取栈顶元素访问右孩子
pTemp = pTemp->left; // 依次访问左孩子
}
if(!s.empty()){ // 取栈顶元素访问右孩子
pTemp = s.top();
s.pop();
pTemp = pTemp->right;
}
}
}
};
class Solution {
public:
vector<int> inOrder;
vector<int> inorderTraversal(TreeNode *root) { // 中序遍历,3ms,488k
if(root == nullptr)
return inOrder;
inorder(root);
return inOrder;
}
void inorder(TreeNode *root){
stack <TreeNode *> s;
TreeNode *pTemp = root;
while(pTemp!=nullptr || !s.empty()){
while(pTemp!=nullptr){ // 若左孩子不为空
s.push(pTemp); // 将左孩子入栈
pTemp = pTemp->left; // 逐个左孩子入栈,一直到没有左孩子的节点为止
}
if(!s.empty()){
pTemp = s.top(); // 取栈顶节点(该节点是最远的左孩子或根节点)
s.pop();
inOrder.push_back(pTemp->val);
pTemp = pTemp->right; // 读右节点
}
}
}
后序遍历的非递归实现是三种遍历的非递归实现中最难的一种,因为后序遍历要求左右孩子都已被访问并且先访问左孩子再访问右孩子,然后才能访问根节点,这就为流程的控制带来了困难。
要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
class Solution {
public:
vector<int> postOrder;
vector<int> postorderTraversal(TreeNode *root) { // 后序遍历,2ms,484k
if(root == nullptr)
return postOrder;
postorder(root);
return postOrder;
}
void postorder(TreeNode *root){
stack <TreeNode *> s;
TreeNode *pCur;
TreeNode *pPre = nullptr; // 前一次访问的节点
s.push(root);
while(!s.empty()){
pCur = s.top();
if( (pCur->left==nullptr && pCur->right==nullptr)|| // 如果当前节点没有孩子
(pPre!=nullptr && (pPre==pCur->left||pPre==pCur->right) ) ){ // 或孩子节点都已被访问过
postOrder.push_back(pCur->val);
s.pop();
pPre = pCur;
}
else{
if(pCur->right!=nullptr)
s.push(pCur->right);
if(pCur->left!=nullptr)
s.push(pCur->left);
}
}
}
};