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;
}
}