带有父节点指针的二叉树找前驱节点和后继节点

带有父节点指针的二叉树找前驱节点和后继节点

题目:给一个正常的二叉树节点类型加一个指向父节点的指针parent。找其中某一个节点的前驱节点和后继节点

*分析:所为前驱节点和后继节点就是找中序遍历。

答:找出一个结点出现的所有可能性并进行操作。可分为下面几种出现的情况
  •  1. 如果该结点无左右子树,判读该结点是否有父节点?
    
  •    1.1 如果有父节点,则判断该节点为父节点的左、右子树?
    
  •        1.1.1 如果为左子树则该父节点就是其后继节点
    
  •        1.1.2 如果为右子树,那么向上找,找出第一个节点有左孩子的那个节点就为其后继节点
    
  •    1.2 如果没有父节点,则这个节点即没有父节点也无左右孩子节点,则为根节点,只需返回null或者返回自己。
    
  •  2. 如果该节点有左孩子,无右孩子,如果此节点是其父节点的左孩子那么返回父节点,如果此节点是父节点的右孩子则返回该节点左孩子的最右孩子
    
  •  3. 如果该节点有右孩子,有无左孩子都可以。即只需返回其右节点的最左节点,就是其后继节点
    

在这里其实有两种方法去写,其实最简单的就是直接递归写中序遍历的代码,然后在根据序列找出前驱和后继,这种方法应该是很多同学第一时间就想到的,也包括我自己。但是如果考虑到算法效率的话,这种写法肯定不是一种时间复杂度低的方法。所有我们注意到题目给我们一个父节点指针,所以肯定有其他方法来写。所以我给大家介绍一下我自己写的第二种方法。

//给一个二叉树节点加一个指向父节点的指针parent

//所谓找后继结点或者是前驱结点就是找中序遍历序列
//找该节点的后继结点
/*
 *  分析:找出一个结点出现的所有可能性并进行操作。可分为下面几种出现的情况
 *      1. 如果该结点无左右子树,判读该结点是否有父节点?
 *        1.1 如果有父节点,则判断该节点为父节点的左、右子树?
 *            1.1.1 如果为左子树则该父节点就是其后继节点
 *            1.1.2 如果为右子树,那么向上找,找出第一个节点有左孩子的那个节点就为其后继节点
 *        1.2 如果没有父节点,则这个节点即没有父节点也无左右孩子节点,则为根节点,只需返回null或者返回自己。
 *      2. 如果该节点有左孩子,无右孩子,如果此节点是其父节点的左孩子那么返回父节点,如果此节点是父节点的右孩子则返回该节点左孩子的最右孩子
 *      3. 如果该节点有右孩子,有无左孩子都可以。即只需返回其右节点的最左节点,就是其后继节点
 *      
 *    总结出这几种可能后,就将返回节点相同的一起写,这样可以优化一下代码。
 * 
 * 
 * */
public class GetLaterNode {
	static class Node {
		public int value;
		Node leftChild;
		Node rightChild;
		Node parent;//

		public Node(int data, Node lc, Node rc,Node p) {
			this.value = data;
			this.leftChild = lc;
			this.rightChild = rc;
			this.parent = p;
		}
	}

	public static void main(String[] args) {
		//初始化一颗树父指针会单独赋值
		Node node4 = new Node(4, null, null,null);
		Node node5 = new Node(5, null, null,null);
		Node node2 = new Node(2, node4, node5,null);
		Node node3 = new Node(3, null, null,null);
		Node node1 = new Node(1, node2, node3,null);
		//给父指针赋值
		node4.parent = node2;
		node5.parent = node2;
		node2.parent = node1;
		node1.parent = null;
		node3.parent = node1;
		
		//如果打印本身 就代表无后继或者前驱
		System.out.println(getLaterNode(node3).value);//打印后继结点
		System.out.println(getFrontNode(node3).value);//打印后继节点
	}
     
	//找后继节点
	public static Node getLaterNode(Node node) {
		if (node == null)
			return node;
		
		//定义parent = node.parent
		Node parent = node.parent;
		
		// 如果有右子树找到右子树最左节点为该子树的后继结点
		if (node.rightChild != null) {
			return getMostLeft(node.rightChild);
		}
		
		// 如果左右子树都无
		else if(node.rightChild==null && node.leftChild==null){
			if(parent!=null&&parent.leftChild==node){
				return parent;
			}
			
		else if(parent!=null&&parent.rightChild==node){
			    //保存变量,如果while没有查到那个合适的元素,不能返回空指针异常。
			    Node node1 = node;
				while (parent != null && parent.rightChild == node) {
					node = parent;
					parent = node.parent;
				}
				return parent==null ? node1 : parent;
			}
		}
		
		else {// 如果无右子树那就看是否有父节点,向上找,找出第一个节点有左孩子那个节点
			
			while (parent != null && parent.rightChild == node) {
				node = parent;
				parent = node.parent;
			}
			return node;
		}
		return node;
	}
    //找最左节点
	public static Node getMostLeft(Node node) {
		if (node == null)
			return node;// 返回自己表示没有后继
		while (node.leftChild != null) {
			node = node.leftChild;
		}
		return node;
	}
	
	// 找前驱结点
	/*
	 * 分析:与后继节点的分析基本类似
	 *     
	 * */
	public static Node getFrontNode(Node node) {
		Node parent = node.parent;
		if (node == null)
			return node;
		else if (node.leftChild != null && node.rightChild == null)
			return getMostRight(node.leftChild);// 当左孩子不为空,右孩子为空时 应该找左孩子的最右结点
		else if (node.leftChild == null && node.rightChild != null)
			return node;// 返回自己 表示没有前驱
		else if (node.leftChild != null && node.rightChild != null)
			return node.leftChild;
		else if (node.leftChild == null && node.rightChild ==null){
			Node node1 =node;//避免后面while循环找不到那个节点,返回空的情况;
			//如果该节点为父亲节点的左孩子,向上找第一个节点有右孩子的那个节点
			while(parent != null && parent.rightChild != node) {
				node = parent;
				parent = node.parent;
			}
			return parent==null ? node1 : parent;
		}
			
		return node;
	}
	// 找左孩子的最右结点
	public static Node getMostRight(Node node) {
		if (node == null)
			return node;

		while (node.rightChild != null) {
			node = node.rightChild;
		}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值