二叉排序树(Binary Sort Tree),又称为二叉查找树,或者二叉搜索树。对于二叉排序树的任何一个非叶子节点,它的左子节点的值比当前节点的值小,右子节点的值比当前节点的值大。
所以,二叉排序树有以下性质:
步骤:
准备:
树的节点的 TreeNode 类class
二叉排序树 类class
添加节点:
二叉树的遍历: (中序遍历)
if(this.left != null) {
this.left.midOrder();
}
System.out.println(this);
if(this.right != null) {
this.right.midOrder();
}
准备:
我们要找到要删除的那个节点以及要删除的那个节点的父节点
判断要删除的节点是父节点的左子节点还是右子节点,然后直接把parent的左子节点或者右子节点置空。
先判断父节点是否为空,如果为空,则直接可以把根节点指向目标节点的下一个节点
如果父节点不为空,判断目标节点是父节点的左子节点还是右子节点。然后再进行删除操作
if (targetNode.left != null) {
if (parent != null) {
// 如果 targetNode 是 parent 的左子节点
if (parent.left.val == val) {
parent.left = targetNode.left; // 把目标节点的left指向父节点的left,达到删除的目的
} else {
// targetNode 是 parent 的右子节点
parent.right = targetNode.left; // 把目标节点的left指向父节点的right
}
} else {
root = targetNode.left;
}
} else { //如果要删除的节点有右子节点
if (parent != null) {
if (parent.left.val == val) {
// 如果 targetNode 是 parent 的左子节点
parent.left = targetNode.right;
} else {
// 如果 targetNode 是 parent 的右子节点
parent.right = targetNode.right;
}
} else {
root = targetNode.right;
}
}
找到删除节点子树中的最小值,删除这个最小节点,然后把最小节点的值赋值给目标节点。
package BinarySortTree;
import java.math.BigInteger;
public class BinarySortTreeDemo {
public static void main(String[] args) {
int[] arr = {7, 3, 10, 12, 5, 1, 9, 2};
BinarySortTree binarySortTree = new BinarySortTree();
// 循环的添加节点到二叉排序树
for (int i = 0; i < arr.length; i++) {
binarySortTree.add(new TreeNode(arr[i]));
}
// 中序遍历二叉排序树
System.out.println("中序遍历:");
binarySortTree.midOreder(); // 1,3,5,7,9,10,12
// 测试删除叶子节点
// binarySortTree.delNode( 2 );
/*binarySortTree.delNode( 5 );
binarySortTree.delNode( 9 );
binarySortTree.delNode( 12 );*/
//binarySortTree.delNode( 1 );
binarySortTree.delNode( 10 );
System.out.println("删除节点吼");
binarySortTree.midOreder();
}
}
/**
* 创建二叉排序树
*/
class BinarySortTree {
private TreeNode root;
// 添加节点的方法
public void add(TreeNode node) {
if(root == null) {
// 如果root为空,直接所加节点就是根节点
root = node;
} else {
root.add(node);
}
}
// 中序遍历
public void midOreder() {
if(root != null) {
root.midOrder();
} else {
System.out.println("二叉排序树为空,不能遍历");
}
}
// 查找要删除的节点
public TreeNode search(int val) {
if(root == null) {
return null;
} else {
return root.search( val );
}
}
// 查找要删除节点的父节点
public TreeNode searchParent(int val) {
if(root == null) {
return null;
} else {
return root.searchParent( val );
}
}
/**
*
* @param node 传入的节点(当做一棵二叉排序树的根节点)
* @return 以node为根节点的二叉排序树的最小节点的值
*/
public int delRigthTreeMin(TreeNode node) {
TreeNode target = node;
// 循环的查找左节点,找到最小的那个值
while(target.left != null) {
target = target.left;
}
// 这是target指向最小的节点
// 删除最小节点
delNode( target.val );
return target.val;
}
// 删除节点
public void delNode(int val) {
if(root == null) {
return;
} else {
// 1. 先找到要删除的节点 targetNode
TreeNode targetNode = search( val );
// 如果没有要删除的节点
if(targetNode == null) {
return;
}
// 如果二叉排序树只有一个节点
if(root.left == null && root.right == null ){
root = null;
return;
}
// 2.找到 targetNode 的父节点
TreeNode parent = searchParent( val );
// 如果要删除的节点是叶子节点
if(targetNode.left == null && targetNode.right == null) {
// 说明targetNode为叶子节点
// 判断targetNode 是父节点的左子节点还是右子节点
if(parent.left != null && parent.left.val == val) {
// 左子节点
parent.left = null;
} else if(parent.right != null && parent.right.val == val) {
// 右子节点
parent.right = null;
}
} else if(targetNode.left != null && targetNode.right != null) {
int minVal = delRigthTreeMin( targetNode.right );
targetNode.val = minVal;
} else { //删除只有一棵子树的节点
// 如果要删除的节点有左子节点
if (targetNode.left != null) {
if (parent != null) {
// 如果 targetNode 是 parent 的左子节点
if (parent.left.val == val) {
parent.left = targetNode.left;
} else {
// targetNode 是 parent 的右子节点
parent.right = targetNode.left;
}
} else {
root = targetNode.left;
}
} else { //如果要删除的节点有右子节点
if (parent != null) {
if (parent.left.val == val) {
// 如果 targetNode 是 parent 的左子节点
parent.left = targetNode.right;
} else {
// 如果 targetNode 是 parent 的右子节点
parent.right = targetNode.right;
}
} else {
root = targetNode.right;
}
}
}
}
}
}
/**
* 创建Node节点
*/
class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
}
@Override
public String toString () {
return "TreeNode [value = " + val + "]";
}
/**
* 查找要删除的节点
* @param val 希望删除节点的值
* @return 如果找到返回该节点,没找到返回null
*/
public TreeNode search(int val) {
if(val == this.val) {
// 找到该节点
return this;
} else if (val < this.val) {
// 如果查找的值小于当前节点的值, 则向左子树递归查找
// 如果左子节点为空,不能再找了
if(this.left == null) {
return null;
}
return this.left.search(val);
} else {
// 如果查找的值大于等于当前节点的值, 则向右子树递归查找
if(this.right == null) {
return null;
}
return this.right.search( val );
}
}
/**
* 查找要删除节点的父节点
* @param val 要查找的节点的值
* @return 返回的是要删除节点的父节点,如果没有返回null。
*/
public TreeNode searchParent(int val) {
// 如果当前节点就是要删除节点的父节点,直接返回
if((this.left != null && this.left.val == val) || (this.right != null && this.right.val == val)) {
return this;
} else {
if(val < this.val && this.left != null) {
// 如果要查找的节点的值小于当前节点的值,并且当前节点的左子节点不为空
// 向左子树递归查找
return this.left.searchParent( val );
} else if(val >= this.val && this.left != null) {
// 如果要查找的节点的值大于等于当前节点的值,并且当前节点的右子节点不为空
return this.right.searchParent( val );
} else {
// 没有找到父节点
return null;
}
}
}
// 添加节点的方法 —— 递归完成
public void add (TreeNode node) {
if(node == null ) {
return;
}
// 判断要添加节点的值于当前节点值的关系
// 如果当前节点的值大于要添加节点的值,判断当前节点的左子树的情况
if(node.val < this.val) {
// 如果当前节点的左子节点为null
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);
}
}
}
// 中序遍历
public void midOrder() {
if(this.left != null) {
this.left.midOrder();
}
System.out.println(this);
if(this.right != null) {
this.right.midOrder();
}
}
}
本文对二叉排序树作了基本的介绍。使用代码完成了二叉排序树的创建,遍历,删除等功能。