DS二叉排序树之删除

DS二叉排序树之删除

时间限制: 1 Sec  内存限制: 128 MB


题目描述

给出一个数据序列,建立二叉排序树,并实现删除功能

对二叉排序树进行中序遍历,可以得到有序的数据序列

输入

第一行输入t,表示有t个数据序列

第二行输入n,表示首个序列包含n个数据

第三行输入n个数据,都是自然数且互不相同,数据之间用空格隔开

第四行输入m,表示要删除m个数据

从第五行起,输入m行,每行一个要删除的数据,都是自然数

以此类推输入下一个示例

输出

第一行输出有序的数据序列,对二叉排序树进行中序遍历可以得到

从第二行起,输出删除第m个数据后的有序序列,输出m行

以此类推输出下一个示例的结果

样例输入

1

6

22 33 55 66 11 44

3

66

22

77

样例输出

11 22 33 44 55 66

11 22 33 44 55

11 33 44 55

11 33 44 55

提示

当删除数据不在序列中,那么删除操作等于不执行,所以输出序列不变化

Solution :

import java.util.*;
public class Main{
	public static void main(String args[]){
		Scanner scanner = new Scanner(System.in);
		int t = scanner.nextInt();
		for (int i = 0; i <t ; i++) {
			BST bst = new BST();//创建二叉排序树
			int n = scanner.nextInt();
			for (int j = 0; j <n ; j++) {//将结点加入到二叉排序树中
				bst.add(new Node(scanner.nextInt()));
			}
			bst.midShow();//中序遍历进行输出
			System.out.println();

			int m = scanner.nextInt();
			for (int j = 0; j <m ; j++) {
				bst.delete(scanner.nextInt());// 删除结点
				bst.midShow();
				System.out.println();
			}
		}
	}
}

/**
 * 二叉树结点
 */
class Node{
	int value;
	Node left;
	Node right;
	int count = 1;
	public Node(int value){
		this.value = value;
	}

	/**
	 * 往二叉树中插入结点
	 * @param node
	 */
	public void add(Node node){
		if (node == null){
			return;
		}
		/*
		如果插入的结点的值小于当前结点的值,则该插入的结点应该向左走
		 */
		if (node.value<this.value){
			// 该结点的左孩子为空,则正好放入插入结点
			if (this.left == null){
				this.left = node;
			}else {
				//该结点的左孩子非空,则插入结点需要加入到左孩子树中
				this.left.add(node);
			}
		}else {
			//右边同理,右孩子为空,直接放入插入结点
			if (this.right== null){
				this.right = node;
			}else {
				// 右孩子非空,则插入结点需要加入到右孩子树中
				this.right.add(node);
			}
		}
	}

	/**
	 * 中序遍历,将二叉树中的结点,按照从小到大的顺序输出
	 * @param node
	 */
	public void midShow(Node node){
		if (node == null){
			return;
		}
		midShow(node.left);//遍历左子树
		System.out.print(node.value+" ");//输出当前结点值
		midShow(node.right);//遍历右子树
	}

	/**
	 * 传入值,搜索对应的结点,返回结点
	 * @param value
	 * @return 如果找不到,返回空
	 */
	public Node search(int value){
		// 找到了,直接返回当前结点
		if (this.value == value){
			return this;
		}else if (value<this.value){ // 要搜索的值小于当前结点的值,向左子树中进行查找
			if (left == null){// 左子树为空,说明找不到
				return null;
			}
			left.count = this.count+1;
			return left.search(value);// 非空,递归查找
		}else {// 同理,要搜索的值大于当前结点的值,向右子树中进行查找
			if (right == null){
				return null;
			}
			right.count = this.count+1;
			return right.search(value);
		}
	}

	/**
	 * 查找对应结点的父亲结点
	 * @param value
	 * @return 找不到则返回空
	 */
	public Node searchParent(int value){
		// 如果当前结点的左孩子或者右孩子等于查找值,说明当前结点即为该查找值的父亲结点
		if ((this.left!=null && this.left.value ==value)||(this.right!=null && this.right.value ==value)){
			return this;
		}else {
			// 如果当前值大于查找值,同时当前值的左孩子非空
			if (this.value>value &&this.left!=null){
				return this.left.searchParent(value);//到左子树中查找
			// 如果当前值小于查找值,同时当前值的右孩子非空
			}else if (this.value<value && this.right!=null){
				return this.right.searchParent(value);//到右子树中查找
			}else {
				// 当前值既不等于查找值,也没有孩子结点,说明查找失败,返回空
				return null;
			}
		}
	}

}

class BST{
	Node root;

	/**
	 * 往二叉排序树中加入结点
	 * @param node
	 */
	public void add(Node node){
		if (root == null){
			root =node;
		}else {
			root.add(node);
		}
	}

	/**
	 * 中序遍历二叉排序树
	 */
	public void midShow(){
		if (root!=null){
			root.midShow(root);
		}
	}

	/**
	 * 在二叉排序树中查找
	 * @param value
	 * @return
	 */
	public Node search(int value){
		if (root == null){
			return null;
		}else {
			return root.search(value);
		}
	}

	/**
	 * 删除结点
	 * @param value
	 */
	public void delete(int value){
		if (root ==null){
			return;
		}else {
			//查找要删除的结点
			Node target = search(value);
			if (target ==null){
				return;
			}
			// 查找父亲结点
			Node parent = searchParent(value);
			// 如果目标结点没有孩子,可直接将该结点删除
			if (target.left ==null && target.right == null){
				// 判断目标结点是其父亲结点的左孩子还是右孩子
				if (parent.left.value ==value){
					parent.left =null;
				}else {
					parent.right = null;
				}
			// 如果目标结点既有左孩子,又有右孩子,需要在目标结点的右孩子中找到一个最小值,
			// 将目标结点删除后,替代目标结点的位置。
			}else if (target.left!=null && target.right!=null){
				// 删除右子树中的最小值,同时获得该值
				int min = deleteMin(target.right);
				// 将要删除的结点的值改为最小值
				target.value = min;
			// 如果目标结点只有一个孩子,只需让目标结点的该孩子顶替目标结点
			}else {
				// 如果目标结点有的是左孩子
				if (target.left!=null){
					// 判断目标结点是其父亲结点的左孩子还是右孩子
					if (parent.left.value ==value){
						parent.left =target.left;
					}else {
						parent.right = target.left;
					}
				}else {
					if (parent.left.value ==value){
						parent.left =target.right;
					}else {
						parent.right = target.right;
					}
				}
			}
		}
	}

	/**
	 * 在二叉排序树中查找该值的父亲结点,并返回
	 * @param value
	 * @return 查找失败则返回空
	 */
	public Node searchParent(int value){
		if (root ==null){
			return null;
		}else {
			return root.searchParent(value);
		}
	}

	/**
	 * 删除某个结点的右子树中值最小的结点,并返回该值
	 * @param node
	 * @return
	 */
	private int deleteMin(Node node){
		Node target = node;
		while (target.left!=null){//右子树中最小值必然是其最下层的左孩子
			target = target.left;
		}
		// 该最小值结点可能是叶子结点,也可能有右孩子,但delete函数已经考虑了这两种情况了,
		// 所以可以直接调用。(但不可能有左孩子,因为其是最小的)
		delete(target.value);
		return target.value;
	}

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜饼同学

帮助别人,就是帮助自己,共勉。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值