1. 什么是二叉搜索树
- 对二叉搜索树进行中序遍历,其结果是有序的。
- 若左右子树不为空,左子树上所有节点的值小于根节点的值,右子树上所有节点的值大于根节点的值。
2. 实现二叉搜索树的 查找、插入、删除操作
2.1 先准备一个二叉搜索树的节点
class BinaryNode{
int key;
int value;
BinaryNode left;
BinaryNode right;
public BinaryNode(int key, int value) {
this.key = key;
this.value = value;
}
}
2.2 准备根节点
BinaryNode root=null;
2.3 查找,get()方法的实现
思路
- 若key小于根节点的值,在根节点的左子树中找
- 若key大于根节点的值,在根节点的右子树中找
代码
public Integer get(int key){
BinaryNode cur=root;
while(cur!=null){
if(key<cur.key){
cur=cur.left;
}else if(key>cur.key){
cur=cur.right;
}else{
return cur.value;
}
}
return null;
}
2.4 增加键值对,put()方法的实现
思路
- 定义两个引用,parent和cur
- 如果key已经存在,那么只需要修改key的value即可
- 如果key不存在,找到待插元素的合适位置,进行插入即可
代码
public void put(int key,int value){
BinaryNode parent=null;
BinaryNode cur=root;
while(cur!=null){
if(key<cur.key){
parent=cur;
cur=cur.left;
}else if(key>cur.key){
parent=cur;
cur=cur.right;
}else{
cur.value=value;
return;
}
}
//找到插入的位置了,此时cur指向空
//具体要插入到parent的左子树还是右子树,只需要判断key大于还是小于parent的key
BinaryNode newNode=new BinaryNode(key,value);
if(key<parent.key){
parent.left=newNode;
}else{
parent.right=newNode;
}
}
2.5 删除键值对,remove()方法实现
思路
首先根据 key 找到待删节点 cur,记录其位置和其父节点 parent 的位置
分为三种情况:
- ① cur的左子树为空
cur是根节点;cur是parent的左子树;cur是parent的右子树
- ② cur的右子树为空
cur是根节点;cur是parent的左子树;cur是parent的右子树
- ③ cur的左右子树均不为空
从待删节点的右子树中找到一个key最小的节点goat,采用移形换影,将goat的信息赋给cur,此时也就相当于cur不存在了
由于goat是cur右子树的最小值,所以是一路向左跑,即最终goat一定是没有左子树的。
删掉goat即可,所以将其称为替罪羊节点
public void remove(int key){
//首先找到要删除键值对的位置
BinaryNode parent=null;
BinaryNode cur=root;
while(cur!=null){
if(key<cur.key){
parent=cur;
cur=cur.left;
}else if(key>cur.key){
parent=cur;
cur=cur.right;
}else{
//找到要删除的节点了
removeNode(parent,cur);
}
}
}
public void removeNode(BinaryNode parent,BinaryNode cur) {
if(cur.left==null){
if(root==cur){
root=cur.right;
}else if(parent.left==cur){
parent.left=cur.right;
}else{
parent.right=cur.right;
}
}else if(cur.right==null){
if(root==cur){
root=cur.left;
}else if(parent.left==cur){
parent.left=cur.left;
}else{
parent.right=cur.left;
}
}else{
BinaryNode parentGoat=cur;
BinaryNode goat=cur.right;
//从待删节点的右子树中找到key最小的节点goat
while(goat.left!=null){
parentGoat=goat;
goat=goat.left;
}
//将goat的信息赋给待删节点cur,相当于cur被删除了,此时只需要删除goat就行
cur.key=goat.key;
cur.value=goat.value;
//由于goat是一路向左找的,所以goat一定没有左子树
if(parentGoat.left==goat){
parentGoat.left=goat.right;
}else{
parentGoat.right=goat.right;
}
}
}