1.二叉树的遍历方式
对于一棵二叉树一共有四种遍历方式。分别是:前序遍历、中序遍历、后序遍历和层序遍历。
前序遍历:根左右的顺序
中序遍历:左根右的顺序
后序遍历:左右根的顺序
层序遍历:一层一层的遍历也叫广度优先遍历
例如:
前序遍历:4 2 5 6 1 3
中序遍历:5 2 6 4 1 3
后序遍历:5 6 2 3 1 4
层序遍历:4 2 1 5 6 3
2.递归
2.1前序遍历
class Solution {
public:
void pre(TreeNode* root,vector<int>&result){
if(root==nullptr){
return;
}
result.push_back(root->val);//根
pre(root->left,result);//左
pre(root->right,result);//右
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
pre(root,result);
return result;
}
};
2.2中序遍历
class Solution {
public:
void in(TreeNode* root,vector<int>&result){
if(root==nullptr){
return;
}
in(root->left,result);//左
result.push_back(root->val);//根
in(root->right,result);//右
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
in(root,result);
return result;
}
};
2.3后序遍历
class Solution {
public:
void post(TreeNode* root,vector<int>&result){
if(root==nullptr){
return;
}
post(root->left,result);//左
post(root->right,result);//右
result.push_back(root->val);//根
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
post(root,result);
return result;
}
};
2.4层序遍历
class Solution {
public:
void Order(TreeNode* cur,int depth,vector<vector<int>>& result){
if(cur==nullptr){
return;
}
if(result.size()==depth){
result.push_back(vector<int>{});//为即将放入的元素申请空间
}
result[depth].push_back(cur->val);
Order(cur->left,depth+1,result);
Order(cur->right,depth+1,result);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
if(root==nullptr){
return result;
}
int depth=0;//初始深度为0
Order(root,depth,result);
return result;
}
};
从以上四种递归遍历方式中我们可以发现,前中后序为一组,层序单独为一组。
3.非递归
对于非递归的遍历方式我们需要一些数据结构辅助我们来进行遍历。前中后序遍历通常采用一个栈来辅助遍历,层序遍历需要使用一个辅助队列进行遍历。
3.1前序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> sta;//辅助栈
vector<int> result;
if(root==nullptr){
return result;
}
sta.push(root);
while(!sta.empty()){
TreeNode* node;
node=sta.top();
result.push_back(node->val);
sta.pop();
if(node->right){//由于栈满足先进后出的特性,因此右节点先入栈。
sta.push(node->right);
}
if(node->left){
sta.push(node->left);
}
}
return result;
}
};
3.2中序遍历
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> sta;//辅助栈
vector<int> result;
if(root==nullptr){
return result;
}
TreeNode* cur;//由于中序遍历的顺序和处理结点的顺序不一致,因此需要一个指针遍历树
cur=root;
while(!sta.empty() || cur!=nullptr){
if(cur!=nullptr ){//根、左先入栈
sta.push(cur);
cur=cur->left;
}else{
cur=sta.top();
sta.pop();
result.push_back(cur->val);//按照左、根的顺序出栈
cur=cur->right;//处理右结点
}
}
return result;
}
};
3.3后序遍历
在前序遍历的基础上稍作修改,入栈时左结点先入栈后右结点,因此输出顺序为根右左,最后翻转结果就可以得出后序遍历左右根的顺序。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*>sta;//辅助栈
vector<int> result;
if(root==nullptr){
return result;
}
sta.push(root);
while(!sta.empty()){
TreeNode* node;
node=sta.top();
result.push_back(node->val);
sta.pop();
if(node->left){//左结点入栈
sta.push(node->left);
}
if(node->right){//右结点入栈
sta.push(node->right);
}
}
reverse(result.begin(),result.end());//翻转序列
return result;
}
};
3.4层序遍历
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> que;//辅助队列
vector<vector<int>> result;
if(root==nullptr){
return result;
}
que.push(root);
while(!que.empty()){
vector<int> temp;
int size=que.size();//用来遍历当前队列
for(int i=0;i<size;i++){
TreeNode* node;
node=que.front();
que.pop();
temp.push_back(node->val);
if(node->left){
que.push(node->left);
}
if(node->right){
que.push(node->right);
}
}
result.push_back(temp);
}
return result;
}
};
从以上四种非递归遍历方式中我们可以发现,前后序遍历为一组,中序遍历和层序遍历单独为一组。
4.总结
对于二叉树的常见遍历方式不管是递归还是非递归方式我们都应该掌握。最后,我们也可以把二叉树推广到n叉树实现n叉树的前序、后序和层序遍历,不管递归还是非递归思路都是一样的。有同学可能要问为什么没有n叉树的中序遍历,因为对于n叉树而言我们并不知道哪些孩子是左孩子哪些是右孩子,也没这种说法,因此没有中序遍历。