就以这个树为例,来讲讲二叉树的非递归遍历。
先序遍历: 先序遍历结果为3 4 6 5 8 9,就拿树的左枝为例,3是根,打印,4是3的左孩子,打印,6是4的左孩子,打印,6的左孩子为空,所以返回到4,然后去找4的右孩子,4的右孩子也为空,返回到3,这就是左子树遍历的过程。然后非递归主要用到栈来存储结点,栈先进后出,所以应该是右孩子先入栈,左孩子后入栈,这样pop就能先得到左孩子。先将根结点3入栈,接下来就是开始循环,循环结束的条件就是栈为空,先弹出栈顶,再打印栈顶,如果栈顶的右孩子不为null,就把右孩子放进栈中,如果栈顶的左孩子不为null,就把左孩子放入栈中。
用下面一幅图来说明整个过程
void pretravel2(TreeNode root) {
if (root == null) return;
Stack<TreeNode> s = new Stack<TreeNode>();
s.push(root);
while (!s.isEmpty()) {
TreeNode node = s.pop();
System.out.print(node.val+" ");
if (node.right != null) {
s.push(node.right);
}
if (node.left != null) {
s.push(node.left);
}
}
}
中序遍历:中序遍历的结果为6 4 3 8 5 9,其实就是左遍历完了,弹出根,找根的右结点,整个过程是先一路找左结点,找到左结点为null的6,然后找6的根4,接着找4的右,为null,接着找4的根3,接着一路找3的左,直到结点的左孩子为null,这就找到了8,然后找8的根5,再找5的右9,这样就找完了。他们的入栈出栈顺序:根结点入栈,左孩子直接入栈,并且标记这个结点已经走过,以防后面再走,当发现哪个结点的左孩子为null的时候,就打印这个结点,并且将这个结点出栈,让他的右孩子入栈
void intravel2(TreeNode root) {
if(root==null)
return ;
Stack<TreeNode> stack=new Stack<>();
stack.push(root);
//使用list来标记结点是否走过
List<TreeNode> list=new ArrayList<>();
while(!stack.isEmpty()) {
//只需要拿到根结点,不需要pop出来
TreeNode peek = stack.peek();
//如果左孩子不为null并且左孩子没有被走过,就把他放到栈里,并且标记为走过
if(peek.left!=null&& !list.contains(peek.left)) {
stack.push(peek.left);
list.add(peek.left);
}
else {
//左孩子为空,打印根结点,根结点出栈,右孩子进栈
TreeNode pop = stack.pop();
System.out.print(pop.val+" ");
if(pop.right!=null)
stack.push(pop.right);
}
}
}
中序遍历还有另外一种写法:
void intravel3(TreeNode root) {
Stack<TreeNode> stack=new Stack<>();
TreeNode p=root;
while(p!=null||!stack.isEmpty()) {
while(p!=null) {