用递归方法能解决的问题,都能用非递归解决,因为递归利用的原理是函数栈来保存信息,我们可以通过数据结构的栈来实现。(以下分析,自己画图效果最佳)
Node.java
public class Node {
public int value;
public Node left;
public Node right;
public Node(int value)
{
this.value=value;
}
}
BinaryTree.java
public class BinaryTree {
//构造二叉树
public Node MatkeTree(int[] arr,int index)
{
Node temp=null;
if(index<arr.length)
{
temp=new Node(arr[index]);
temp.left=MatkeTree(arr, index*2+1);//arr[index*2+1]的值应该给左节点
temp.right=MatkeTree(arr, index*2+2);//arr[index*2+2]的值应该给右节点
//树从的层次遍历就是数组arr[0]到arr[Last];
return temp;
}
//如果index超出数组的范围,则直接返回null
return temp;
}
public static void main(String[] args) {
int[] arr= {9,6,4,2,3,7,1,0};
BinaryTree bTree=new BinaryTree();
Node root=bTree.MatkeTree(arr,0);
}
}
非递归
先序(根 左 右):由于栈是后进先出,则二叉树节点的入栈的顺序应该是:输出当前值(也就是当前根节点)、右子树入栈、左子树入栈。再去栈顶元素,重新上述操作,该操作过程就是遍历根、左、右的过程。
public void PreOrder1(Node head)
{
if(head!=null)
{
Stack<Node> stack=new Stack<>();
stack.push(head);
while(!stack.isEmpty())
{
Node t=stack.pop();
if(t.right!=null)
stack.push(t.right);
if(t.left!=null)
stack.push(t.left);
System.out.print(t.value+" ");
}
}
}
中序(左根右):
1.申请一个新的stack,还有一个声明变量cur=head
2.把cur压入栈,再把cur的左节点依次压入栈,及通过cur=cur.left,
3.一直重新2操作,直到cur为空,取出栈顶元素node打印node.value,再把cur=node.right;
public void InOrder1(Node head)
{
Node cur=head;
Stack<Node> stack=new Stack<>();
while(!stack.isEmpty()||cur!=null)
{
if(cur!=null)
{
stack.push(cur);
cur=cur.left;
}
else
{
cur=stack.pop();
System.out.print(cur.value+" ");
cur=cur.right;
}
}
}
后序(左右根):
在草稿纸上画有助于理解。
1.申请两个栈stack1,stack2.,把head压入栈stack1.
2.取stack1栈顶元素node,把node.left,node.right依次压入stack1。再把node.value压入satck2栈。
3.重复步骤2。直到stack1为空。
4.从stack2取出元素的过程就是左右根
public void PostOrder1(Node head)
{
if(head!=null)
{
Stack<Node> stack1=new Stack<>();
Stack<Integer> stack2=new Stack<>();
stack1.add(head);
while(!stack1.isEmpty())
{
Node t=stack1.pop();
if(t.left!=null)
stack1.push(t.left);
if(t.right!=null)
stack1.push(t.right);
stack2.push(t.value);
}
while(!stack2.isEmpty())
{
System.err.print(stack1.pop()+" ");
}
}
}
只使用一个栈实现后序遍历:
1.新建一个栈stack,还有变量last_print:代表最近弹出栈并打印了的节点, top:代表栈的栈顶元素。
2.初始时,last_print=head,top=null;
三种情况分析:
(1)top.left ! = null&&last_print ! =top.left&&last_print ! =top.right时代表左子树还没处理过,左子树入栈
特别注意的是这里不用加上top.right ! = null (当top.right = = null时,而前面的三条逻辑都正确,就是因为right==null,会导致left不会入栈 )(而这里 的top.left ! = null是必须加的,如果不加,可能把null入栈了)
(2)top.right ! =null&&last_print ! =top.right时代表右子树还没处理过,右子树入栈
(3)此时就是左子树已经处理,右子树也已经处理,则打印栈顶元素的值,并且last_print = top;top = stack.peek();
public void PostOrder2(Node head)
{
if(head!=null)
{
Stack<Node> stack=new Stack<>();
stack.push(head);
Node last_print=head;
Node top=null;
while(!stack.isEmpty())
{
top=stack.peek();
//左子树还没处理
if(top.left!=null&&last_print!=top.left&&last_print!=top.right)
{
stack.push(top.left);
}
//右子树还没处理
else if(top.right!=null&&last_print!=top.right)
{
stack.push(top.right);
}
else //当左右子树已经处理或者左右子树为空时就打印该节点
{
System.out.print(stack.pop().value+" ");
last_print=top;
}
}
}
}
递归遍历
//先序
public void PreOrder(Node head)
{
if(head==null)
return;
System.out.print(head.value+" ");
PreOrder(head.left);
PreOrder(head.right);
}
//中序递归
public void InOrder(Node head)
{
if(head==null)
return;
InOrder(head.left);
System.out.print(head.value+" ");
InOrder(head.right);
}
//后序递归
public void PostOrder(Node head)
{
if(head==null)
return;
PostOrder(head.left);
PostOrder(head.right);
System.out.print(head.value+" ");
}
按层反序列化
public static String serialByLevel(Node head) {
if (head == null) {
return "#!";
}
String res = head.value + "!";
Queue<Node> queue = new LinkedList<Node>();
queue.offer(head);
while (!queue.isEmpty()) {
head = queue.poll();
if (head.left != null) {
res += head.left.value + "!";
queue.offer(head.left);
} else {
res += "#!";
}
if (head.right != null) {
res += head.right.value + "!";
queue.offer(head.right);
} else {
res += "#!";
}
}
return res;
}