package com.wy.tree;
import java.util.LinkedList;
import java.util.Queue;
/**
* @date 2018/3/28 19:12
* 二叉搜索树
*/
public class BST<Key extends Comparable<Key>,Value> {
public Node root; //二叉搜索树根节点
private class Node{
private Key key; //键
private Value value; //值
private Node left,right; //指向子树的链接
private int N; //以该节点为根的子树中的总数节点
public Node(Key key,Value value,int N){
this.key = key;
this.value = value;
this.N = N;
}
}
// 构造函数, 默认构造一棵空二分搜索树
public BST() {
root = null;
}
//获取树的元素个数
public int size(){
return size(root);
}
private int size(Node root){
if(root==null)
return 0;
return root.N;
}
//插入数据
public void put(Key key,Value value){
//增加数据,找到则更新数据,否则创建一个新的节点
root = put(root,key,value);
}
private Node put(Node root,Key key,Value value){
if(root==null) {
return new Node(key, value, 1);
}
int cmp = key.compareTo( root.key );//将待插入的数据的键与根节点的键比较
if(cmp<0){ //如果待插入的键小于根节点的键,则在左边插入
root.left = put(root.left,key,value);
}else if(cmp>0){
root.right = put(root.right,key,value);
}else{ //待插入的数据的键与根节点的键相等
root.key = key;
}
// 更新数的元素个数
root.N = size(root.left)+size(root.right)+1;
return root;
}
// 查找操作
public Value get(Key key){
return get(root,key);
}
private Value get(Node root,Key key){
// 在以root为根节点的子树中查找并返回key对于的值
if(root==null)
return null;
int cmp = key.compareTo(root.key);
if(cmp<0){ //则在左子树中查找
return get(root.left,key);
}else if(cmp>0){
return get(root.right,key);
}else{
return root.value;
}
}
//前序遍历 使用递归
public void preOrder(Node root){
if(root!=null){
System.out.print( root.value+" " );
preOrder(root.left);
preOrder(root.right);
}
}
//中序遍历 使用递归
public void inOrder(Node root){
if(root!=null){
inOrder(root.left);
System.out.print( root.value+" " );
inOrder(root.right);
}
}
//后序遍历 使用递归
public void postOrder(Node root){
if(root!=null){
postOrder(root.left);
postOrder(root.right);
System.out.print( root.value+" " );
}
}
//层次遍历
public void levelOrder(Node root){
Queue<Node> queue = new LinkedList<Node>();
if(root!=null){
queue.offer(root);
}
while (!queue.isEmpty()){
root = queue.poll(); //出队,并移除该元素
System.out.print( root.value+" " );
//把左右孩子入队
if(root.left!=null)
queue.offer( root.left );
if(root.right!=null)
queue.offer( root.right);
}
}
//最小值
public Key min(){
if(root==null)
return null;
return min(root).key;
}
private Node min(Node root){ //可以尝试非递归的写法
if(root.left==null)//如果树的左孩子为空,则最小值就是根
return root;
return min(root.left);
}
//最大值
public Key max(){
if(root==null)
return null;
return max(root).key;
}
private Node max(Node root){ //可以尝试非递归的写法
if(root.right==null)//如果树的左孩子为空,则最小值就是根
return root;
return max(root.right);
}
//删除最小值
public void deleteMin(){
//删除最小值后返回一个新的节点
root = deleteMin(root);
}
private Node deleteMin(Node root) {
if(root.left==null) //如果左孩子为空,则说明最小值就是根节点,那么新的二叉搜索树就是右子树,直接返回即可
return root.right;
root.left = deleteMin(root.left);
root.N = size(root.left)+size(root.right)+1;
return root;
}
//删除最大节点
public void deleteMax(){
root = deleteMax(root);
}
private Node deleteMax(Node root){
if(root.right==null)
return root.left;
root.right = deleteMax(root.right);
root.N = size(root.left)+size(root.right)+1;
return root;
}
//删除节点 Hibbard算法 时间复杂度为 O(logn)
public void delete(Key key){
root = delete(root,key);
}
private Node delete(Node root,Key key){
if(root==null)
return null;
int cmp = key.compareTo(root.key);
if(cmp<0){
root.left = delete(root.left,key);
}else if(cmp>0){
root.right = delete(root.right,key);
}else{
if(root.right==null) //删除的是没有右子树的情况
return root.left;
if(root.left==null)
return root.right;
//向把待删除的键复制一份
Node t = root;
//以t为根节点找到他右子树的最小节点
root = min(t.right);
//然后删除右子树中最小的节点,返回这颗右子树
root.right = deleteMin(root.right);
root.left = t.left;
}
root.N = size(root.left)+size(root.right)+1;
return root;
}
//floor操作
public Key floor(Key key){
Node x = floor(root,key);
if(x==null)
return null;
return x.key;
}
private Node floor(Node root, Key key) {
if(root==null)
return null;
int cmp = key.compareTo(root.key);
if(cmp==0){ //表示根节点正式我们要找的元素
return root;
}else if(cmp<0){
return floor(root.left,key); //在左子树中去查找
}
Node t = floor(root.right,key); //可能在右子树中
if(t!=null){
return t;
}else{
return root;
}
}
//ceiling
public Key ceiling(Key key){
Node x = ceiling(root,key);
if(x==null)
return null;
return x.key;
}
private Node ceiling(Node root,Key key){
if(root==null)
return null;
int cmp = key.compareTo(root.key);
if(cmp==0){ //表示根节点正式我们要找的元素
return root;
}else if(cmp>0){
return ceiling(root.right,key); //在左子树中去查找
}
Node t = floor(root.left,key); //可能在右子树中
if(t!=null){
return t;
}else{
return root;
}
}
// 返回排名第 k的节点
public Key select(int k){
return select(root,k).key;
}
private Node select(Node root,int k){
if(root==null)
return null;
//计算左子树的元素个数
int t = size(root.left);
if(k<t){ //排名第k的元素在左子树中
return select(root.left,k);
}else if(k>t){ //在右子树中排名,减去左子树的个数在减 1
return select(root.right,k-t-1);
}else{
return root;
}
}
//键的排名
public int rank(Key key){
return rank(root,key);
}
private int rank(Node root,Key key){
if(root==null)
return 0;
int cmp = key.compareTo(root.key);
if(cmp<0){
return rank(root.left,key);
}else if(cmp>0){ //在右子树中,则需要加上左子树的个数
return 1+size(root.left)+rank(root.right,key);
}else { //与根节点相等,则只需要计算左子树元素个数即可
return size(root.left)+1;
}
}
}
测试用例
package com.wy.tree;
/**
* @date 2018/3/28 19:38
*/
public class BSTTest {
public static void main(String[] args) {
BST<Integer, Integer> bst = new BST<Integer, Integer>();
bst.put(6,6);
bst.put(3,3);
bst.put(14,14);
bst.put(16,16);
bst.put(10,10);
bst.put(9,9);
bst.put(13,13);
bst.put(11,11);
bst.put(12,12);
System.out.println( bst.size() );
System.out.println( bst.get(6));
//前序遍历
bst.preOrder( bst.root );
System.out.println();
bst.levelOrder(bst.root);
System.out.println();
System.out.println( "16排名第"+bst.rank(16) );
System.out.println(bst.floor(15));
System.out.println( bst.ceiling(15) );
}
}