声明:本文原题主要来自力扣,记录此博客主要是为自己学习总结,不做任何商业等活动!
二叉树的遍历有前序遍历、中序遍历、后序遍历和层次遍历,其中二叉树基本知识点可以参考博主上篇博客(二叉树基本知识点图文介绍(全网最简洁)_净无邪博客-CSDN博客),二叉树的前序遍历可以参考博主这篇博客(二叉树前序遍历(递归法和迭代法(即非递归法))——C++_净无邪博客-CSDN博客),后序遍历可以参考博主这篇博客(二叉树后序遍历(递归法和迭代法(非递归法))——C++),本文主要总结二叉树的中序遍历。
中序遍历是先遍历左子节点left,在遍历父节点parent,最后遍历右子节点right,即遍历顺序:
left ——> parent ——> right
下面是力扣原题,写一个中序遍历程序。
给定一个二叉树的根节点
root
,返回它的 中序 遍历。示例 1:
输入:root = [1,null,2,3] 输出:[1,3,2]
递归法主要用编译器栈自动压入递归的函数参数和局部变量,依次按照中序遍历顺序有且仅有一次访问二叉树。下面是具体示例代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector inorderTraversal(TreeNode* root) {
if(root == nullptr)
return datas;
if(root->left != nullptr)
inorderTraversal(root->left);
datas.push_back(root->val);
if(root->right != nullptr)
inorderTraversal(root->right);
return datas;
}
private:
vector datas;
};
结果:
迭代法是采用非递归方法实现二叉树的中序遍历,主要利用数据结构std::stack来实现,利用栈std::stack的先进后出特性依次压入待访问的节点,然后依次按照中序遍历顺序弹出和访问节点,确保每个节点有且仅有一次访问。
具体步骤如下:
a1 先将所有父节点和左子节点依次压入栈;
这样做的目的是为了先弹出左子节点,再弹出父节点,可以在弹出左子节点的时候进行遍历,同时处理右节点,比如将右节点压入栈,这样就实现了先访问左节点,然后父节点,最后右子节点。
while (cur != nullptr)
{
nodeStack.push(cur);
cur = cur->left;
}
a2 然后弹出一个节点,进行遍历;
此时弹出的节点前提是左子节点为空,则该节点是父节点,故需要在后面遍历右子节点
cur = nodeStack.top();
nodeStack.pop();
datas.push_back(cur->val);
a3 遍历右子节点,将其作为一棵右子节点树的父节点,继续循环第a1步骤,直到整个栈为空即可
while (cur != nullptr || !nodeStack.empty())
{
while (cur != nullptr) // 控制父节点和左子树非空,则先压入父节点,然后压入左节点
{
// 循环将做父节点和左子树压入栈 ......
}
// 弹出栈和遍历节点 ......
cur = cur->right; // 将弹出栈的右子节点当作右子树的父节点进行循环遍历
}
下面是完整代码实现:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector inorderTraversal(TreeNode* root) {
TreeNode* cur = root;
std::stack nodeStack;
while(cur != nullptr || !nodeStack.empty()) // 循环截止条件是父节点为空或栈为空
{
while(cur != nullptr) // 控制父节点和左子树非空,则先压入父节点,然后压入左节点
{
nodeStack.push(cur);
cur = cur->left;
}
cur = nodeStack.top();
nodeStack.pop();
datas.push_back(cur->val);
cur = cur->right; // 将弹出栈的右子节点当作父节点进行循环遍历
}
return datas;
}
private:
vector datas;
};
结果:
二叉树的中序遍历递归法跟前序遍历差不多,但是迭代法在代码结构上却有较大差别,前序遍历主要通过一个栈先访问当前节点也就是父节点,然后再遍历左节点,接着遍历右节点,代码结构清晰易于理解;但是中序遍历的迭代法代码实现结构却不同,主要还是数据结构栈的性质,决定了中序遍历需要先将父节点压入栈,然后压入左节点,这是一个循环的步骤,直到左子树为空才停止压栈,此时需要弹出栈进行遍历该节点(可以看成父节点,左节点为空),遍历完后再将该节点的右节点作为右子树的父节点,重复前面步骤,直到整个栈为空即可完成每个节点中序遍历。