1.二叉排序树介绍
二叉排序树:BST(Binary Sort Tree),对于二叉排序树的任何一个非叶子节点,要求左子节点的值比当前节点的值小,如右子节点的值当当前节点值大。如果有相同的值,可以将改节点放在左子节点或右子节点。
比如针对数据{7,3,10,12,5,1,9},对应的二叉排序树为:
2.二叉排序树的创建
2.1思路分析:
(1)先判断二叉排序树的根节点是否为空,如果为空则把当前节点复制给跟节点
(2)如果不为空,则进行添加操作
(3)进行添加操作时先判断当前节点的值是否大于添加节点,如果大于再判断当前节点左节点是否为空,如果为空则进行添加,如果不为空则进行递归操作
(4)如果当前节点小于添加节点,则判断当前节点的右子节点是否为空,如果为空则进行添加操作,如果不为空则进行递归操作
2.2代码演示
//二叉排序树
class BinarySortTree{
//二叉排序树的根节点
private Node root;
public Node getRoot() {
return root;
}
public void setRoot(Node root) {
this.root = root;
}
//创建二叉排序树
public void add(Node node) {
if (root == null) {
root = node;
return;
}
root.addNode(node);
}
//中序遍历
public void infixOrder() {
if (root != null) {
root.infixOrder();
return;
}
throw new NullPointerException("根节点为空");
}
}
//二叉排序树的节点
class Node{
private int value;
private Node left;
private Node right;
public Node(int value) {
this.value = value;
}
public Node() {}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
/**
* 向二叉排序树中添加节点
* @param node 要添加的节点
*/
public void addNode(Node node) {
if (node == null) {
throw new NullPointerException("节点为空");
}
//判断当前节点的值是否大于添加节点
if (this.value > node.value) {
//判断当前节点的左子节点是否为空
if (this.left == null) {
this.left = node;
return;
}
//递归
this.left.addNode(node);
return;
}
//判断当前节点的右子节点是否为空
if (this.right == null) {
this.right = node;
return;
}
//递归
this.right.addNode(node);
}
//中序遍历
public void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.println(this);
if (this.right != null) {
this.right.infixOrder();
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
}
3.二叉排序树的删除
3.1思路分析
二叉排序树的删除情况比较复杂,有下面6种情况要考虑
(1)删除叶子节点(比如2,5,9,12)
(2)删除只有一个子节点的节点(比如1)
(3)删除有两颗子节点的节点(比如7,3,10)
(4)删除叶子节点为根节点时
(5)删除只有一个子节点的节点为根节点
(6)删除有两颗子节点的节点为根节点
第一种情况:
(1)先要找到要删除的节点targetNode
(2)再找到要删除节点的父节点parent
(3)判断targetNode时parent的左子节点还是右子节点
(4)左子节点:parent.left = null,右子节点 parent.right = null
第二种情况:
(1)先要找到要删除的节点targetNode
(2)再找到要删除节点的父节点parent
(3)判断targetNode时parent的左子节点还是右子节点
(4)判断targetNode的子节点是左子节点还是右子节点
(5)如果targetNode是parent的左子节点
(5.1)如果targetNode有左子节点parent.left = target.left
(5.2)如果targetNode有右子节点parent.left= target.right
(6)如果targetNode是parent的右子节点
(6.1)如果targetNode有左子节点parent.right= target.left
(6.2)如果targetNode有右子节点parent.right= target.right
第三种情况:
(1)先要找到要删除的节点targetNode
(2)再找到要删除节点的父节点parent
(3)从targetNode的左子树上找到最大的节点并复制给max
(4)删除最大节点
(5)max.left = targetNode.left
(6)max.right = targetNode.right
(7)如果如果targetNode是parent的左子节点,parent.left =max
(8)如果如果targetNode是parent的右子节点,parent.right=max
第四种情况:
直接把根节点置空,root = null
第五种情况:
(1)如果根节点左子节点,root = roo.left
(2)如果根节点右子节点,root = roo.right
第六种情况:
(1)从root的左子树上找到最大的节点并复制给max
(2)删除最大节点
(3)max.left = root.left
(4)max.right = root.right
(5) root = max
3.2代码实现
//查找要删除的节点
public Node search(int value) {
if (this.root != null){
return this.root.search(value);
}
throw new NullPointerException("根节点为空");
}
//查找要删除节点的父节点
public Node searchParent(int value) {
if (this.root != null){
return this.root.searchParent(value);
}
throw new NullPointerException("根节点为空");
}
//删除节点
public Node deleteNode(int value) {
if (this.root != null){
//需要先去找到要删除的节点
Node targetNode = this.root.search(value);
//找到要删除节点的父节点
Node parent = this.root.searchParent(value);
//表示没有找到要删除的节点
if (targetNode == null) {
return null;
}
//说明根节点就是要我们要删除的节点
if (this.root.getLeft() == null && this.root.getRight() == null) {
Node temp = this.root;
this.root = null;
return temp;
}
//说明根节点就是要我们要删除的节点,而根节点又有一个左子节点或右子节点
if (this.root.getValue() == value &&
(this.root.getLeft() == null || this.root.getRight() == null)) {
//说明左节点不为空
if (this.root.getLeft() != null) {
Node temp = this.root;
this.root = this.root.getLeft();
return temp;
}
//说明右节点不为空
Node temp = this.root;
this.root = this.root.getRight();
return temp;
}
//说明根节点就是要我们要删除的节点,而根节点又有一个左子节点和一个右子节点
if (this.root.getValue() == value &&
(this.root.getLeft() != null && this.root.getRight() != null)) {
//需要从要删除节点的左子树上找到最大的节点,然后替换要删除的节点
Node max = searchMax(this.root.getLeft());
deleteNode(max.getValue());
max.setLeft(this.root.getLeft());
max.setRight(this.root.getRight());
Node temp = this.root;
this.root = max;
return temp;
}
//说明要删除节点没有左右子节点,改要删除的节点是叶子节点
if (targetNode.getLeft() == null && targetNode.getRight() == null) {
//说明要删除是父节点的左节点
if (parent.getValue() > targetNode.getValue()) {
parent.setLeft(null);
return targetNode;
}
//说明要删除是父节点的右节点
parent.setRight(null);
return targetNode;
}
//说明要删除节点有一个左子节点或右子节点
if (targetNode.getLeft() == null || targetNode.getRight() == null) {
//说明要删除是父节点的左节点
if (parent.getValue() > targetNode.getValue()) {
//说明要删除节点有一个左子节点
if (targetNode.getLeft() != null) {
parent.setLeft(targetNode.getLeft());
return targetNode;
}
//说明要删除节点有一个右子节点
parent.setLeft(targetNode.getRight());
return targetNode;
}
//说明要删除节点有一个左子节点
if (targetNode.getLeft() != null) {
parent.setRight(targetNode.getLeft());
return targetNode;
}
//说明要删除节点有一个右子节点
parent.setRight(targetNode.getRight());
return targetNode;
}
//说明要删除的节点有一个左子节点和一个右子节点
if (targetNode.getLeft() != null && targetNode.getRight() != null) {
//需要从要删除节点的左子树上找到最大的节点,然后替换要删除的节点
Node max = searchMax(targetNode.getLeft());
deleteNode(max.getValue());
max.setLeft(targetNode.getLeft());
max.setRight(targetNode.getRight());
//说明要删除是父节点的左节点
if (parent.getValue() > targetNode.getValue()) {
parent.setLeft(max);
return targetNode;
}
//说明要删除是父节点的右节点
parent.setRight(max);
return targetNode;
}
}
throw new NullPointerException("根节点为空");
}
//寻找值最大的节点
public Node searchMax(Node node) {
if (node != null) {
return node.searchMax();
}
throw new NullPointerException("节点为空");
}
/**
* 查找要删除的节点
* @param value 希望删除的节点的值
* @return 删除的节点
*/
public Node search(int value) {
//找到了要删除的节点
if (this.value == value) {
return this;
}
//如果当前的节点的值大于要删除的节点的值,则向左递归查找
if (this.value > value && this.left != null) {
return this.left.search(value);
}
//如果当前的节点的值小于要删除的节点的值,则向右递归查找
if (this.value <= value && this.right != null) {
return this.right.search(value);
}
//没有查找到要删除的节点
return null;
}
/**
* 查找要删除节点的父节点
* @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;
}
//向左递归查找
if (this.left != null && this.value > value) {
return this.left.searchParent(value);
}
//向右递归查找
if (this.right != null && this.value <= value) {
return this.right.searchParent(value);
}
//没有查找到父节点
return null;
}
public Node searchMax() {
if (this.getRight() != null) {
return this.getRight().searchMax();
}
return this;
}