剑指offer给定二叉树,求中序遍历的下一个 节点,前序遍历,后序遍历扩展

题目链接https://www.nowcoder.com/practice/9023a0c988684a53960365b889ceaf5e?tpId=13&tqId=11210&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

如有更优的解法:欢迎提点

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
 */

/*
 * 
 * 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。
 *	注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
 *
 *中序遍历:先左子树,后根节点,再右子树
 *前序遍历:先根节点,后左子树,再右子树
 *后序遍历:先左子树,后右子树,再根节点。
 *
 *
 *		     A
 *		   /   \
 *		  B     C
 *	  	 / \   / \
 *		D   E F   G
 *  	 	   / \
 *  		  H   I
 *  
 *   DBHEIAFCG----中序遍历
 *   ABDEHICFG----前序遍历
 *   DHIEBFGCA----后序遍历

 */
public class Solution22 {

	/*
	 * 中序遍历 思路: 
	 * (1) 若该节点存在右子树:则下一个节点为右子树最左子节点(如图节点 B ) 
	 * (2) 若该节点不存在右子树:这时分两种情况:
	 * 2.1 该节点为父节点的左子节点,则下一个节点为其父节点(如图节点 D ) 
	 * 2.2该节点为父节点的右子节点,则沿着父节点向上遍历,直到找到一个节点的父节点的左子节点为该节点, 则该节点的父节点下一个节点(如图节点 I,沿着父节点一直向上查找找到 B ( B 为其父节点的左子节点),则 B 的父节点 A 为下一个节点)。
	 */
	public TreeLinkNode GetNext(TreeLinkNode pNode) {
		// 该节点为空节点
		if (pNode == null) {
			return null;
		}
		// 该节点有右子树,下一节点为右子树最左节点
		if (pNode.right != null) {
			// 指向右子树的根节点
			pNode = pNode.right;
			// 查找最左子树
			while (pNode.left != null) {
				pNode = pNode.left;
			}
			return pNode;
		}
		// 该节点无右子树,
		while (pNode.next != null) {
			TreeLinkNode proot = pNode.next;
			// 该节点是父节点的左子节点,返回父节点
			if (proot.left == pNode) {
				return proot;
			}
			// 改节点是父节点的右子树,向上继续找到直到该节点是父节点的左子节点
			if (proot.right == pNode) {
				pNode = proot;
			}
		}
		// 直到为根节点时,则返回null
		return null;

	}

	/**
	 * 前序遍历 
	 * 1.只有根节点时,节点为空时(节点A) 
	 * 2.有左子节点时,直接返回左子节点 
	 * 3.无左子节点时,向上遍历父节点知道得到右子节点
	 * 这里有一个特殊情况,就是当该节点本身就是右子节点时,需要保存自身,在往上遍历
	 * 
	 * */
	public TreeLinkNode GetNextbyFirst(TreeLinkNode pNode) {
		if (pNode == null) {
			return null;
		}
		// 只有根节点的情况(节点A)
		if (pNode.next == null && pNode.left == null && pNode.right == null) {
			return null;
		}
		// 如果有左子节点,直接返回(节点BCE)
		if (pNode.left != null) {
			return pNode.left;
		}
		// 标记当前节点
		TreeLinkNode p = pNode;
		// 当前节点无左子节点时,
		while (pNode != null) {
			// 如果有右子节点,则返回右子节点,否则往上找父节点的兄弟
			if (pNode.right != p && pNode.right != null) {
				return pNode.right;
			} else {
				p = pNode;
				pNode = pNode.next;
			}
		}
		return null;
	}

	/**
	 * 后序遍历--左右根
	 * 
	 * 
	 * 
	 * */
	public TreeLinkNode GetNextbyLast(TreeLinkNode pNode) {
		if (pNode == null || pNode.next == null) {
			return null;
		}
		// 该节点为右子树上的节点,且该节点无子节点,则后序遍历的下一个节点是该节点的父节点
		if (pNode.left == null && pNode.right == null) {
			// 该节点为父节点的左子节点
			if (pNode.next.left == pNode) {
				// 该节点无右兄弟
				if (pNode.next.right == null) {
					return pNode.next;
				}
				// 该节点有右兄弟子树
				else {
					// 找到最左子节点
					pNode = pNode.next.right;
					while (pNode != null) {
						// 左子节点不为空
						if (pNode.left != null) {
							pNode = pNode.left;
						}
						// 左子节点为空,右子节点不为空
						else if (pNode.right != null) {
							pNode = pNode.right;
						}
						// 左右子节点都为空
						else {
							return pNode;
						}
					}
				}
			}

		}
		// 该节点为父节点的左子节点
		if (pNode.left != null && pNode.right != null
				&& pNode.next.left == pNode) {
			// 该节点无右兄弟
			if (pNode.next.right == null) {
				return pNode.next;
			}
			// 该节点有右兄弟子树
			else {
				// 找到最左子节点
				pNode = pNode.next.right;
				while (pNode != null) {
					// 左子节点不为空
					if (pNode.left != null) {
						pNode = pNode.left;
					}
					// 左子节点为空,右子节点不为空
					else if (pNode.right != null) {
						pNode = pNode.right;
					}
					// 左右子节点都为空
					else {
						return pNode;
					}
				}
			}
		}
		// 该节点为父节点的右子节点,则返回父节点,节点I,
		if (pNode.next.right == pNode) {
			return pNode.next;
		}
		return pNode;

	}

	public static void main(String[] args) {
		TreeLinkNode A = new TreeLinkNode("A");
		TreeLinkNode B = new TreeLinkNode("B");
		TreeLinkNode C = new TreeLinkNode("C");
		TreeLinkNode D = new TreeLinkNode("D");
		TreeLinkNode E = new TreeLinkNode("E");
		TreeLinkNode F = new TreeLinkNode("F");
		TreeLinkNode G = new TreeLinkNode("G");
		TreeLinkNode H = new TreeLinkNode("H");
		TreeLinkNode I = new TreeLinkNode("I");
		A.next = null;
		A.left = B;
		A.right = C;
		B.next = A;
		B.left = D;
		B.right = E;
		D.next = B;
		D.left = D.right = null;
		E.next = B;
		E.left = H;
		E.right = I;
		H.next = E;
		H.left = H.right = null;
		I.next = E;
		I.left = I.right = null;
		C.next = A;
		C.left = F;
		C.right = G;
		F.next = C;
		F.left = F.right = null;
		G.next = C;
		G.left = G.right = null;

		// * DBHEIAFCG----中序遍历
		// * ABDEHICFG----前序遍历
		// * DHIEBFGCA----后序遍历
		// try {
		// Solution22 s22 = new Solution22();
		// TreeLinkNode p1 = s22.GetNext(A);
		// System.out.println("p1=="+p1.val);
		// TreeLinkNode p2 = s22.GetNextbyFirst(I);
		// System.out.println("p2=="+p2.val);
		// } catch (Exception e2) {
		// System.out.println("null");
		// }
		Solution22 s22 = new Solution22();
		TreeLinkNode p2 = s22.GetNextbyLast(D);
		// System.out.println(""+p2);
		while (p2 != null) {
			try {
				System.out.println("p2==" + p2.val);
				p2 = s22.GetNextbyLast(p2);
			} catch (Exception e2) {
				// TODO: handle exception
				System.out.println("null");
			}

		}

	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值