树的查找和删除节点

查找指定节点

使用我们的前中后序遍历找到一个指定节点,查找HeroNode = 4 分别查找了几次?

例子还是我们上面讲到的那个二叉树,我们先分析

前序查找:先判断当前的no是不是要查找的,是就返回当前节点,不是的话,判断当前节点的左子节点是否为空,若不为空则递归前序查找,找到返回,为空(或者没有找到)的话就去判断右子树,跟我们的左子节点一样

emmmm,其他两种都已一样的套路,这里就不多说了

在这里插入图片描述

前序遍历:小王——>小胡——>小黄——>老肥找到

中序遍历:小胡——>小王——>老肥找到

后序遍历:小胡——>老肥找到

上代码,我用的还是上次的那个二叉树,我直接贴方法的代码,其他的就不补充了

节点中的遍历查找方法

/**
	 * 前序遍历查找
	 * @param no  待查找编号
	 * @return
	 */
	public HeroNode preOrderSearch(int no){
    
    
		//判断当前节点是不是
		if(this.no == no){
    
    
			return this;
		}
		//判断左子节点是否为空
		HeroNode resNode = null;//辅助节点
		if(this.left != null){
    
    
			resNode = this.left.preOrderSearch(no);
		}
		if(resNode != null){
    
    
			//说明左子树上找到了
			return resNode;
		}
		if(this.right != null){
    
    
			resNode = this.right.preOrderSearch(no);
		}
		return resNode;
	}
	//中序遍历查找
	public HeroNode infixOrderSearch(int no){
    
    
		HeroNode resNode = null;
		//先判断当前节点的左子节点
		if(this.left != null){
    
    
			resNode = this.left.infixOrderSearch(no);
		}
		if(resNode != null){
    
    
			return resNode;
		}
		if(this.no == no){
    
    
			return this;
		}
		if(this.right != null){
    
    
			resNode = this.right.infixOrderSearch(no);
		}
		return resNode;
	}
	//后序遍历查找
	public HeroNode postOrderSearch(int no){
    
    
		HeroNode resNode = null;
		if(this.left != null){
    
    
			resNode = this.left.postOrderSearch(no);
		}
		if(resNode != null){
    
    
			return resNode;
		}
		if(this.right != null){
    
    
			resNode = this.right.postOrderSearch(no);
		}
		if(resNode != null){
    
    
			return resNode;
		}
		if(this.no == no)
			return this;
		return resNode;
	}

树中的遍历查找方法

//前序遍历查找 
	public HeroNode preOrderSearch(int no){
    
    
		if(root != null){
    
    
			return root.preOrderSearch(no);
		}else{
    
    
			return null;
		}
	}
	//中序遍历查找 
	public HeroNode infixOrderSearch(int no){
    
    
		if(root != null){
    
    
			return root.infixOrderSearch(no);
		}else{
    
    
			return null;
		}
	}
	//后续序遍历查找 
	public HeroNode postOrderSearch(int no){
    
    
		if(root != null){
    
    
			return root.postOrderSearch(no);
		}else{
    
    
			return null;
		}
	}

测试

		//测试查找
		System.out.println("-----------------------------");
		System.out.println("测试前序遍历查找4号节点");
		System.out.println(binnaryTreeDemo.preOrderSearch(4));
		System.out.println("-----------------------------");
		System.out.println("测试中序遍历查找4号节点");
		System.out.println(binnaryTreeDemo.infixOrderSearch(4));
		System.out.println("-----------------------------");
		System.out.println("测试后序遍历查找4号节点");
		System.out.println(binnaryTreeDemo.postOrderSearch(4));
-----------------------------
测试前序遍历查找4号节点
HeroNode [no=4, name=老肥]
-----------------------------
测试中序遍历查找4号节点
HeroNode [no=4, name=老肥]
-----------------------------
测试后序遍历查找4号节点
HeroNode [no=4, name=老肥]

删除节点

我们需要分情况

1.删除叶子结点的话,我们直接删除就OK了

2.如果删除的节点是非叶子节点,则要删除这个子树

那我们还用刚才的那个树

我现在添加一个节点,让我们的树变成这个样子

在这里插入图片描述

我们删除油哥这个节点和小黄这个节点

我们按照不同的情况进行不同的操作

1.删除油哥,他是不是叶子结点呢?是的话就单独删除这一个节点

因为我们的二叉树是单向的,所以我们是判断当前结点的子结点是否需要删除结点,而不能去判断当前这个结点是不是需要删除结点

