二叉查找树(也叫二叉搜索树、二叉排序树)
因为它要求左子树小于根结点,右子树大于根结点(对于每个结点均如此),这就说明了二叉树具有有序的特定。
二叉树查找的效率取决于数的高度。
定义结点类:
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
1.查找(查找元素K)
思路:
- 查找从根结点开始,如果树为空,返回NULL
- 若搜索树非空,则根结点关键字和X进行比较, 并进行不同处理:
- 若X小于根结点键值,只需在左子树中继续搜
- 如果X大于根结点的键值, 在右子树中进行继续搜索;
- 若两者比较结果是相等,搜索完成,返回结点。
//递归方式(尾递归)
public TreeNode Find(int K,TreeNode root){
if(root==null)
return null;
if(K>root.val)
return Find(K,root.right);//在右子树中继续查找
else if(K<root.val)
return Find(K,root.left);//在左子树中继续查找
else
return root;
}
//由于非递归函数的执行效率高,可将“尾递归”改为迭代函数
// public TreeNode Find(int K,TreeNode root){
// while(root!=null){
// if(K>root.val)
// root=root.right;
// else if(K<root.val)
// root=root.left;
// else
// return root;
// }
// return null;
// }
2.查找最大和最小元素
思路:最大元素一定是在树的最右分枝的端结点上
最小元素一定是在树的最左分枝的端结点上
以下查找用了两种不同的方式
public TreeNode FindMax(TreeNode root){
if(root!=null)
while(root.right!=null) //沿右分支继续查找,直到最右叶结点
root=root.right;
return root;
}
public TreeNode FindMin(TreeNode root){
if(root==null)
return null; //空的二叉搜索树,返回null
else if(root.left==null)
return root; //找到最左叶结点并返回
else
return FindMin(root.left); //沿左分支继续查找
}
3.插入
思路:关键是要找到元素应该插入的位置,可以采用与Find类似的方法
public TreeNode Insert(int K,TreeNode root){
if(root==null){ //若原树为空, 生成并返回一个结点的二叉搜索树
TreeNode node=new TreeNode(K);
node.left=null;
node.right=null;
root=node;
}
else if(K<root.val){
root.left=Insert(K,root.left);//递归插入左子树
}
else if(K>root.val){
root.right=Insert(K,root.right);//递归插入右子树
}
return root;
}
4.删除
考虑三种情况:
- 要删除的是叶结点:直接删除, 并再修改其父结点指向为null
-
要删除的结点 只有一个孩子 结点 : 将其 父结点 的 指向 要删除结点的 孩子结点
-
要删除的结点 有左、右两棵子树:
用另一结点替代被删除结点: 右子树的最小元素 或者 左子树的最大元素 (因为左子树的最大元素一定在右边没有右儿子。
右子树的最小元素一定在最左边,没有左子)
public TreeNode Delete(int K,TreeNode root){
TreeNode node;
if(root==null)
System.out.println("要删除的元素不存在");
else if(K<root.val){
root.left=Delete(K,root.left); //左子树递归删除
}
else if(K>root.val){
root.right=Delete(K,root.right); //右子树递归删除
}
else
if((root.left!=null) && (root.right!=null)){ //被删除结点有左右两个子结点
node=FindMin(root.right); //在右子树中找最小的元素填充删除结点
root.val=node.val;
root.right=Delete(root.val,root.right); //在删除结点的右子树中删除最小元素
}
else{ //被删除结点有一个或无子结点
if(root.left==null) //有右孩子或无子节点
root=root.right;
else if(root.right==null) //有左孩子或无子节点
root=root.left;
}
return root;
}