二叉搜索树
Binary Search Tree
能够用于快速查找的存储数据结构,左子树值<根节点值<右子树值
# 定义
它或者是一棵空树,或者是具有下列性质的二叉树:
-
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
-
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
-
它的左、右子树也分别为二叉排序树。
# 遍历
以遍历根节点的顺序来定义
-
前序遍历:根-左-右
-
中序遍历:左-根-右 —>遍历结果为有序递增序列
-
后序遍历:左-右-根
# 前驱节点和后继节点
前驱节点
定义: 二叉树中数据值小于该结点的"最大结点"。
- 有左子树,就是左子树的最大值
- 无左子树
- 是父节点(不为空)的右子树,父节点为前驱
- 是父节点的左子树,离它最近的有右孩子的节点即为前驱
后继节点
**定义:**二叉树中数据值大于该结点的"最小结点"。
-
有右子树,就是右子树的最小值
-
无右子树
-
是父节点(不为空)的左子树,父节点为前驱
-
是父节点的左子树,离它最近的左孩子的节点即为前驱
-
# 节点删除
- 被删除节点有前驱: 前驱顶替
- 被删除节点只有左子树或者右子树:孩子顶替
- 被删除节点没有子树(根节点或叶子节点):直接删除
package com.piziwang.tree.bstree;
/**
* 二叉查找树
* @author PIZIWANG
* @date 2022-05-04 10:50
**/
public class BSTree<T extends Comparable<T>> {
private BSTNode<T> mRoot;
/**
* bstnode
* @author piziwang
* @date 2022/05/04
*/
public class BSTNode<T extends Comparable<T>>{
/*值*/
T key;
/*左节点*/
BSTNode<T> left;
/*右节点*/
BSTNode<T> right;
/*父节点*/
BSTNode<T> parent;
public BSTNode(T key, BSTNode<T> left, BSTNode<T> right, BSTNode<T> parent) {
this.key = key;
this.left = left;
this.right = right;
this.parent = parent;
}
}
/**
* 插入
* @param key 关键
*/
public void insert(T key){
BSTNode<T> newNode = new BSTNode<T>(key, null,null,null);
if (newNode != null) {
insert(this,newNode);
}
}
/**
* 插入
* @param bst tbs树
* @param newNode 新节点
*/
private void insert(BSTree<T> bst, BSTNode<T> newNode) {
BSTNode<T> current = bst.mRoot;
BSTNode<T> currentParent = null;
/*新插入节点与当前节点的比较标志*/
int cmp;
/*找到最终的插入位置*/
while (current != null) {
currentParent=current;
cmp = newNode.key.compareTo(current.key);
if (cmp < 0) {
current = current.left;
}else {
current = current.right;
}
}
/*插入*/
newNode.parent = currentParent;
if(currentParent == null){
/*是空树*/
bst.mRoot = newNode;
}else {
cmp = newNode.key.compareTo(currentParent.key);
if (cmp < 0) {
currentParent.left = newNode;
}else {
currentParent.right = newNode;
}
}
}
/**
* 先序遍历
* @param tree 树
* 访问根结点;
* 先序遍历左子树;
* 先序遍历右子树
*/
private void preOrder(BSTNode<T> tree){
if (tree!= null) {
System.out.print(tree.key+" ");
preOrder(tree.left);
preOrder(tree.right);
}
}
public void preOrder(){
preOrder(mRoot);
}
/**
* 中序遍历左子树;
* 访问根结点;
* 中序遍历右子树。
*/
private void inOrder(BSTNode<T> tree){
if (tree!= null) {
inOrder(tree.left);
System.out.print(tree.key + " ");
inOrder(tree.right);
}
}
public void inOrder(){
inOrder(mRoot);
}
/**
* 后序遍历左子树;
* 后序遍历右子树;
* 访问根结点;
*/
private void postOrder(BSTNode<T> tree){
if (tree!= null) {
postOrder(tree.left);
postOrder(tree.right);
System.out.print(tree.key + " ");
}
}
public void postOrder(){
postOrder(mRoot);
}
/**
* 获取树的深度
* @return
*/
public int depth() {
return depth(mRoot);
}
private int depth(BSTNode<T> bstNode) {
int m,n;
if (bstNode == null) {
return 0;
}
else {
m = depth(bstNode.left);
n = depth(bstNode.right);
if(m>n){
return m+1;
}else {
return n+1;
}
}
}
/**
* 搜索
* @param current
* @param key
* @return
*/
public BSTNode<T> search(BSTNode current,T key) {
if (current == null) {
return null;
}
int cmp = current.key.compareTo(key);
if (cmp < 0) {
return search(current.right,key);
}else if (cmp> 0) {
return search(current.left, key);
}else {
return current;
}
}
public BSTNode<T> search(T key) {
return search(mRoot,key);
}
/**
* 获取树的最大值
* @return {@link T}
*/
public T maximum(){
BSTNode<T> p = maximum(mRoot);
if (p != null) {
return p.key;
}
return null;
}
private BSTNode<T> maximum(BSTNode<T> tree) {
if (tree == null) {
return null;
}
if (tree.right!=null) {
return maximum(tree.right);
}else {
return tree;
}
}
/**
* 获取树的最小值
* @return {@link T}
*/
public T minimum() {
BSTNode<T> p = minimum(mRoot);
if (p != null) {
return p.key;
}
return null;
}
private BSTNode<T> minimum(BSTNode<T> tree) {
if (tree == null) {
return null;
}
if (tree.left != null) {
return minimum(tree.left);
}else {
return tree;
}
}
/**
* 查找"二叉树中数据值小于该结点"的"最大结点"
* 1.存在左子树,则左子树最大节点就是前驱
* 2. 不存在左子树,找父节点,如果该节点是父节点右孩子,则父节点就是前驱,
* 如果该节点是父节点的左孩子,则需要向上找到离x最近的,拥有右孩子的父节点
*/
public BSTNode<T> predecessor( BSTNode<T> x) {
// 1.存在左子树,则左子树最大节点就是前驱
if (x.left!=null) {
return maximum(x.left);
}
// 2. 不存在左子树,找父节点,如果该节点是父节点右孩子,则父节点就是前驱
BSTNode<T> y = x.parent;
while ((y!=null) && (x==y.left)) {
x = y;
y = y.parent;
}
return y;
}
/**
* 查找"二叉树中数据值大于该结点"的"最小结点
* 1.存在右子树,则右子树的最小值就是后驱
* 2. 没有右子树,如果是父节点的左孩子,则父节点就是后驱
* 向上找离x最近的,拥有左孩子的父节点
* @param x
* @return
*/
public BSTNode<T> successor(BSTNode<T> x) {
if (x.right != null) {
return minimum(x.right);
}
BSTNode<T> y = x.parent;
while ((y != null)&&(x==y.right)) {
x= y;
y = y.parent;
}
return y;
}
/**
* 删除值为key的节点
* @param key 关键
*/
public void remove(T key){
BSTNode<T> z;
// 待删除节点存在
if ((z=search(mRoot,key))!=null) {
remove(this,z);
}
}
/**
* 删除
* 1.被删除节点有左右子树,用前驱顶替
* 2. 被删除节点只有一个子树,直接用子树顶替
* 3. 被删除节点没有子树,直接删除
* @param bst bst
* @param z z
* @return {@link BSTNode}<{@link T}>
*/
private BSTNode<T> remove(BSTree<T> bst, BSTNode<T> z) {
BSTNode<T> x = null;
BSTNode<T> y = null;
// 只有左子树或者右子树,直接用子树替代
if ((z.left==null)||(z.right == null)) {
y = z;
}else {
y = predecessor(z);
}
// 用x记录,将被用于顶替删除节点的节点的子树
if(y.left!=null){
x = y.left;
}else {
x = y.right;
}
// 调整子树的父节点
if (x != null) {
x.parent = y.parent;
}
// y是根节点
if (y.parent == null) {
bst.mRoot = x;
} else if (y == y.parent.left) {
y.parent.left = x;
} else {
y.parent.right = x;
}
// 替换删除的节点的值
if (y != z) {
z.key = y.key;
}
return y;
}
/**
* 摧毁
* @param tree 树
*/
private void destroy(BSTNode<T> tree) {
if (tree==null) {
return ;
}
if (tree.left != null) {
destroy(tree.left);
}
if (tree.right != null) {
destroy(tree.right);
}
tree=null;
}
public void clear() {
destroy(mRoot);
mRoot = null;
}
/**
* 打印
* @param tree 树
* @param key 关键
* @param direction 0- 跟节点 1 右子树 -1 左子树
*/
private void print(BSTNode<T> tree, T key, int direction) {
if(tree != null) {
// tree是根节点
if(direction==0)
{
System.out.printf("%2d is root\n", tree.key);
} else // tree是分支节点
{
System.out.printf("%2d is %2d's %6s child\n", tree.key, key, direction==1?"right" : "left");
}
print(tree.left, tree.key, -1);
print(tree.right,tree.key, 1);
}
}
/**
* 打印
*/
public void print() {
if (mRoot != null) {
print(mRoot, mRoot.key, 0);
}
}
}