二叉树遍历(非递归与递归)

用递归方法能解决的问题,都能用非递归解决,因为递归利用的原理是函数栈来保存信息,我们可以通过数据结构的栈来实现。(以下分析,自己画图效果最佳)

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;
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值