十、二叉排序树(Binary Sort Tree)
1、概念
也称为二叉搜索树(Binary Search Tree),对于每个非叶子节点,其左子节点的值小于或等于当前节点的值,而右子节点的值大于或等于当前节点的值。
2、方法
-
添加节点
判断是否存在根节点,不存在直接赋值为根节点。存在则继续判断节点值和根节点值的大小,如果小于则向左子树添加,如果大于等于则向右子树添加。添加到子树时,先判断子节点是否存在,如果不存在则 直接指定为子节点,否则就给以子节点为根节点的子树,添加节点。
-
查找结点
判断是否和根节点值相等,如果相等,则直接返回根节点。如果不等,则判断节点值和根节点值的大小,如果小于则向左子树查找,如果大于等于则向右子树查找(和添加时的顺序一致)。
-
查找父节点
判断是否和当前节点的左子节点或右子节点的值相等,如果相等,则直接返回当前节点。如果不等,则需要判断节点值和当前节点值的大小,如果小于,并且存在左子节点,则向左子树查找。如果大于等于,并且存在右子节点,则向右子树查找(和添加时的顺序一致)。
-
删除节点
-
删除叶子节点。找到父节点,判断目标节点是父节点的左子节点还是右子节点,并解除相应的绑定关系(置空指针)。
如果没有父节点(目标节点是根节点),则直接将根节点置空。
-
删除只有一棵子树的节点。找到父节点,判断目标节点是父节点的左子节点还是右子节点,再找到目标节点的子树是左边还是右边,并建立父节点和目标节点的子节点的绑定关系。
如果没有父节点(目标节点是根节点),则直接指定新的根节点是当前根节点的左子节点或右子节点。
-
删除有两棵子树的节点。找到目标节点的左子节点的最大值节点或右子节点的最小值节点,删除该节点,并将该节点的值赋给目标节点。
-
3、示例
import java.util.Stack;
class BinarySortTree<T extends Comparable<T>> {
private TreeNode<T> root;
public void addNode(TreeNode<T> node) {
if (null == root) {
this.root = node;
return;
}
this.root.addNode(node);
}
public void infixOrder() {
if (null == this.root) {
return;
}
Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
TreeNode<T> node = this.root;
while (!stack.isEmpty() || null != node) {
if (null != node) {
stack.push(node);
node = node.getLeft();
} else {
node = stack.pop();
System.out.print(node.getData() + " ");
node = node.getRight();
}
}
System.out.println();
}
public void deleteNode(T data) {
if (null == root) {
return;
}
TreeNode<T> target = root.searchNode(data);
// 叶子节点
if (null == target.getLeft() && null == target.getRight()) {
if (root.getData().equals(data)) { // 只剩下根节点
root = null;
return;
}
TreeNode<T> parent = root.searchParentNode(data);
if (null != parent.getLeft() && parent.getLeft().getData().equals(data)) {
parent.setLeft(null);
} else if (null != parent.getRight() && parent.getRight().getData().equals(data)) {
parent.setRight(null);
}
return;
}
// 含有一棵子树
if (null == target.getLeft() || null == target.getRight()) {
TreeNode<T> parent = root.searchParentNode(data);
TreeNode<T> left = target.getLeft();
if (null != left) {
if (null == parent) { // 目标节点是根节点
root = left;
} else {
if (null != parent.getLeft() && parent.getLeft().getData().equals(data)) {
parent.setLeft(left);
} else if (null != parent.getRight() && parent.getRight().getData().equals(data)) {
parent.setRight(left);
}
}
} else {
TreeNode<T> right = target.getRight();
if (null == parent) { // 目标节点是根节点
root = right;
} else {
if (null != parent.getLeft() && parent.getLeft().getData().equals(data)) {
parent.setLeft(right);
} else if (null != parent.getRight() && parent.getRight().getData().equals(data)) {
parent.setRight(right);
}
}
}
return;
}
// 含有两棵子树
target.setData(findLeftMaxAndDelete(target));
}
/**
* 找到左子树中最大值的节点
*/
private T findLeftMaxAndDelete(TreeNode<T> node) {
node = node.getLeft();
while (null != node.getRight()) {
node = node.getRight();
}
T data = node.getData();
deleteNode(data); // 叶子节点或含有一棵子树,不会StackOverflowError
return data;
}
/**
* 找到右子树中最小值的节点
*/
private T findRightMinAndDelete(TreeNode<T> node) {
node = node.getRight();
while (null != node.getLeft()) {
node = node.getLeft();
}
T data = node.getData();
deleteNode(data); // 叶子节点或含有一棵子树,不会StackOverflowError
return data;
}
}
class TreeNode<T extends Comparable<T>> {
private T data;
private TreeNode<T> left;
private TreeNode<T> right;
public TreeNode(T data) {
this.data = data;
}
public void addNode(TreeNode<T> node) {
if (null == node) {
return;
}
if (0 < this.data.compareTo(node.data)) {
if (null == this.left) {
this.left = node;
} else {
this.left.addNode(node);
}
} else { // 相同的值,添加到最后
if (null == this.right) {
this.right = node;
} else {
this.right.addNode(node);
}
}
}
public TreeNode<T> searchNode(T data) {
if (this.data.equals(data)) {
return this;
}
if (0 < this.data.compareTo(data)) {
if (null == this.left) {
return null;
}
return this.left.searchNode(data);
}
if (null == this.right) {
return null;
}
return this.right.searchNode(data);
}
public TreeNode<T> searchParentNode(T data) {
if ((null != this.left && this.left.data.equals(data)) ||
(null != this.right && this.right.data.equals(data))) {
return this;
}
if (null != this.left && (0 < this.data.compareTo(data))) {
return this.left.searchParentNode(data);
}
if ((null != this.right && (0 >= this.data.compareTo(data)))) {
return this.right.searchParentNode(data);
}
return null;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public TreeNode<T> getLeft() {
return left;
}
public void setLeft(TreeNode<T> left) {
this.left = left;
}
public TreeNode<T> getRight() {
return right;
}
public void setRight(TreeNode<T> right) {
this.right = right;
}
}
class Test {
public static void main(String[] args) {
Integer[] array = { 4, 6, 5, 2, 1, 3, 7 };
/*
* 4
* 2 6
* 1 3 5 7
*/
BinarySortTree<Integer> bst = new BinarySortTree<Integer>();
for (int i = 0, len = array.length; i < len; i++) {
bst.addNode(new TreeNode<Integer>(array[i]));
}
bst.infixOrder(); // 1 2 3 4 5 6 7
bst.deleteNode(3);
bst.infixOrder();
bst.deleteNode(2);
bst.infixOrder();
bst.deleteNode(6);
bst.infixOrder();
}
}