說到非遞歸遍歷,很多人可以想到藉助棧或者隊列,沒錯,我們層序遍歷就是藉助隊列來實現的。那麼我們今天的中序非遞歸又是怎末做到的呢?
首先,我們先看看中序遍歷的規律,分析思路才能更方便寫代碼
如上圖所示的二叉樹,我們都知道中序遍歷是:左子樹----根節點----右子樹。遍歷結果爲:3 2 1 5 4 6
從結果以及中序遍歷的特點可以看出,從根節點一直向左下,直到拿到根節點左子樹的最左節點(也就是3),然後纔打印3、2、1
由此我們便可以聯想到棧的特性:先進後出
同時我們把根節點的右子樹也看成一顆二叉樹,遍歷結果是:5 4 6.也是將左子樹一次入棧,直到最後一個左子樹節點,然後訪問棧頂元素並將其出棧,再判斷是否有右子樹。
至此 我們可以總結一下:
1>先找以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;
}
}