二叉查找树要求,在树中任意一个节点,其左子树中的任一个节点的值要小于该节点,其右子树中的任一个一个节点的值要大于该节点。这个要求是二叉查找树能够快速进行查找、插入、删除操作的基础。
1. 二差查找树的查找操作
二差查找树查找某一个元素的过程是一个递归的过程。先将一个元素的值和根节点进行比较,如果元素的值等于根节点,则返回该节点;如果元素的值小于根节点则递归的在左子树中查找;如果元素的值大于根节点则递归的在右子树中进行查找。
class Node{
public int val;
public Node left;
public Node right;
public Node(int a){
this.val = a;
};
}
class Solution{
public Node binarySearchTree(Node root, int value){
if(root == null) return null;
while(root != null){
if(root.val == value) //如果值相同,已找到
return root;
else if(root.val < value) //如果值小于value,左递归
return binarySearchTree(root.left, value);
else //如果值大于value,右递归
return binarySearchTree(root.right, value);
}
return null; //没有找到该值时返回空
};
}
2. 二叉排序树的插入操作
二叉树的插入过程也是一个递归的过程。(基本假设是插入的元素没有重复的),先将一个元素的值和根节点进行比较,如果元素的值小于根节点则递归的在左子树中插入;如果元素的值大于根节点则递归的在右子树中进行插入。
递归写法:
class Node{
public int val;
public Node left;
public Node right;
public Node(int a){
this.val = a;
};
}
class Solution{
public Node insert(Node root, Node insertNode){
if(root == null){ //根节点为空,直接插入
root = insertNode;
}
if(insertNode.val < root.val){ //小于根节点的值,插在左子树中
root.left = insert(root.left, insertNode);
}else{ //大于根节点的值,插在右子树中
root.right = insert(root.right, insertNode)
}
return root; //返回根节点的值
};
}
非递归写法(比递归写法要复杂):
class Node{
public int val;
public Node left;
public Node right;
public Node(int a){
this.val = a;
};
}
class Solution{
public Node insert(Node root, Node insertNode){
if(root == null){
root = insertNode;
return;
}
Node p = root;
while(p != null){
if(insertNode.val < p.val){ //在左子树中寻找插入位置
if(p.left == null){ //若左子树为空,直接插入
p.left = insertNode;
return;
}else{
p = p.left; //重复上述过程
}
}else{ //在右子树中寻找合适的位置
if(p.right == null){ //若右子树为空直接插入
p.right = insertNode;
return;
}else{
p = p.right; //重复上述过程
}
}
}
return root; //返回插入节点过后的树的根节点
};
}
3. 二叉排序树的删除操作(leetcode450)
二叉树排序树的删除操作是其查、插、删三种操作中最为复杂的一种,因为其涉及到好几种情况,需要分开进行讨论:
- 如果待删除的节点没有子节点,则只需要将其父节点中,指向该节点的指针置为空
- 如果待删除的节点只有一个子节点(不管是左节点还是右节点),我们只需要更新父节点中指向该节点的指针,将其指向待删除节点的子节点即可
- 如果待删除的节点有两个子节点,我们需要找到待删除节点的右子树的最小节点然后将其删除,并替代待删除节点在树中的位置,因为该节点为右子树中的最小节点,所以必然没有左子树,故可以采用上述两种方法将其删除
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null){
return null;
}
TreeNode p = root;
TreeNode pParent = null; //记录p的父亲节点
while(p != null && p.val != key){ //找到和key值相等的节点值
pParent = p;
if(key < p.val){
p = p.left;
}else{
p = p.right;
}
}
if(p == null) return root; //没有找到key值对应的节点,说明树中不存在相应的节点值,直接返回
if(p.left != null && p.right != null){ //待删除节点p左右两个节点的值都不为空
//找到p的右子树中的最左节点(即最小节点)
TreeNode minp = p.right;
TreeNode minpParent = p; //记录下最小节点的父节点
while(minp.left != null){
minpParent = minp;
minp = minp.left;
}
//找到p的最左节点过后,将其值赋值给p
p.val = minp.val;
p = minp; //删除minp的工作留给后面的操作
pParent = minpParent;
}
TreeNode child = null; //用于记录待删除节点p的父节点的子节点
if(p.left != null) child = p.left; //待删除节点p的左子节点不为空
else if(p.right != null) child = p.right; //待删除节点p的右子节点不为空
else
child = null; //待删除节点p的左右节点均为空
if(pParent == null){ //待删除节点p就是根节点,这种情况
root = child;
}else if(pParent.left == p){
pParent.left = child;
}else{
pParent.right = child;
}
return root;
};
}