二叉查找树
二叉查找树定义
定义:一颗二叉查找树(BST)是一棵二叉树,其中每个结点都含有一个Comparable的键(以及相关联的值)且每个结点的键都大于其左子树中的任意结点的键而小于右子树的任意结点的键. 二叉查找树中搜索,插入,删除的复杂度等于树高,即O(log(n))
二叉查找树代码实现
基本方法实现
import java.util.ArrayList;
import java.util.List;
public class BST <Key extends Comparable<? super Key>,Value> {
/** 根节点 */
private Node root;
/** 内部节点类 */
private class Node{
private Key key;//键
private Value value;//值
private Node left;//左子节点
private Node right;//右子节点
private int N;//以该节点为根节点的子树中的节点总数
Node(Key key,Value value,int N){
this.key=key;
this.value=value;
this.N=N;
}
}
/**
* 整棵树的节点数量
* @return
*/
public int size(){
return size(root);
}
/**
* 返回以node节点为根的子树的大小(节点数量)
* @param node
* @return
*/
private int size(Node node){
if(node==null){
return 0;
}
return node.N;
}
/**
* 更新节点的size
* @param node
* @return
*/
private int updateSize(Node node){
return size(node.left)+size(node.right)+1;
}
}
查找某个节点的值
/**
* 查找树中key对应的value值
* @param key 要查找的key值
* @return key对应的value值,不存在则返回null
*/
public Value get(Key key){
return get(root,key);
}
/**
* 查找以node节点为根节点的子树中key对应的value值
* @param node 要作为根节点的节点
* @param key 要查找的key值
* @return key对应的value值,不存在则返回null
*/
private Value get(Node node,Key key){
if(node==null){
throw new RuntimeException("Cannot find key "+key);
}
int compareResult = key.compareTo(node.key);
if(compareResult<0){
return get(node.left,key);
}else if(compareResult>0){
return get(node.right,key);
}else{
return node.value;
}
}
查找树中最小的节点值
/**
* 查找树中最小的key
* @return 最小key值
*/
public Key min(){
return min(root).key;
}
/**
* 查找以node为根节点的子树中最小的key
* @param node 子树的跟节点
* @return 最小的key对应的node
*/
private Node min(Node node){
//如果树为空,则直接返回null
if(node==null){
return null;
}
//如果节点为叶子节点,则返回该节点
if(node.left==null){
return node;
}
//递归查找最左边的节点,也就是最小的节点
return min(node.left);
}
查找树中最大的节点值
/**
* 查找树中最大的key
* @return 最大key值
*/
public Key max(){
return max(root).key;
}
/**
* 查找以node为根节点的子树中最大的key
* @param node 子树的根节点
* @return 最大的key对应的node
*/
private Node max(Node node){
if(node==null){
return null;
}
if(node.right==null){
return node;
}
return max(node.right);
}
插入节点
向二叉搜索树中插入新元素时,必须先检测这个元素是否在树中已经存在。如果已经存在,则不进行插入,如果元素不存在则将新元素插入到搜索停止的时候,也就是每次插入都是一个叶子节点。
/**
* 插入节点
* @param key 要插入的节点的key
* @param value 要插入的节点的value
*/
public void put(Key key,Value value){
root=put(root,key,value);
}
private Node put(Node node,Key key, Value value){
//node==null则表示已经找到要插入新节点的地方
if(node==null){
return new Node(key,value,1);
}
int compareResult = key.compareTo(node.key);
if(compareResult<0){
node.left=put(node.left,key,value);
}else if(compareResult>0){
node.right=put(node.right,key,value);
}else{
node.value=value;//如果存在相同的key,则更新其value值
}
node.N=updateSize(node);//新增节点需要更新N值
return node;
}
删除节点
要删除的节点存在以下三种情况:
- 要删除的节点为叶子节点,即没有子树
- 要删除的节点有且仅有一颗子树,即有左子树或右子树
- 要删除的节点有左右子树.( 第3种情况比较复杂,需要找出要删除节点的右子树中最小的节点[或者使用左子树中最大的节点]替换掉要删除的节点.)
/**
* 删除key对应的节点
* @param key
*/
public void delete(Key key){
root=delete(root,key);
}
private Node delete(Node node,Key key){
//没有查找到
if(node==null){
return null;
}
int compareResult = key.compareTo(node.key);
if(compareResult<0){
//要删除的节点位于左子树
node.left=delete(node.left,key);
}else if(compareResult>0){
//要删除的节点位于右子树
node.right=delete(node.right,key);
}else{
/**
*查找到要删除的节点,分成三种情况
* 1.要删除的节点有左右子树
* 2.要删除的节点有且仅有左子树或者右子树
* 3.要删除的节点为叶子节点,即没有子树
*/
if(node.left!=null&&node.right!=null){
Node minOfRightTree = min(node.right);//node节点中右子树中最小的节点
node.key=minOfRightTree.key;//替换掉要删除节点的key
node.value=minOfRightTree.value;//替换掉要删除节点的value
node.right=delete(node.right,minOfRightTree.key);//要删除掉node节点中右子树中最小的节点,因此进行递归删除即可。
}else {
//情况2和情况3均使用子节点替换掉要删除的节点即可.
node=node.left!=null?node.left:node.right;
}
}
node.N=updateSize(node);
return node;
}
中序遍历树中节点
public List<Key> keys(){
ArrayList<Key> list = new ArrayList<>();
keys(root,list);
return list;
}
private void keys(Node node, ArrayList<Key> list){
if(node==null){
return;
}
keys(node.left,list);
list.add(node.key);
keys(node.right,list);
}
浅析树结构(一)二叉查找树(BST树代码实现)
浅析树结构(二)AVL平衡二叉树(AVL树原理及代码实现)
浅析树结构(三)红黑树