二叉树的遍历
二叉树的遍历方式细分可以成为6种,但是一般约定左节点先于右节点,那么可以合并为3中,根据根节点的访问顺序,分为前序遍历、中序遍历、后续遍历,递归模板主要分为一下情况::
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
}
//前序遍历
void preVisite(TreeNode *root)
{
if(root==NULL) return;
//前序访问
print(root->val);
preVisit(root->left);
preVisit(root->right);
}
//中序遍历
void midVisite(TreeNode *root)
{
if(root==NULL) return;
preVisit(root->left);
//中序访问
print(root->val);
preVisit(root->right);
}
//后序遍历
void postVisite(TreeNode *root)
{
if(root==NULL) return;
preVisit(root->left);
preVisit(root->right);
//后序访问
print(root->val);
}
对于这些递归模式,要牢记于心,很多二叉树的问题都是基于二叉树的遍历,选择合适的遍历顺序,能够极大的提高算法的效率。
非递归遍历二叉树
递归遍历二叉树,具有很好的模板特性,本质是函数栈的调用,为了在迭代形式下访问二叉树,就需要借助自建的数据栈来保存数据。
很多时候,非递归二叉树遍历没有固定的模板,尤其针对中序遍历和后续遍历,因为执行顺序和访问顺序不同,所以就显得十分麻烦。这里采用统一方法–在访问节点后面添加空指针,show the code now
前序遍历
前序遍历的非递归模式,有一个非常简单的方式(因为执行顺序和访问顺序相同)
简单模式如下:
//
//前序遍历-
void preVisite(TreeNode *root)
{
if(root==NULL) return;
stack<TreeNode *> treeStack;
treeStack.push(root);;
while(!treeStack.empty())
{
TreeNode *cur = treeStack.top();
treeStack.pop();
print(cur->val);
if(cur->right) treeStack.push(cur->right);
if(cur->left) treeStack.push(cur->left);
}
}
统一模式如下:
统一模板的重点在于:先将root压入辅助栈,在主循环中,每次判断当前的栈顶节点,如果不是NULL节点,那么需要将这个节点弹出后,在该节点后压入一个NULL,这样保证每个节点都会压入一个NULL节点,同时要注意出了辅助的NULL节点,不会有其他的NULL节点,所以在压入当前节点的左右孩子的时候要注意判断左右孩子是不是NULL节点。
//借助null--压入栈的顺序完全相反 右-左-中
//前序遍历-
void preVisite(TreeNode *root)
{
if(root==NULL) return;
stack<TreeNode *> treeStack;
treeStack.push(root);;
while(!treeStack.empty())
{
TreeNode *cur = treeStack.top();//延迟弹出
if(cur!=NULL)
{
treeStack.pop();
if(cur->right) treeStack.push(cur->right);//右
if(cur->left) treeStack.push(cur->left);//左
treeStack.push(cur);//中
treeStack.push(NULL);//下一次就可以访问这个节点
}
else//开始访问
{
treeStack.pop();//弹出空
print(treeStack.top());
treeStack.pop();//访问后弹出来
}
}
}
中序遍历
//借助null--压入栈的顺序完全相反 右-中-左
//中序遍历-
void inVisite(TreeNode *root)
{
if(root==NULL) return;
stack<TreeNode *> treeStack;
treeStack.push(root);;
while(!treeStack.empty())
{
TreeNode *cur = treeStack.top();//延迟弹出
if(cur!=NULL)
{
treeStack.pop();
if(cur->right) treeStack.push(cur->right);//右
treeStack.push(cur);//中
treeStack.push(NULL);
if(cur->left) treeStack.push(cur->left);//左孩子是NULL的时候才会开始访问
}
else//开始访问
{
treeStack.pop();//弹出空
print(treeStack.top());
treeStack.pop();//访问后弹出来
}
}
}
后续遍历
//借助null--压入栈的顺序完全相反 中-右-左
//后序遍历-
void postVisite(TreeNode *root)
{
if(root==NULL) return;
stack<TreeNode *> treeStack;
treeStack.push(root);;
while(!treeStack.empty())
{
TreeNode *cur = treeStack.top();//延迟弹出
if(cur!=NULL)
{
treeStack.pop();
treeStack.push(cur);//中
treeStack.push(NULL);
if(cur->right) treeStack.push(cur->right);//右
if(cur->left) treeStack.push(cur->left);//左孩子是NULL的时候才会开始访问
}
else//开始访问
{
treeStack.pop();//弹出空
print(treeStack.top());
treeStack.pop();//访问后弹出来
}
}
}