龙空技术网

Java工程师面试1000题224-递归非递归实现二叉树前、中、后序遍历

老胖鱼头 288

前言:

而今我们对“二叉树的先序中序后序遍历伪代码”大约比较关切,各位老铁们都需要剖析一些“二叉树的先序中序后序遍历伪代码”的相关资讯。那么小编在网上网罗了一些对于“二叉树的先序中序后序遍历伪代码””的相关资讯,希望咱们能喜欢,姐妹们一起来了解一下吧!

224、使用递归和非递归实现二叉树的前、中、后序遍历

使用递归来实现二叉树的前、中、后序遍历比较简单,直接给出代码,我们重点讨论非递归的实现。

class Node { public int value; public Node left; public Node right; public Node() { } public Node(int value) { this.value = value; }}public class Solution { //递归实现前序遍历 public void preOrderRecur(Node head){ if (head == null) return; System.out.println(head.value + " "); preOrderRecur(head.left); preOrderRecur(head.right); }  //递归实现中序遍历 public void inOrderRecur(Node head){ if (head == null) return; inOrderRecur(head.left); System.out.println(head.value + " "); inOrderRecur(head.right); } //递归实现后续遍历 public void posOrderRecur(Node head){ if (head == null) return; posOrderRecur(head.left); posOrderRecur(head.right); System.out.println(head.value + " "); }}

凡是可以使用递归可以解决的问题都可以使用非递归的方法来实现。这是因为递归方法无非就是利用函数栈来保存信息,如果用自己申请的数据结构来代替函数栈,也可以实现相同的功能。

用非递归的方法实现二叉树的先序遍历,具体过程如下:

1、申请一个新的栈,记为stack。然后将头结点head压入stack中;

2、从stack中弹出栈顶节点,记为cur,然后打印cur节点的值,再将节点cur的右孩子节点(如果不为空)先压入到stack中,最后将cur的左孩子节点(如果不为空)压入stack中。

3、不断重复步骤2,直到stack为空,过程全部结束。

下面举例说明整个过程,假如存在一颗二叉树如图所示:

节点1先入栈,然后弹出并打印。接下来把节点3压入栈,再把节点2压入栈,此时stack从顶到底依次为2、3;节点2弹出并打印,把节点5压入栈,再把节点4压入栈,此时栈中从顶到底元素依次为4、5、3;节点4弹出并打印,由于节点4没有孩子节点可以压入栈,所以此时栈中元素从顶到底依次为5、3;节点5弹出并打印,由于节点5没有孩子节点可以压入栈,所以此时栈中元素仅有3;节点3弹出并打印,先把节点7压入栈,再把节点6压入栈,此时栈中元素从顶到底依次为6、7;节点6弹出并打印,由于节点6没有孩子节点可以压入栈,所以此时栈中元素仅有7;节点7弹出并打印,由于节点7没有孩子节点可以压入栈,此时stack中为空,过程停止。

整个过程请参考如下代码:

 //不用递归实现前序遍历 public void preOrderUnRecur(Node head){ System.out.print("前序遍历:"); if (head != null){ Stack<Node> stack = new Stack<>(); stack.add(head); while (!stack.isEmpty()){ head = stack.pop(); System.out.print(head.value + " "); if (head.right != null){ stack.push(head.right); } if (head.left != null){ stack.push(head.left); } } } System.out.println(); }

用非递归的方式来实现二叉树的中序遍历,具体过程如下:

申请一个新的栈,记为stack。初始时,令变量cur = head;先把cur节点压入栈中,对以cur节点为头结点的整颗子树来说,依次把左边界压入栈中,即不停的令cur= cur.left;然后重复此步骤;不断重复步骤2,直到发现cur为空,此时从stack中弹出一个节点,记为node。打印node的值,并且让cur = node.right,然后继续重复步骤2;当stack为空且cur为空时,整个过程停止。

还是以上图的二叉树为例子来说明整个过程:

初始时cur为节点1,将节点1压入栈,令cur= cur.left,此时cur变为节点2;cur为节点2,将节点2压入栈中,令cur = cur.left,即此时cur变为节点4;cur为节点4,将节点4压入栈中,令cur = cur.left,此时cur变为了null,此时栈中元素从顶到底依次为4、2、1;cur为null,从栈中弹出节点4(node)并打印,并令cur = node.right,cur仍然为null,此时stack中从顶到底依次为2、1;cur为null,从栈中弹出节点2(node)并打印,并令cur = node.right,此时cur变为节点5,此时栈中元素只有1;cur为节点5,将节点5压入stack中,并令cur = cur.left,此时cur变为null,栈中元素有5、1;cur为null,从栈中弹出节点5(node)并打印,并令cur = node.right,即cur仍为null,此时栈中元素为1;cur为null,从栈中弹出节点1(node)并打印,并令cur = node.right,即cur变为节点3,此时栈中为空;cur为节点3,将节点3压入栈中,令cur = cur.left,此时cur变为节点6,此时栈中仅有元素3;cur为节点6,将节点6压入栈中,令cur = cur.left,此时cur变为null,此时栈中有元素6、3;cur为null,弹出节点6(node)并打印,令cur = node.right,cur仍为null,此时栈中元素仅有3;cur为null,弹出节点3(node)并打印,令cur = node.right,cur变为节点7,此时栈中为空;cur为节点7,将节点7压入栈,令cur = cur.left,此时cur变为null,此时栈中仅有元素7;cur为null,弹出节点7(node)并打印,令cur = node.right,cur仍然为null,此时栈stack也为null。cur和stack同时为null,整个过程终止。

代码如下:

