package com.atguigu.java1;
/**
* 二叉排序树的讲解
*二叉树的删除
* 7
* 3 10
* 1 5 9 12
* 2
* ①删除叶子节点(2,5,9,12)
* ②删除只有一棵子树的节点:(1)
* ③删除二棵子树的节点:(7,3,10)
*
* 第一种情况:删除叶子节点
* (1):需要先找到待删除的节点,targetNode
* (2):找到targetNode的父节点,parent(如果是root节点还需再判断)
* (3):确定targetNode是parent的左子节点,还是右子节点
* (4):根据前面的情况来对应的删除
* 左子节点,parent.left=null
* 右子节点,parent.right=null
*
* 第二种情况:删除只有一棵子树的节点,比如1
* (1):需要先找到待删除的节点,targetNode
* (2):找到targetNode的父节点,parent(如果是root节点还需再判断)
* (3):确定targetNode的子节点是左子节点还是右子节点
* (4);确定targetNode是parent的左子节点还是右子节点
* (5)如果targetNode有左子节点
* 5.1如果targetNode是parent的左子节点
* parent.left=targetNode.left;
* 5.2如果targetNode是parent的右子节点
* parent.right=targetNode.left;
*
* 如果targetNode有右子节点
* 6.1如果targetNode是parent的左子节点
* parent.left=targetNode.right;
* 6.2如果targetNode是parent的右子节点
* parget.right=targetNode.right;
*
* 第三种情况:删除两颗子树的节点:比如7,3,10,举例删除10
* 思路
* (1):需要先找到待删除的节点,targetNode
* (2):找到targetNode的父节点,parent(如果是root节点还需再判断)
* (3);从targetNode的右子树找到最小的节点
* (因为右子树最小的值刚好满足比左子树所有的值都大,且比其右子树其它的值都小)最后得构成二叉排序树。
* 注:找左子树最大的节点也行
* (4);用一个临时变量,将最小节点的值保存temp=12
* (5);删除该最小节点(其实就是12)
* (6);targetNode.value=temp;(用12代替10)
*
*
*
* @author WZ
* @create 2021-10-30 22:13
*/
public class BinarySortTreeDemo {
public static void main(String[] args) {
int[] arr=new int[]{7,3,10,12,5,1,9,2};
BinarSortTree binarSortTree = new BinarSortTree();
//循环的添加节点到二叉树
for (int i = 0; i < arr.length; i++) {
binarSortTree.add(new Node(arr[i]));
}
//中序遍历二叉排序树
System.out.println("中序遍历二叉排序树");
binarSortTree.infixOrder();//1 3 5 7 9 10 12
//测试删除叶子节点
// binarSortTree.delNode(2);
// binarSortTree.delNode(5);
// binarSortTree.delNode(9);
binarSortTree.delNode(10);
System.out.println("测试删除节点后");
binarSortTree.infixOrder();
}
}
//创建二叉排序树
class BinarSortTree{
private Node root;//根节点
//查找要删除的节点
public Node search(int value){
if (root==null){
return null;
}else {
return root.search(value);
}
}
//查找父节点
public Node searchParent(int value){
if (root==null){
return null;
}else {
return root.searchParent(value);
}
}
//编写一个方法,向右寻找并删除子树的最小节点(其实向左找最大的也行,不过还得编写一个方法)
/**1.返回的是以node为根节点的二叉排序树的最小节点的值
* 2.删除以node为根节点的二叉排序树的最小节点的
*
* @param node 这个表示传入的节点(当作二叉排序树的根节点)
* @return 返回的是以node为根节点的二叉排序树的最小节点的值
*/
public int delRightTreeMin(Node node){
Node target=node;
//循环的查找左节点,就会找到最小值(前提是传入的节点是待删除节点的右节点)
while (target.left!=null){
target=target.left;
}
//这时target就指向了最小节点
//删除最小节点
delNode(target.value);
return target.value;
}
//删除节点的方法
public void delNode(int value){
if (root==null){
return;
}else {
//1.需要先找到要删除的节点 targetNode
Node targetNode = search(value);
//如果没有找到要删除的节点
if (targetNode==null){
return;//直接结束即可
}
//如果我们发现当这个二叉排序树只有一个节点,而且这个节点就是要查找删除的节点,直接置空删除即可
if (root.left==null && root.right==null){
root=null;//
return;
}
//2.去找targetNode的父节点
Node parent = searchParent(value);
//情况一:如果删除的节点是叶子节点
if (targetNode.left==null && targetNode.right==null){
//判断targetNode是父节点的左子节点还是右子节点
if (parent.left!=null && parent.left.value==value){//是左子节点
//说明要删除的targetNode就是要删除的
parent.left=null;
}else if (parent.right!=null && parent.right.value==value){//是右子节点
parent.right=null;
}
}else if (targetNode.left!=null && targetNode.right!=null){//这个是情况三,情况二比较复杂最后写,
//删除的节点有两个子树
int minValue = delRightTreeMin(targetNode.right);
targetNode.value=minValue;//重置value值
}else {//情况二,删除只有一颗子树的节点,因为前两种情况都排除了
//如果要删除的节点有左子节点
if (targetNode.left!=null){
if (parent!=null) {
//如果targetNode是parent的左子节点
if (parent.left.value == value) {
parent.left = targetNode.left;
} else {
//说明targetNode是parent的右子节点
parent.right = targetNode.left;
}
}else {
root=targetNode.left;
}
}else {//表示要删除的节点有右节点
if (parent != null) {
//如果targetNode是parent的左子节点
if (parent.left.value == value) {
parent.left = targetNode.right;
} else {//如果targetNode是parent的右子节点
parent.right = targetNode.right;
}
}else {
root=targetNode.right;
}
}
}
}
}
//添加节点的方法
public void add(Node node){
if (root==null){
root=node;//如果node为空,则直接让root指向node
}else {
root.add(node);
}
}
//中序遍历
public void infixOrder(){
if (root!=null){
root.infixOrder();
}else {
System.out.println("当前这棵二叉树为空,不能遍历");
}
}
}
//创建Node节点
class Node{
int value;//节点的值
Node left;//左子节点
Node right;//右子节点
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
//查找要删除的节点
/**
*
* @param value 希望删除的节点的值
* @return 如果找到,返回该节点,否则返回null
*/
public Node search(int value){
if (value==this.value){
//找到,就是该节点
return this;
}else if (value<this.value){//如果查找的值小于当前节点,向左递归查找
//左递归有风险,如果左子节点为空
if (this.left==null){
return null;
}
//左子节点不为空,才可以左递归
return this.left.search(value);
}else {//如果要查找的值不小于当前接待你,那么右递归查找
if (this.right==null ){
return null;
}
return this.right.search(value);
}
}
//查找要删除节点的父节点
/**
*
* @param value 这个指的是要找的节点的值
* @return 返回的是要删除节点的父节点,如果没有,则返回null;
*/
public Node searchParent(int value){
//如果当前节点就是要删除节点的父节点
if ((this.left!=null && this.left.value==value) || (this.right!=null&& this.right.value==value)){
return this;//此时this就是当前节点的父节点
}else {
//如果查找的值小于当前节点的值,并且当前节点的左子节点不为空
if (value<this.value && this.left!=null){
return this.left.searchParent(value);//左递归
}else if (value>=this.value && this.right!=null){
return this.right.searchParent(value);//向右子树递归查找
}else {
return null;//没有找到父节点
}
}
}
//添加节点的方法,递归的形式进行添加节点,需要满足二叉排序树
public void add(Node node){
if (node==null){
System.out.println("数据为空,不能判断");
return;
}
//判断传入节点的值,和当前子树根节点的关系
if (node.value<this.value){//this表示当前节点
//如果当前节点左子节点为null,直接放到左子节点即可
if (this.left==null){
this.left=node;
}else {
//如果左子节点不为空,直接向左边递归即可
this.left.add(node);
}
}else {
//如果传入node.value大于当前节点的值,那就需要再进行判断
//先看右子节点是否为空。。。。。。。。。。。。。。。。。
if (this.right==null){
this.right=node;
}else {
//递归的向右子树添加
this.right.add(node);
}
}
}
//中序遍历
public void infixOrder(){
if (this.left!=null){
//左递归
this.left.infixOrder();
}
System.out.println(this);
if (this.right!=null){
//右递归
this.right.infixOrder();
}
}
}
08-11
2176
03-28
2362