如果当前节点的左子节点不为空,并且左子节点就是需要删除的节点,也就是说要删除油哥,我们要找到小黄判断小黄的左子节点是不是需要删除的节点是的话就将this.left = null;没有找到就去当前节点的右子节点继续判断

都不是就递归左子树,再去递归右子树

如果树是空树root为空,或者只有一个root节点,则等价将二叉树置空

首选是节点中的代码

	//递归删除节点
	//1.删除叶子结点的话,我们直接删除就OK了
	//2.如果删除的节点是非叶子节点,则要删除这个子树
	public void deleteHeroNode(int no){
    
    
		//思路如果当前节点的左子节点不为空,
		//并且左子节点就是需要删除的节点,也就是说要删除油哥,
		//我们要找到小黄,判断小黄的左子节点是不是需要删除的节点,
		//是的话就将this.left = null;没有找到就去当前节点的右子节点继续判断
		//都不是就递归左子树,再去递归右子树
		if(this.left != null && this.left.no == no){
    
    
			this.left = null;
			return;
		}
		if(this.right != null && this.right.no == no){
    
    
			this.right = null;
			return;
		}
		//向左子树递归
		if(this.left != null){
    
    
			this.left.deleteHeroNode(no);
		}
		//向右子树递归删除
		if(this.right != null){
    
    
			this.right.deleteHeroNode(no);
		}
	}

然后是我们树中的操作

/**
 * 删除节点操作
 * @param no   需要删除的节点
 */
public void deleteHeroNode(int no){
    
    
	if(root == null){
    
    
		System.out.println("该二叉树为空树,不能删除");
	}else{
    
    
		//如果root只有一个节点,这里立即判断root是不是要删除的节点
		//否则往下一找就没机会回来了
		if(root.getNo() == no){
    
    
			root = null;
		}else{
    
    
			//递归删除
			root.deleteHeroNode(no);
		}
	}
}

测试结果

	BinnaryTreeDemo binnaryTreeDemo = new BinnaryTreeDemo();
	//创建节点
	HeroNode root = new HeroNode(1, "小王");
	HeroNode node2 = new HeroNode(2, "小胡");
	HeroNode node3 = new HeroNode(3, "小黄");
	HeroNode node4 = new HeroNode(4, "老肥");
	HeroNode node5 = new HeroNode(5, "油哥");
	//手动创建二叉树,后面用递归方式创建二叉树
	root.setLeft(node2);
	root.setRight(node3);
	node3.setRight(node4);
	node3.setLeft(node5);
	binnaryTreeDemo.setRoot(root);
	System.out.println("删除前的树,前序遍历为");
	binnaryTreeDemo.preOrder();
	System.out.println("开始删除油哥");
	binnaryTreeDemo.deleteHeroNode(5);
	System.out.println("删除后的树,前序遍历为");
	binnaryTreeDemo.preOrder();
删除前的树,前序遍历为
HeroNode [no=1, name=小王]
HeroNode [no=2, name=小胡]
HeroNode [no=3, name=小黄]
HeroNode [no=5, name=油哥]
HeroNode [no=4, name=老肥]
开始删除油哥
删除后的树,前序遍历为
HeroNode [no=1, name=小王]
HeroNode [no=2, name=小胡]
HeroNode [no=3, name=小黄]
HeroNode [no=4, name=老肥]

显示正确,那要是我们现在删除的是小黄呢?小黄下面还有一个右子节点,能否一起删除呢?

删除小黄后,树只剩下了小王和小胡,我们试试

	System.out.println("开始删除小黄");
	binnaryTreeDemo.deleteHeroNode(3);
	System.out.println("删除后的树,前序遍历为");
	binnaryTreeDemo.preOrder();
开始删除小黄
删除后的树,前序遍历为
HeroNode [no=1, name=小王]
HeroNode [no=2, name=小胡]
正确

那么这个到底是怎么走的呢?删除叶子结点很容易理解,但时删除非叶子节点是怎么删除的呢

我们来分析一波

第一步:判断我们的root节点是不是空,我们的root节点是小王不为空,继续往下走

第二步:直接判断root节点是不是要删除的节点,小王的编号是1不是3,所以继续往下

第三步:进入递归删除—>小王的左子节点为空么?是小胡不为空,那是不是就是我们要删除的节点呢?小胡是2显然不是,那么继续往下走

第四步:小王的右子树为空么?是小黄不为空,那小黄是要删除的节点么,是的,那么进入删除,直接把小黄置空

