关于二叉树遍历,先序,中序,后序其实都是很简单了。 二叉树一般定义:
public class Node{ public int value; public Node left; public Node right; public Node(int val){ this.val=val; } }先序遍历
public void preOrder(Node tree){ if(tree==null) return; System.out.println(tree.val); preOrder(tree.left); preOrder(tree.right); }中序,后序仅仅是语句的交换。非常简单,不给出了。
所有递归实现的算法,都可用非递归实现: 思路: 一般将递归转为非递归,不是利用循环就是利用栈。 我们可以自己申请栈来实现: 步骤如下: 1. 申请一个新的栈,将头节点压入栈 2. 从栈中弹出栈顶节点,记为cur,然后打印cur节点的值,再将节点cur的右孩子压入stack,最后压入left child 3. 不断重复步骤2. 直到栈空,全部过程结束
弹出一个结点的时候,如果它有孩子的话! 要压入它的左右孩子节点! 没有就直接弹出
代码:
public void preOrderRecur(Node head){ if(head!=null){ Stack<Node> stack=new Stack<Node>(); stack.push(head); //add也可以,但add是ArrayList或者说List类的方法 while(!stack.empty()){ head=stack.pop(); System.out.println(head.val); if(head.right!=null){ stack.push(head.right); } if(head.left!=null){ stack.push(head.left); } } } }这种弹出父结点然后就压入它的左右子节点的做法是最经常用到的技巧! !
总结这个方法: push到left为空,pop到right不为空!
直观的想法: 使用两个栈实现。 压入head节点 第一个栈负责依次 弹出父节点 ,然后压入 左子节点 由右子节点 注意是先左后右的压入,其实因为我们用了第二个栈 弹出的节点都压入第二个栈! 所以我们要保证第二个栈弹出的顺序是 后序遍历的顺序,所以按照左先右后的压入第一个栈,那么弹出第二个栈的时候就肯定是左边先出,右边后出! 最后我们只需要依次弹出打印右边的即可
public void postOrderUnRecur(Node head){ if(head!=null){ Stack<Node> s1=new Stack<Node>(); Stack<Node> s2=new Stack<Node>(); s1.push(head); while(!s1.empty()){ head=s1.pop();//update s2.push(head); if(head.left!=null){ s1.push(head.left); } if(head.right!=null){ s2.push(head.right); } } while(!s2.empty()){ System.out.println(s2.pop().val+" "); } } }还有一种方法,使用一个栈实现后序非递归 它的思想是多设置两个变量h和c 。h代表最近一次弹出并打印的节点 c代表栈顶节点。 然后分3种情况处理。这个算法后续再讨论