二叉查找树
简述
二叉查找树是一颗二叉树,其每个节点都含有可比较的Key值及一个Value值。其满足其上每个节点的键都大于其左子树中任意节点的键,小于其右子树中任意节点的键。
复杂度
二叉查找树结合了链表的插入灵活性及有序数组的查找高效性,在平均情况下查询复杂度为O( log ( n ) ),插入复杂度与查询复杂度近似。插入本身有序的数据时二叉查找树会退化为单链表,此时无法保证平衡,树的深度为n。
操作描述
查找
由于二叉查找树的性质易得查找过程如下:
首先从根节点开始,比较当前节点Key与所查找Key的大小。
若当前节点Key小于所找的Key,则从当前节点的右子节点继续寻找。
若当前节点Key大于所找的Key,则从当前节点的左子节点继续寻找。
若当前节点Key等于所找的Key,则返回对应的值。
若当前节点不存在,则可知所查找的Key不存在,查找未命中。插入
由二叉查找树的性质易得插入过程只需效仿查找过程即可。
若最后可查找到Key值相同的节点则更新节点的Value。
若最后无法查找到Key值相同的节点则根据最后到达节点的Key确定操作:
若最后到达节点的Key值小于欲插入节点的Key,则将新节点作为左子节点。
若最后到达节点的Key值大于欲插入节点的Key,则将新节点作为右子节点。删除
首先进行查找找到待删除节点K,其后按情况而定:
若待删除节点为叶子节点,则则直接将该节点从树中删除即可。
若待删除结点只有左子树或只有右子树,则直接使用其左子节点或右子节点直接代替被删除节点即可。
若待删除节点同时具有左子树及右子树时,需要在被删除节点的右子树中找到最小节点(左子树找最大节点也可)用于代替被删除的节点。
具体实现
删除操作存在重构空间
/**
* 通用二叉查找树
* Created by Hzldex on 2018/4/17.
*/
public class BinarySearchTree<Key extends Comparable<Key>, Value> {
private BSTNode root;
public static void main(String[] args) {
BinarySearchTree<String, Integer> binarySearchTree = new BinarySearchTree<>();
binarySearchTree.insert("q", 60);
binarySearchTree.insert("a", 40);
binarySearchTree.insert("z", 20);
binarySearchTree.insert("d", 10);
binarySearchTree.insert("c", 30);
System.out.println(binarySearchTree.get("q"));
binarySearchTree.delete("q");
System.out.println(binarySearchTree.get("q"));
System.out.println(binarySearchTree.get("a"));
}
public Value get(Key key) {
BSTNode curNode = root;
while (curNode != null) {
int result = curNode.compareTo(key);
if (result > 0) { // key小于当前节点的key
curNode = curNode.left; // 进入左子树
} else if (result < 0) { //key大于当前结点的key
curNode = curNode.right; // 进入右子树
} else {
return curNode.value; //返回值
}
}
return null; //未找到
}
public void insert(Key key, Value value) {
if (root == null) { //搜索树为空只需建立根节点放入键值
root = new BSTNode(key, value);
} else {
int cmpResult;
BSTNode curParent = root;
BSTNode curNode = root;
while (curNode != null) {
cmpResult = curNode.compareTo(key);
curParent = curNode;
if(cmpResult > 0){ //若key小于节点
curNode = curNode.left; //进入左子树
}else if(cmpResult < 0){ //若key搭滴于节点
curNode = curNode.right; //进入右子树
}else{
curNode.value = value; //更新值
return; //插入完成 退出
}
}
BSTNode newNode = new BSTNode(key, value); //前面未更新值则必需要新建节点
if (curParent.compareTo(key) > 0) { //若key小于其父节点的key
curParent.left = newNode; //新节点插入左子树
} else {
curParent.right = newNode; //新节点插入右子树
}
}
}
public void delete(Key key) {
if (root.compareTo(key) == 0) { //若根节点为欲删除节点
if(root.left == null){ //若根节点无左子树
root = root.right; //将根节点替换为其右子树
}else if(root.right == null){
root = root.left;
}else{
BSTNode curParent = root; //搜索右子树中最小值
BSTNode curNode = root.right;
while(curNode.left!= null){
curParent = curNode;
curNode = curNode.left;
}
root.key = curNode.key;
root.value = curNode.value;
if(curParent == root){ //若根节点右子节点即为其右子树最小值
curParent.right = curNode.right;
}else{
curParent.left = curNode.right;
}
}
} else {
int cmpResult;
BSTNode curParent = root;
BSTNode curNode = root;
boolean isFind = false;
while (curNode != null) { //搜索找到欲删除节点
cmpResult = curNode.compareTo(key);
if(cmpResult > 0){
curParent = curNode;
curNode = curNode.left;
}else if(cmpResult < 0){
curParent = curNode;
curNode = curNode.right;
}else {
isFind = true;
}
if (isFind) break;
}
if (isFind) {
if (curNode.left == null) { // 判断是否只存在左子树或只存在右子树
if (curParent.compareTo(key) > 0) {
curParent.left = curNode.right;
} else {
curParent.right = curNode.right;
}
} else if (curNode.right == null) {
if (curParent.compareTo(key) > 0) {
curParent.left = curNode.left;
} else {
curParent.right = curNode.left;
}
} else { // 两边子树都存在的情况
BSTNode delNode = curNode;
curParent = curNode;
curNode = curNode.right;
while (curNode.left != null) {//找右子树最小值
curParent = curNode;
curNode = curNode.left;
}
delNode.key = curNode.key;//与被删除节点交换键值
delNode.value = curNode.value;
if(curParent ==delNode){//删除与被删除节点交换的节点
curParent.right = curNode.right;
}else{
curParent.left = curNode.right;
}
}
}
}
}
class BSTNode implements Comparable<BSTNode> {
BSTNode left = null, right = null;
Key key;
Value value;
BSTNode(Key key, Value value) {
this.key = key;
this.value = value;
}
@Override
public int compareTo(BSTNode o) {
return this.getKey().compareTo(o.getKey());
}
int compareTo(Key o) {
return this.getKey().compareTo(o);
}
public BSTNode getLeft() {
return left;
}
public void setLeft(BSTNode left) {
this.left = left;
}
public BSTNode getRight() {
return right;
}
public void setRight(BSTNode right) {
this.right = right;
}
public Key getKey() {
return key;
}
public void setKey(Key key) {
this.key = key;
}
public Value getValue() {
return value;
}
public void setValue(Value value) {
this.value = value;
}
}
}