 //不用递归实现中序遍历 public void inOrderUnrecur(Node head){ System.out.println("in-Order:"); if (head != null){ Stack<Node> stack = new Stack<>(); while (!stack.isEmpty() || head != null){ if (head != null){ stack.push(head); head = head.left; }else { head = stack.pop(); System.out.print(head.value + " "); head = head.right; } } } System.out.println(); }

用非递归方式实现二叉树后序遍历有点麻烦。下面介绍使用两个栈来实现后序遍历的过程,具体步骤如下:

申请一个栈记为s1,然后将头结点压入s1中;从s1中弹出的节点记为cur,然后依次将cur的左孩子和右孩子压入s1中;在整个过程中,每一个从s1中弹出的节点都放进s2中;不断重复步骤2和步骤3,直到s1为空,过程停止;然后从s2中依次弹出节点并打印,打印的顺序就是后序遍历的顺序。

下面还是使用上面的图示二叉树来演示整个过程:

申请两个栈s1和s2,将头结点1压入s1中,然后再从s1中弹出节点1,再把节点1压入s2中,再把节点2和节点3一次压入s1,此时s1从栈顶到栈底元素为3、2;s2从栈顶到栈底只有1;从s1中弹出节点3,节点3放入s2中,然后将节点3的两个孩子节点6和节点7一次压入s1,此时s1从栈顶到栈底元素依次为7、6、2;s2中为3、1;从s1中弹出节点7,节点7放入s2中,由于节点7没有孩子,不需要往s1中添加任何元素,此时s1中保存6、2;s2中保存7、3、1;从s1中弹出节点6,节点6放入s2中,由于节点6没有孩子,不需要往s1中添加任何元素,此时s1中保存2,s2中保存6、7、3、1;从s1中弹出节点2,节点2放入s2中,然后将节点2的两个孩子节点4和节点5一次压入s1中,此时s1从栈顶到栈底元素为5、4;s2中存放的元素为2、6、7、3、1;从s1中弹出节点5,节点5放入s2中,节点5无孩子节点,不需要往s1中添加任何元素,此时s1中保存4;s2中保存5、2、6、7、3、1;从s1中弹出节点4,节点4放入s2中,节点4无孩子节点,不需要往s1中添加任何节点,此时s1中为空,s2中保存的元素从栈顶到栈底依次是4、5、2、6、7、3、1;过程结束,依次弹出并打印s2中的节点即可。

通过如上过程我们知道,每棵子树的头结点都是先从s1中弹出,然后再把该节点的两个孩子节点按照先左再右的顺序依次压入s1,那么从s1弹出的顺序就是先右后左,所以从s1中弹出的顺序就是中、右、左。然后,s2重新收集的过程就是把s1的弹出顺序逆序,所以s2从栈顶到栈底的顺序就变成了左、右、中。

代码如下:

 //不用递归实现后续遍历 public void posOrderUnRecur(Node head){ System.out.println("pos-order: "); if (head != null){ Stack<Node> s1 = new Stack<>(); Stack<Node> s2 = new Stack<>(); s1.push(head); while (!s1.isEmpty()){ head = s1.pop(); s2.push(head); if (head.left != null){ s1.push(head.left); } if (head.right != null){ s1.push(head.right); } } while (!s2.isEmpty()){ System.out.print(s2.pop().value + " "); } } System.out.println(); }

标签: #二叉树的先序中序后序遍历伪代码 #用非递归方法实现递归算法时一定要使用递归工作栈