说到非递归遍历,很多人可以想到借助栈或者队列,没错,我们层序遍历就是借助队列来实现的。那麽我们今天的中序非递归又是怎末做到的呢?
首先,我们先看看中序遍历的规律,分析思路才能更方便写代码
如上图所示的二叉树,我们都知道中序遍历是:左子树----根节点----右子树。遍历结果为:3 2 1 5 4 6
从结果以及中序遍历的特点可以看出,从根节点一直向左下,直到拿到根节点左子树的最左节点(也就是3),然后才打印3、2、1
由此我们便可以联想到栈的特性:先进后出
同时我们把根节点的右子树也看成一颗二叉树,遍历结果是:5 4 6.也是将左子树一次入栈,直到最后一个左子树节点,然后访问栈顶元素并将其出栈,再判断是否有右子树。
至此 我们可以总结一下:
1>先找以root为根的左子树最左下的节点,并保存所经路径的所有节点---》保存到栈里。
2>然后遍历栈顶的元素并将栈顶元素出栈-------->先打印栈顶元素并且出栈,然后再判断栈顶的是否有右孩子
3>获取栈顶元素(也就是root根节点左下的节点)判断是否有右子树
-
如果该栈顶元素有右孩子: 将该右孩子当作以刚才遍历左子树的方式继续入栈;
-
没有右孩子: 直接出栈
方法一:
class Solution {
//找到左子树最左下的节点
private void leftOrder(TreeNode cur,Stack<TreeNode> stack)
{
//有左子树节点
while(cur!=null)
{
//先入栈
stack.push(cur);
cur=cur.left;
}
}
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList();
if(root==null)
{
return list;
}
TreeNode cur=root;
Stack<TreeNode> stack=new Stack<>();
leftOrder(cur,stack);
//判断栈顶元素是否有右孩子
while(!stack.empty())
{
if(stack.peek().right!=null)
{//有右孩子,让其按照寻找最左下节点继续遍历
list.add(stack.peek().val);
TreeNode lcur=stack.pop();
leftOrder(lcur.right,stack);
}else{//栈顶元素没有右孩子
//遍历并出栈
list.add(stack.peek().val);
stack.pop();
}
}
return list;
}
}
方法二:
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList();
if(root==null)
{
return list;
}
//1.先找根节点的最做下的节点,并且将该路径上的所有节点保存到栈里
TreeNode cur=root;
Stack<TreeNode> stack=new Stack<>();
while(!stack.empty() ||cur!=null)
{
//有左子树节点
while(cur!=null)
{
//先入栈
stack.push(cur);
cur=cur.left;
}
//2.得到最左下节点--->栈顶元素
TreeNode node=stack.peek();
//3.打印栈顶元素,并且判断是否有右子树
if(stack.peek().right!=null)
{//有右孩子,让其按照寻找最左下节点继续遍历
list.add(stack.peek().val);
cur=stack.pop().right;//栈顶出栈,并将cur置为栈顶的右孩子
}else{//栈顶元素没有右孩子
//遍历并出栈
list.add(stack.peek().val);
stack.pop();
}
}
return list;
}
}