一.简介
任何一个节点的左子树上的点,都必须小于当前节点,任何一个节点的右子树上的点,都必须大于当前节点,等于当前节点的数据可以放在左节点或右节点。
二.实现
对于节点的删除有如下判断:
1.待删除节点是叶子节点则找到父节点直接删除
2.待删除结点只有左节点,则父节点直接指向待删除结点的左节点
3.待删除结点只有右节点,则父节点直接指向待删除结点的右节点
4.待删除结点有左右节点,则寻找待删除结点左子树最大值或待删除结点右子树最小值替换待删除结点值,并把寻找到的节点删除。
package com.vincent;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
BinSortTree<Integer> tree = new BinSortTree<>();
for(int i=0;i<32;i++){
tree.add((int)(Math.random() * 100));
}
List<Integer> list = tree.infixList();
System.out.println(list);
System.out.println("删除:" + list.get(0));
tree.delete(list.get(0));
list = tree.infixList();
System.out.println(list);
System.out.println("删除:" + list.get(list.size()-1));
tree.delete(list.get(list.size()-1));
list = tree.infixList();
System.out.println(list);
System.out.println("删除:" + list.get(list.size()/2));
tree.delete(list.get(list.size()/2));
list = tree.infixList();
System.out.println(list);
}
}
//二叉排序树(BST)
class BinSortTree<T extends Comparable<T>>{
static class Node<T extends Comparable<T>> {
private T item;
private Node<T> left;
private Node<T> right;
public Node(T item) {
this.item = item;
}
public void add(Node<T> node){
if(node.item.compareTo(this.item) <= 0){
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);
}
}
}
/**
* 从当前节点开始寻找等于item的节点
* @param item 带查找结点的值
* @return
*/
public Node<T> searchParentNode(T item){
if(this.left != null && this.left.item.compareTo(item)==0 || this.right!=null && this.right.item.compareTo(item)==0){
return this;
}
Node<T> value = null;
if(this.left != null){
value = this.left.searchParentNode(item);
}
if(value != null){
return value;
}
if(this.right != null){
return this.right.searchParentNode(item);
}
return null;
}
/**
* 获取当前节点子树最小节点
* @return
*/
public Node<T> minNode(){
if(this.left != null){
return this.left.minNode();
}
return this;
}
/**
* 节点的中序遍历
* @param dst 遍历节点的存放容器
*/
public void infixList(List<T> dst){
if(this.left != null){
this.left.infixList(dst);
}
dst.add(this.item);
if(this.right != null){
this.right.infixList(dst);
}
}
@Override
public String toString() {
return "Node{" +
"item=" + item +
'}';
}
}
private Node<T> root;
public void add(T item){
Node<T> node = new Node<>(item);
if(this.root == null){
this.root = node;
}
else{
this.root.add(node);
}
}
public boolean delete(T item){
if(root.item.compareTo(item)==0){//删除根节点
if(root.left==null && root.right==null){
this.root = null;
return true;
}
else if(root.left==null){
this.root = root.right;
return true;
}
else if(root.right==null){
this.root = root.left;
return true;
}
else if(root.left!=null && root.right!=null){
//寻找右子树最小节点
Node<T> parent = this.root;
Node<T> node = this.root.right;
while(node.left!=null){
parent = node;
node = node.left;
}
parent.left = null;
this.root.item = node.item;
return true;
}
}
//待删除结点的父节点
Node<T> parent = this.root.searchParentNode(item);
if(parent == null){
return false;
}
//待删除结点
Node<T> node = parent.left;
if(parent.right != null && item.compareTo(parent.right.item)==0){
node = parent.right;
}
if(node.left==null && node.right==null){
if(parent.left==node){
parent.left = null;
}
else{
parent.right = null;
}
}
else if(node.left==null){
if(parent.left==node){
parent.left = node.right;
}
else{
parent.right = node.right;
}
}
else if(node.right==null){
if(parent.left==node){
parent.left = node.left;
}
else{
parent.right = node.left;
}
}
else{
//寻找待删除结点左节点最大节点
Node<T> maxParent = null;
Node<T> maxNode = node.left;
while(maxNode.right != null){
maxParent = maxNode;
maxNode = maxNode.right;
}
if(maxParent==null){
node.left = null;
}
else{
maxParent.right = null;
}
node.item = maxNode.item;
}
return true;
}
public List<T> infixList(){
List<T> rst = new ArrayList<>();
this.root.infixList(rst);
return rst;
}
}
效果:
三.总结
1.对排序二叉树中序遍历可得到一个有序数列
2.子节点没有指向父节点的指针,对于删除操作将寻找节点的父节点,相对繁琐,可以为每个节点增加一个指向父节点的指针