二叉搜索树
概念
二叉搜索树又叫二叉排序树
- 如果它的左子树不为空,左子树的所有节点的值均小于根节点的值
- 如果它的右子树不为空,右子树的所有节点的值均大于根节点的值
- 它的左右子树也分别是二叉搜索树
- 其中序遍历是有序的:4 6 8 10 12 16 20
兄弟们,先搞一个二叉搜索树
class BinarySortTree {
class TreeNode{
public int val;
public TreeNode left;
public TreeNode right;
}
public TreeNode root;
public TreeNode search(int key){
}
}
查找
- 若根节点不为空,key值和根节点的值比较
- key值 < 根节点,在左子树寻找
- key值 > 根节点,在右子树寻找
- 若根节点为空,说明没有所要寻找的节点
public TreeNode search(int key){
TreeNode cur = root;
while(cur != null){
if(cur.val > key){
cur = cur.left;
}else if(cur.val < key){
cur = cur.right;
}else{
break;
}
}
return cur;
}
时间复杂度分析
最好情况:二叉树为完全二叉树,时间复杂度为 log2N
最差情况:二叉树为单分支树,时间复杂度为 N
插入
- 插入一定要插入原二叉搜索树中没有的数,如果插入相同的数,不符合二叉搜索树的规定
- 插入不要想着去替换原来某个节点的位置,而是要作为叶子节点插入
如果 root 为空的话,直接插入
如果 root 不为空,cur 查找应该插入的位置,parent作为cur的父亲节点跟随。当 cur 为空时,找到插入位置,通过 parent 节点连接
public boolean insert(int key){
if(root == null){
root = new TreeNode(key);
return true;
}
TreeNode cur = root;
TreeNode parent = null;
while(cur != null){
if(key > cur.val){
parent = cur;
cur = cur.right;
}else if(key < cur.val){
parent = cur;
cur = cur.left;
}else{
return false;
}
}
if(key > parent.val){
parent.right = new TreeNode(key);
}else{
parent.left = new TreeNode(key);
}
return true;
}
删除
cur 找到所要删除的节点,parent 作为 cur 的父亲节点跟随
如何删呢?
-
cur.left == null
(1) cur 是根节点,root = cur.right
(2) cur 不是根节点
cur是parent的左孩子,parent.left = cur.right
cur是parent的右孩子,parent.right = cur.right
-
cur.right == null
(1) cur 是根节点,root = cur.left
(2) cur 不是根节点
cur是parent的左孩子,parent.left = cur.left
cur是parent的右孩子,parent.right = cur.left
cur.left != null && cur.right != null
采用替罪羊法删除
- 找可替换cur.val的值(二者选一)
(1) cur左子树的最右边是左树的最大值
或(2) cur右子树的最左边是右树的最小值 - cur.val重新赋值
- 删除“替罪羊”(所替换cur的节点), 因为此时“替罪羊” 父节点的左树或右树一定为空,可通过前面的方法删除
public boolean Remove(int key){
if(root == null){
return true;
}
TreeNode cur = root;
TreeNode parent = null;
while(cur != null){
if(key > cur.val){
parent = cur;
cur = cur.right;
}else if(key < cur.val){
parent = cur;
cur = cur.left;
}else{
RemoveNode(cur,parent);
return true;
}
}
return false;
}
public void RemoveNode(TreeNode cur, TreeNode parent) {
if (cur.left == null) {
if (cur == root) {
root = cur.right;
} else {
if (cur == parent.left) {
parent.left = cur.right;
} else {
parent.right = cur.right;
}
}
} else if (cur.right == null) {
if (cur == root) {
root = cur.left;
} else {
if (cur == parent.left) {
parent.left = cur.left;
} else {
parent.right = cur.left;
}
}
} else {
RemoveChild(cur);
}
}
//找左子树的最大值
public void RemoveChild(TreeNode cur){
TreeNode target = cur.left;
//此处targetparent一定是cur,可能target.right==null,不进入循环
TreeNode targetparent = cur;
while(target.right != null){
targetparent = target;
target = target.right;
}
cur.val = target.val;
//不要天真的认为target一定是targetparent的右孩子,可能它没进入上面的循环哦
if(target == targetparent.left){
targetparent.left = cur.left;
}else{
targetparent.right = cur.left;
}
}