本文源码示例是自己在LeetCode上做的相关题目而来。
前序遍历
遍历思想:根节点→左子树→右子树
递归版本
/**
* Definition for a binary tree node.
* struct TreeNode
* {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution
{
public:
void preOrder(vector<int> &vec, TreeNode* root)
{
if (root != nullptr)
{
vec.push_back(root->val);
preOrder(vec, root->left);
preOrder(vec, root->right);
}
}
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> ans;
preOrder(ans, root);
return ans;
}
};
非递归版本
非递归版本需要用栈来模拟递归版本中对节点指针的“保存”以达到回溯目的,因为先序遍历是先访问根节点,所以对每一个节点都可以直接打印,然后将其压入栈中,再将节点指针移动到左子节点中。当节点为空时,将栈顶元素弹出(即获得其父结点的指针),然后将节点指针移动到父结点的右子结点中。
class Solution
{
public:
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> ans;
if (root == nullptr)
{
return ans;
}
stack<TreeNode*> nodes;
TreeNode* pNode = root;
while (pNode != nullptr || !nodes.empty())
{
if (pNode != nullptr)
{
ans.push_back(pNode->val);
nodes.push(pNode);
pNode = pNode->left;
}
else
{
pNode = nodes.top()->right;
nodes.pop();
}
}
return ans;
}
};
中序遍历
遍历思想:左子树→根节点→右子树
递归版本
/**
* Definition for a binary tree node.
* struct TreeNode
* {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution
{
public:
void inOrder(vector<int> &vec, TreeNode* root)
{
if (root != nullptr)
{
inOrder(vec, root->left);
vec.push_back(root->val);
inOrder(vec, root->right);
}
}
vector<int> inorderTraversal(TreeNode* root)
{
vector<int> ans;
inOrder(ans, root);
return ans;
}
};
非递归版本
中序遍历的非递归版本与前序遍历相似,由于是先打印左子树再打印根节点,所以只需要将打印操作移到出栈后即可。
class Solution
{
public:
vector<int> inorderTraversal(TreeNode* root)
{
vector<int> ans;
if (root == nullptr)
{
return ans;
}
stack<TreeNode*> nodes;
TreeNode* pNode = root;
while (pNode != nullptr || !nodes.empty())
{
if (pNode != nullptr)
{
nodes.push(pNode);
pNode = pNode->left;
}
else
{
ans.push_back(nodes.top()->val);
pNode = nodes.top()->right;
nodes.pop();
}
}
return ans;
}
};
后序遍历
遍历思想:左子树→右子树→根节点
递归版本
/**
* Definition for a binary tree node.
* struct TreeNode
* {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution
{
public:
void postOrder(vector<int> &vec, TreeNode* root)
{
if (root != nullptr)
{
postOrder(vec, root->left);
postOrder(vec, root->right);
vec.push_back(root->val);
}
}
vector<int> postorderTraversal(TreeNode* root)
{
vector<int> ans;
postOrder(ans, root);
return ans;
}
};
非递归版本
后序遍历的非递归版本比前序遍历和中序遍历要难,因为必须保证根节点的左子树和右子树都已经被打印过了才能打印根节点。
一种思路如下:一个节点可以被打印的条件要么是其左子树和右子树都为空,要么是左子树和右子树都已经打印过了。对于后者,我们需要两个节点指针来帮助我们做出判断:一个节点指针所指向的节点是另一个节点指针的指向节点的父结点。如果不满足被打印的条件,则将该节点的右子结点和左子结点先后压入栈中(注意顺序不能搞错)。
class Solution
{
public:
vector<int> postorderTraversal(TreeNode* root)
{
vector<int> ans;
if (root == nullptr)
{
return ans;
}
stack<TreeNode*> nodes;
TreeNode *parent = nullptr, *child = nullptr;
nodes.push(root);
while (!nodes.empty())
{
parent = nodes.top();
if ((parent->left == nullptr && parent->right == nullptr) || (child != nullptr && (child == parent->left || child == parent->right)))
{
ans.push_back(parent->val);
nodes.pop();
child = parent;
}
else
{
if (parent->right != nullptr)
{
nodes.push(parent->right);
}
if (parent->left != nullptr)
{
nodes.push(parent->left);
}
}
}
return ans;
}
};