从前序中序遍历序列构造二叉树的迭代算法理解

力扣上这道题的大神的迭代解法不是特别好理解,比如 详细通俗的思路分析,多解法 的迭代算法,看着解法新颖,但是我看了大半天都吃不透。后来想到了一个关于栈的算法题,就是给定两个数组 A 和 B,A 代表的是元素入栈的顺序,问 B 的元素顺序是不是 A 的出栈顺序。可以说,理解了出栈顺序这道题,基本就理解了这个二叉树构造的迭代算法了。

数组 A :[1,2,3,4,5],数组 B1 :[5,4,3,2,1],B2:[4,5,3,2,1],B3 :[3,4,5,2,1]。数组 B1,B2,B3 均是数组 A 的合法出栈顺序。我们可以发现,每次都是从 A 里面拿元素放入栈中,然后看栈顶元素值是不是和数组 B 指针指向的值相等,相等则弹出,否则不断将数组 A 的元素入栈。

而构造树,相对出栈顺序而言,要复杂一点,首先它是二维的,再一个就是任一节点都和根节点一样,也代表了一棵树,具有递归属性。

public static TreeNode build(int[] preArr, int[] inArr){
	if (preArr == null || inArr == null || preArr.length != inArr.length || inArr.length == 0)
		return null;
	int pre = 0, in = 0;
	TreeNode root = new TreeNode(preArr[pre++]), curRoot = root;
	Stack<TreeNode> s = new Stack<>();
	s.push(root);
	while (pre < preArr.length){
		if (s.peek().val == inArr[in]){
			while (!s.isEmpty() && s.peek().val == inArr[in]){
				curRoot = s.pop();
				in++;
			}
			curRoot.right = new TreeNode(preArr[pre++]);
			s.push(curRoot.right);
			curRoot = curRoot.right;
		} else {
			curRoot.left = new TreeNode(preArr[pre++]);
			s.push(curRoot.left);
			curRoot = curRoot.left;
		}
	}		
	return root;
}

我的理解如下:

1. while 不断遍历前序数组 (出栈题是遍历数组 A)
2. 每次都是先检查栈顶元素是不是等于中序指针指向的元素,然后根据情况入栈 (出栈题也是入栈前,检查栈顶元素是否
等于数组 B 指针指向的值)
	a. 不相等,说明前序数组指针指向的元素是栈顶元素的左子节点
	b. 相等,说明栈顶节点的左子树遍历完了或者为空
	c. 第二个 while 循环是针对某个节点子孙节点都没有右子树的情况
3. 出栈完了后,那么此时的前序元素是 curRoot 节点的右子节点 (出栈题是一维的,树是二维的,所以要用 curRoot 
维持状态,至于为什么是右子节点看文中链接作者给出的反证法)
4. curRoot 的右子节点也需要入栈,然后 curRoot 指向这个右子节点继续遍历
5. 此时,等于完成了一轮根节点的所有左子树节点入栈的过程,入栈和出栈过程中关联节点。当 curRoot 指向某个节点
的右子树节点时,此时的 curRoot 就和 root 性质一样了,逻辑上是“递归”以它为“根”节点的子树遍历过程

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值