第五步:递归进入左子树,假如我们删除的是油哥,那么上述的四步都没有找到,第五步,小王的左子树为空么?是小胡不为空,递归,那此时的this就指向了小胡,发现没有子树了,出来

第六步:递归进入右子树,发现右子树是小黄,this变成了小黄,然后以小黄为基准再次开始第一步判断,直到找到删除的节点

那么二叉树的常见操作都写完了,我把最终代码贴一遍

package;
//二叉树的前序、中序、后序遍历
//2021年1月25日22:57:42
//@author     王
public class BinnaryTree {
    
    

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		//创建一颗二叉树
		BinnaryTreeDemo binnaryTreeDemo = new BinnaryTreeDemo();
		//创建节点
		HeroNode root = new HeroNode(1, "小王");
		HeroNode node2 = new HeroNode(2, "小胡");
		HeroNode node3 = new HeroNode(3, "小黄");
		HeroNode node4 = new HeroNode(4, "老肥");
		HeroNode node5 = new HeroNode(5, "油哥");
		//手动创建二叉树,后面用递归方式创建二叉树
		root.setLeft(node2);
		root.setRight(node3);
		node3.setRight(node4);
		node3.setLeft(node5);
		binnaryTreeDemo.setRoot(root);
		//测试
//		System.out.println("前序遍历");
//		binnaryTreeDemo.preOrder();
//		System.out.println("中序遍历");
//		binnaryTreeDemo.infixOrder();
//		System.out.println("后序遍历");
//		binnaryTreeDemo.postOrder();
//		
//		//测试查找
//		System.out.println("-----------------------------");
//		System.out.println("测试前序遍历查找4号节点");
//		System.out.println(binnaryTreeDemo.preOrderSearch(4));
//		System.out.println("-----------------------------");
//		System.out.println("测试中序遍历查找4号节点");
//		System.out.println(binnaryTreeDemo.infixOrderSearch(4));
//		System.out.println("-----------------------------");
//		System.out.println("测试后序遍历查找4号节点");
//		System.out.println(binnaryTreeDemo.postOrderSearch(4));
		System.out.println("删除前的树,前序遍历为");
		binnaryTreeDemo.preOrder();
		System.out.println("开始删除油哥");
		binnaryTreeDemo.deleteHeroNode(5);
		System.out.println("删除后的树,前序遍历为");
		binnaryTreeDemo.preOrder();
		System.out.println("开始删除小黄");
		binnaryTreeDemo.deleteHeroNode(3);
		System.out.println("删除后的树,前序遍历为");
		binnaryTreeDemo.preOrder();
	}

}
//定义一个BinnaryTree二叉树
class BinnaryTreeDemo{
    
    
	private HeroNode root;


	public void setRoot(HeroNode root) {
    
    
		this.root = root;
	}
	//前序遍历
	public void preOrder(){
    
    
		if(this.root != null){
    
    
			this.root.preOrder();
		}else{
    
    
			System.out.println("二叉树为空,无法遍历");
		}
	}
	//中序遍历
	public void infixOrder(){
    
    
		if(this.root != null){
    
    
			this.root.infixOrder();
		}else{
    
    
			System.out.println("二叉树为空,无法遍历");
		}
	}
	//后序遍历
	public void postOrder(){
    
    
		if(this.root != null){
    
    
			this.root.postOrder();
		}else{
    
    
			System.out.println("二叉树为空,无法遍历");
		}
	}
	//前序遍历查找 
	public HeroNode preOrderSearch(int no){
    
    
		if(root != null){
    
    
			return root.preOrderSearch(no);
		}else{
    
    
			return null;
		}
	}
	//中序遍历查找 
	public HeroNode infixOrderSearch(int no){
    
    
		if(root != null){
    
    
			return root.infixOrderSearch(no);
		}else{
    
    
			return null;
		}
	}
	//后续序遍历查找 
	public HeroNode postOrderSearch(int no){
    
    
		if(root != null){
    
    
			return root.postOrderSearch(no);
		}else{
    
    
			return null;
		}
	}
	/**
	 * 删除节点操作
	 * @param no   需要删除的节点
	 */
	public void deleteHeroNode(int no){
    
    
		if(root == null){
    
    
			System.out.println("该二叉树为空树,不能删除");
		}else{
    
    
			//如果root只有一个节点,这里立即判断root是不是要删除的节点
			//否则往下一找就没机会回来了
			if(root.getNo() == no){
    
    
				root = null;
			}else{
    
    
				//递归删除
				root.deleteHeroNode(no);
			}
		}
	}
	
}


