二叉搜索树(BST)
- 二叉搜索树它是二叉树的一种类别,其节点按特定顺序排列。这也称为有序二叉树。
- 在二叉搜索树中,左子树中所有节点的值小于根的值。
- 类似地,右子树中所有节点的值大于或等于根的值。
- 此规则将递归地应用于根的所有左子树和右子树。
前序遍历:30,15,7,22,17,27,60,45,75
中序遍历: 7,15,17,22,27,30,45,60,75
后序遍历:7,17,27,22,15,45,75,60,30
二叉查找树的实现:
API设计:
1.节点类:
2.二叉搜索树类:
//节点类
public class Node<K, V> {
//为了方便使用,成员变量设置为public
public Node left; //记录左子节点
public Node right; //记录右子节点
public K key; //键
public V value; //值
public Node(K key, V value, Node left, Node right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
}
}
//K extends Comparable<K> 让我们的key具有排序的功能
public class BinaryTree<K extends Comparable<K>,V> {
private Node root; //记录根节点
private int N; //记录树中元素个数
public BinaryTree() {}
/**
* 向树中插入一个节点
* @param key 节点的键
* @param value 节点的值
*/
public void put(K key, V value){
root = put(root, key, value);
}
/**
* 向指定树x中插入一个节点
* 1.如果x==null,则创建节点,作为x
* 2.如果x!=null
* 2.1 如果 key < x.key, 则往左子树插入
* 2.2 如果 key > x.key, 则往右子树插入
* 2.3 如果 key == x.key, 则将x.value 替换为 value
* @param x 树x的根节点
* @param key 节点的键
* @param value 节点的值
* @return 插入节点后的新树
*/
private Node put(Node x, K key, V value){
//1.如果x==null,则创建节点,作为x
if(x == null){
N++;
return new Node<K,V>(key, value, null, null);
}
//2.如果x!=null
int cmp = key.compareTo((K)x.key);
if(cmp < 0){
//2.1 如果 key < x.key, 则往左子树插入
x.left = put(x.left, key, value);
}else if(cmp > 0){
//2.2 如果 key > x.key, 则往右子树插入
x.right = put(x.right, key, value);
}else{
//2.3 如果 key == x.key, 则将x.value 替换为 value
x.value = value;
}
return x;
}
/**
* 根据key查找节点的值
* @param key 要查找的节点的键
* @return 返回查找到的节点的值
*/
public V get(K key){
return get(root, key);
}
/**
* 从指定的树x中,找出key对应的值
* 1.如果x==null,则返回null
* 2.如果x!=null
* 2.1 如果 key < x.key, 则往左子树查找
* 2.2 如果 key > x.key, 则往右子树查找
* 2.3 如果 key == x.key, 则找到,并返回value
* @param x 指定的树的根节点
* @param key 要查找的节点的键
* @return 查找到的节点的值,未找到则返回null
*/
private V get(Node x, K key){
// 1.如果x==null,则返回null
if(x == null) return null;
// 2.如果x!=null
int cmp = key.compareTo((K) x.key);
if(cmp < 0){
// 2.1 如果 key < x.key, 则往左子树查找
return get(x.left, key);
}else if(cmp > 0){
// 2.2 如果 key > x.key, 则往右子树查找
return get(x.right, key);
}else{
// 2.3 如果 key == x.key, 则找到,并返回value
return (V) x.value;
}
}
/**
* 删除树中指定的key的节点
* @param key 要删除的节点的key
*/
public void delete(K key){
root = delete(root, key);
}
/**
* 从指定树x中删除指定key的节点
* @param x 指定树x的根节点
* @param key 要删除的节点的key
* @return 返回删除后的新树
*/
private Node delete(Node x, K key){
//1.如果 x==null,返回null
if(x == null) return null;
//2.如果x != null
int cmp = key.compareTo((K)x.key);
if(cmp < 0){
// 2.1 如果 key < x.key, 则往左子树查找
x.left = delete(x.left, key);
}else if(cmp > 0){
// 2.2 如果 key > x.key, 则往右子树查找
x.right = delete(x.right, key);
}else{
N--;
// 2.3 如果 key == x.key,找到要删除的节点,删除该节点,有3种情况
if(x.right == null){
// 2.3.1 如果 右子树为null,则返回x节点的左子树
return x.left;
}else if (x.left == null){
// 2.3.2 如果 左子树为null,则返回x节点的右子树
return x.right;
}else{
// 2.3.3 x节点的左右子树都不为null,我们需要查找x节点的右子树中最小的节点 node
//将该节点替换要删除的节点
//2.3.3.1 查找x的右子树的最小节点node及其父节点pre
Node<K,V> node = x.right, pre = null;
while(node.left != null){
pre = node;
node = node.left;
}
if(pre != null) pre.left = null; //断开node节点
else x.right = null;
//2.3.3.2 将node节点的左右指针指向x节点的左右子树
node.left = x.left;
node.right = x.right;
//2.3.3.3 将node节点 代替 原来的x节点
x = node;
}
}
return x;
}
/**
* 获取树中节点的个数
* @return 返回节点个数
*/
public int size(){
return N;
}
/**
* 获取二叉搜素树的最小键
* @return
*/
public K min(){
return (K) minNode(root).key;
}
/**
* 查找树x的最小节点
* @param x
* @return
*/
private Node minNode(Node x){
if(x.left == null){
return x;
}
return minNode(x.left);
}
/**
* 获取二叉搜素树的最大键
* @return
*/
public K max(){
return (K) maxNode(root).key;
}
/**
* 查找树x的最大节点
* @param x
* @return
*/
private Node maxNode(Node x){
if(x.right == null){
return x;
}
return maxNode(x.right);
}
/**
* 中序遍历整个树
*/
public void inOrder(){
inOrder(root);
}
/**
* 中序遍历
* @param x 遍历的树的根节点
*/
private void inOrder(Node x){
if(x != null){
inOrder(x.left);
System.out.print("[" + x.key + "," + x.value + "] ");
inOrder(x.right);
}
}
/**
* 前序遍历
*/
public void preOrder(){
preOrder(root);
}
/**
* 前序遍历
* @param x
*/
private void preOrder(Node x){
if(x != null){
System.out.print("[" + x.key + "," + x.value + "] ");
preOrder(x.left);
preOrder(x.right);
}
}
/**
* 后序遍历
*/
public void afterOrder(){
afterOrder(root);
}
/**
* 后序遍历
* @param x
*/
private void afterOrder(Node x){
if(x != null){
afterOrder(x.left);
afterOrder(x.right);
System.out.print("[" + x.key + "," + x.value + "] ");
}
}
/**
* 层次遍历
*/
public void levelOrder(){
levelOrder(root);
}
/**
* 层次遍历
* @param x
*/
private void levelOrder(Node x){
if(x == null) return;
Queue<Node> qu = new ArrayDeque<Node>();
qu.offer(x);
//a:每一层的节点个数,b:统计每一层的节点个数
int a = 1, b = 0;
while(!qu.isEmpty()){
Node pollNode = qu.poll();
a--;
System.out.print(pollNode.key+" ");
if(pollNode.left != null){
b++;
qu.offer(pollNode.left);
}
if(pollNode.right != null){
b++;
qu.offer(pollNode.right);
}
if(a == 0){
a = b;
b = 0;
System.out.println();
}
}
}
/**
* 获取树的最大高度
* @return
*/
public int maxHeight(){
return maxHeight(root);
}
/**
* 获取树x的高度
* @param x
* @return
*/
private int maxHeight(Node x){
if(x == null) return 0;
//左子树的高度
int leftHeight = maxHeight(x.left);
//右子树的高度
int rightHeight = maxHeight(x.right);
//返回左右子树高的 + 1
return Math.max(leftHeight, rightHeight) + 1;
}
}