二叉树的先序中序以及后序遍历(递归 && 非递归)
Posted bywallance
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树的先序中序以及后序遍历(递归 && 非递归)相关的知识,希望对你有一定的参考价值。
树节点定义:
class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } }
递归建立二叉树:
//递归建立二叉树 public static void BuildTree(TreeNode node, int data){ if(node == null){ node = new TreeNode(data); } if(data <= node.val){ if(node.left == null){ node.left = new TreeNode(data); }else{ BuildTree(node.left, data); } } if(data > node.val){ if(node.right == null){ node.right = new TreeNode(data); }else{ BuildTree(node.right, data); } } }
1、先序遍历
遍历方式:根节点-->左节点-->右节点
递归先序遍历:
//先序递归遍历二叉树 public static List<Integer> preTravese(TreeNode root,List<Integer> arr){ if(root == null) return arr; if(root != null){ arr.add(root.val); arr = preTravese(root.left,arr); arr = preTravese(root.right,arr); } return arr; }
非递归遍历:
对于任意一个结点p
1)访问结点p,并将p入栈
2)将p变为p的左孩子结点,如果p的不为空,循环至 1); 否则弹出当前栈顶使用p接收,将p变为p的右孩子结点;
3)当p结点为null并且栈为空时,结束循环。
代码:
//非递归先序遍历 public static List<Integer> preorderTraversal(TreeNode root){ List<Integer> arr = new ArrayList<Integer>(); if(root == null){ return arr; } Stack<TreeNode> ts = new Stack<TreeNode>(); TreeNode ptr = root; while( ptr != null || !ts.isEmpty()){ while(ptr != null){ arr.add(ptr.val); ts.push(ptr); ptr = ptr.left; } if( !ts.isEmpty()){ ptr = ts.pop(); ptr = ptr.right; } } return arr; }
2、中序遍历
遍历方式: 左子树-->根节点-->右子树
递归中序遍历:
//中序递归遍历二叉树 public static List<Integer> inTravese(TreeNode root,List<Integer> arr){ if(root == null) return arr; if(root != null){ arr = inTravese(root.left,arr); arr.add(root.val); arr = inTravese(root.right,arr); } return arr; }
非递归中序遍历:
对于任意一个结点p
1)当结点不为null,将结点压栈;
2)将p更新为它的左孩子,如果左孩子不为空,循环至 1);否则弹出栈顶元素赋值给p,访问p结点,p更新为p的右孩子;
3)当p为null 并且栈为空时结束循环。
代码:
//中序非递归遍历 public static List<Integer> inorderTraversal(TreeNode root){ List<Integer> arr = new ArrayList<Integer>(); if(root == null){ return arr; } Stack<TreeNode> ts = new Stack<TreeNode>(); TreeNode ptr = root; while( ptr != null || !ts.isEmpty() ){ while(ptr != null){ ts.push(ptr); ptr = ptr.left; } if(!ts.isEmpty()){ ptr = ts.pop(); arr.add(ptr.val); ptr = ptr.right; } } return arr; }
3、后序遍历
遍历方式:左子树-->右子树-->根节点
递归遍历:
//后序递归遍历二叉树 public static List<Integer> lastTravese(TreeNode root,List<Integer> arr){ if(root == null) return arr; if(root != null){ arr = lastTravese(root.left,arr); arr = lastTravese(root.right,arr); arr.add(root.val); } return arr; }
非递归遍历:
对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因为其右孩子还没有被访问。
接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。
这样就可以保证正确的访问顺序。
可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。
代码:
首先新建一个类来记录结点是否是第一次弹栈:
//新建一个类,用来记录该结点是不是第一次弹栈 class NewTreeNode{ TreeNode ptr; boolean isFirst; public NewTreeNode(TreeNode ptr){ this.ptr = ptr; this.isFirst = true; } }
非递归后序遍历二叉树:
//后序非递归遍历二叉树 public static List<Integer> lastTraverse(TreeNode root){ List<Integer> arr = new ArrayList<Integer>(); if(root == null){ return arr; } Stack<NewTreeNode> nts = new Stack<NewTreeNode>(); NewTreeNode nptr = null; TreeNode ptr = root; while( ptr!= null || !nts.isEmpty()){ while(ptr != null){ nptr = new NewTreeNode(ptr); nts.push(nptr); ptr = ptr.left; } if(!nts.isEmpty()){ nptr = nts.pop(); if(nptr.isFirst){ nptr.isFirst = false; nts.push(nptr); ptr = nptr.ptr.right; }else{ arr.add(nptr.ptr.val); //ptr置为null,因为此时它的左右子树都已经访问完毕 ptr = null; } } } return arr; } }
以上是关于二叉树的先序中序以及后序遍历(递归 && 非递归)的主要内容,如果未能解决你的问题,请参考以下文章