//先创建HeroNode节点
class HeroNode{
    
    
	private int no;
	private String name;
	private HeroNode left;
	private HeroNode right;
	public HeroNode(int no, String name) {
    
    
		super();
		this.no = no;
		this.name = name;
	}
	public int getNo() {
    
    
		return no;
	}
	public void setNo(int no) {
    
    
		this.no = no;
	}
	public String getName() {
    
    
		return name;
	}
	public void setName(String name) {
    
    
		this.name = name;
	}
	public HeroNode getLeft() {
    
    
		return left;
	}
	public void setLeft(HeroNode left) {
    
    
		this.left = left;
	}
	public HeroNode getRight() {
    
    
		return right;
	}
	public void setRight(HeroNode right) {
    
    
		this.right = right;
	}
	@Override
	public String toString() {
    
    
		return "HeroNode [no=" + no + ", name=" + name + "]";
	}
	//编写前序遍历方法
	public void preOrder(){
    
    
		System.out.println(this);//先输出父节点
		//递归向左子树前序遍历
		if(this.left != null){
    
    
			this.left.preOrder();
		}
		//递归向右子树前序遍历
		if(this.right != null){
    
    
			this.right.preOrder();
		}
	}
	//中序遍历
	public void infixOrder(){
    
    
		//递归向左子树中序遍历
		if(this.left != null){
    
    
			this.left.infixOrder();
		}
		System.out.println(this);//输出父节点
		//向右递归中序遍历子树
		if(this.right != null){
    
    
			this.right.infixOrder();
		}
	}
	
	
	//后序遍历
	public void postOrder(){
    
    
		if(this.left != null){
    
    
			this.left.postOrder();
		}
		if(this.right != null){
    
    
			this.right.postOrder();
		}
		System.out.println(this);//输出父节点
	}
	/**
	 * 前序遍历查找
	 * @param no  待查找编号
	 * @return
	 */
	public HeroNode preOrderSearch(int no){
    
    
		//判断当前节点是不是
		if(this.no == no){
    
    
			return this;
		}
		//判断左子节点是否为空
		HeroNode resNode = null;
		if(this.left != null){
    
    
			resNode = this.left.preOrderSearch(no);
		}
		if(resNode != null){
    
    
			//说明左子树上找到了
			return resNode;
		}
		if(this.right != null){
    
    
			resNode = this.right.preOrderSearch(no);
		}
		return resNode;
	}
	//中序遍历查找
	public HeroNode infixOrderSearch(int no){
    
    
		HeroNode resNode = null;
		//先判断当前节点的左子节点
		if(this.left != null){
    
    
			resNode = this.left.infixOrderSearch(no);
		}
		if(resNode != null){
    
    
			return resNode;
		}
		if(this.no == no){
    
    
			return this;
		}
		if(this.right != null){
    
    
			resNode = this.right.infixOrderSearch(no);
		}
		return resNode;
	}
	//后序遍历查找
	public HeroNode postOrderSearch(int no){
    
    
		HeroNode resNode = null;
		if(this.left != null){
    
    
			resNode = this.left.postOrderSearch(no);
		}
		if(resNode != null){
    
    
			return resNode;
		}
		if(this.right != null){
    
    
			resNode = this.right.postOrderSearch(no);
		}
		if(resNode != null){
    
    
			return resNode;
		}
		if(this.no == no)
			return this;
		return resNode;
	}
	//递归删除节点
	//1.删除叶子结点的话,我们直接删除就OK了
	//2.如果删除的节点是非叶子节点,则要删除这个子树
	public void deleteHeroNode(int no){
    
    
		//思路如果当前节点的左子节点不为空,
		//并且左子节点就是需要删除的节点,也就是说要删除油哥,
		//我们要找到小黄,判断小黄的左子节点是不是需要删除的节点,
		//是的话就将this.left = null;没有找到就去当前节点的右子节点继续判断
		//都不是就递归左子树,再去递归右子树
		if(this.left != null && this.left.no == no){
    
    
			this.left = null;
			return;
		}
		if(this.right != null && this.right.no == no){
    
    
			this.right = null;
			return;
		}
		//向左子树递归
		if(this.left != null){
    
    
			this.left.deleteHeroNode(no);
		}
		//向右子树递归删除
		if(this.right != null){
    
    
			this.right.deleteHeroNode(no);
		}
	}
	
}

猜你喜欢

转载自blog.csdn.net/qq_22155255/article/details/113179036