根据二叉树的前序序列和中序序列得到后序序列

一个例子:

前序序列:abdgcefh

中序序列:dgbaechf

求:后序序列

分析:

根据前序序列可知,a肯定是根节点。再在中序序列中找到a,发现a左侧是dgb,右侧是echf,则dgb应该是a的左孩子,echf是a的右孩子。

接着只要递归的判断左右孩子的后序序列就可以了。比如dgb是左孩子的中序序列,则可以根据abdgcefh得到它的前序序列是bdg。右孩子的做法一样。

编程实现思路:

(1)在前序序列中找第一个元素,作为根节点root;

(2)寻找root在中序序列中的位置index,根据index将中序序列分为两部分(leftMidOrder、rightMidOrder),根据index将前序序列分为两部分(leftPreOrder、rightPreOrder);

(3)根据leftPreOrder和leftMidOrder得到root节点的左孩子的后序序列leftPostOrder;

(4)根据rightPreOrder和rightMidOrder得到root节点的右孩子的后序序列rightPostOrder;

(5)leftPostOrder+rightPostOrder+root就是就是后序序列。

代码:

package binarytree;

public class RestoreBinaryTree {
	/**
	 * 根据前序和中序,得到后序
	 * @param preOrder
	 * @param midOrder
	 * @return
	 */
	public static String getPostByPreAndMid(String[] preOrder, String[] midOrder) throws NullPointerException, IllegalArgumentException{
		if(preOrder==null || midOrder==null) throw new NullPointerException("传递的数组不能为null!");
		if(preOrder.length != midOrder.length) throw new IllegalArgumentException("前序数组和中序数组的长度不一致!");
		
		if(preOrder.length==0) return "";
		if(preOrder.length == 1) return preOrder[0];
		
		String postOrder = "";
		String root = preOrder[0];//get root
		int index = indexOf(midOrder, root);
		if(index==-1) throw new IllegalArgumentException("传递的参数不对");
		String[] leftPreOrder = new String[index];
		System.arraycopy(preOrder, 1, leftPreOrder, 0, index);
		String[] leftMidOrder = new String[index];
		System.arraycopy(midOrder, 0, leftMidOrder, 0, index);
		String leftPostOrder = getPostByPreAndMid(leftPreOrder, leftMidOrder);
		
		int rightPartLen = preOrder.length-index-1;
		String[] rightPreOrder = new String[rightPartLen];
		System.arraycopy(preOrder, index+1, rightPreOrder, 0, rightPartLen);
		String[] rightMidOrder = new String[rightPartLen];
		System.arraycopy(midOrder, index+1, rightMidOrder, 0, rightPartLen);
		String rightPostOrder = getPostByPreAndMid(rightPreOrder, rightMidOrder);

		if(leftPostOrder != null && !leftPostOrder.equals("")){
			if(leftPostOrder.endsWith(",")){//判断的目的是为了输出的时候,每个元素以","隔开
				postOrder += leftPostOrder;
			}else{
				postOrder += leftPostOrder + ",";
			}
		}
		if(rightPostOrder != null && !rightPostOrder.equals("")){
			if(rightPostOrder.endsWith(",")){
				postOrder += rightPostOrder;
			}else{
				postOrder += rightPostOrder + ",";
			}
		}
		postOrder += root;
		return postOrder;
	}
	
	/**
	 * 获得元素在数组的索引
	 * @param strArr
	 * @param key
	 * @return
	 */
	private static int indexOf(String[] strArr, String key){
		int index = -1;
		for(int i=0; i<strArr.length; i++){
			if(strArr[i].equals(key)){
				index = i;
				break;
			}
		}
		return index;
	}
	
	public static void main(String[] args) {
		String[] preOrder = new String[]{"a", "b", "d", "g", "c", "e", "f", "h"};
		String[] midOrder = new String[]{"d", "g", "b", "a", "e", "c", "h", "f"};
		String postOrder = getPostByPreAndMid(preOrder, midOrder);
		System.out.println(postOrder);
	}
}

扩展:

根据二叉树的后序序列和中序序列得到前序序列的思路和根据前序、中序得到后序的思路是一样的,不赘述了。

另外能不能根据前序序列和后序序列得到中序序列呢?有可能得到的是一个唯一的中序序列,也有可能得到的是多个中序序列。为什么呢?

原因就是:如果一个父节点只有一个孩子节点,无论这个孩子是左孩子还是右孩子,对于前序序列和后序序列都没有影响,所以这个时候对于相同的前序和后序序列,中序序列的情况可能有多种。那下面的问题就是:什么时候只有一种可能?如果有多种中序序列的可能,怎么求所有可能的中序序列呢?

(1)什么时候只有一种可能?

上面分析中已经指出,有多种中序序列可能的原因是非叶子节点只有一个孩子,所以,如果二叉树中所有的非叶子节点都有两个孩子,则中序序列是唯一确定的。

(2)如果有多种可能,怎么求所有可能的序列呢?

有多种可能,那么一定有若干个非叶子节点只有一个孩子,只要变换孩子的位置,就能得到一个不一样的中序序列。所以算法思路如下:

仍然是递归的想问题:

(1)如果节点的左右孩子皆为空,则返回节点本身;

(2)如果左孩子不为空,返回左孩子所有可能的中序序列;

(3)如果右孩子不为空,返回右孩子所有可能的中序序列;

(4)如果左右孩子均不空,以该节点为根的中序序列的所有可能是:从左孩子可能的中序序列取一个+根节点+右孩子可能的中序序列中取一个;如果只有左孩子,则所有的中序序列是:从左孩子取一个+根节点,和根节点+左孩子的任意一个;只有右孩子的情况和只有左孩子的情况一致。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值