以下内容测试使用的搜索树为:
一.搜索树的查找
首先我们要知道搜索树的性质:根节点的左子树所有节点的值一定小于根节点,根节点的右子树的所有节点的值一定大于根节点的值,根据此性质,我们要寻找某一值就简单了比如我们要寻找一个值 val,我们用 cur = root让 cur.val 的值来跟 val 比较,如果 cur.val < val,就证明我们应该让cur = cur.right,反之让 cur = cur.left,此时循环下去会有两个结果,要么 cur.val = val,此时我们就找到了要找的值,另一个结果是没有找到 val,此时cur == null,也就代表我们没有找到。在写代码时还要注意,如果 给的是空树,我们也直接返回 false 就可以。
public static void great(TreeNode root){
TreeNode a = new TreeNode(30);
TreeNode b = new TreeNode(20);
TreeNode c = new TreeNode(50);
TreeNode d = new TreeNode(40);
TreeNode e = new TreeNode(60);
TreeNode f = new TreeNode(45);
TreeNode g = new TreeNode(55);
root.left = b;
root.right = c;
c.left = d;
c.right = e;
d.right = f;
e.right = g;
}
static class TreeNode{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int val){
this.val = val;
}
}
//搜索某一值在哪个节点上
public static boolean search(TreeNode root,int val){
TreeNode cur = root;
if (root == null){
return false;
}
while (cur != null){
if (cur.val < val){
cur = cur.right;
}
if (cur.val > val){
cur = cur.left;
}
if (cur.val == val){
return true;
}
}
return false;
}
测试:
public class test {
public static void main(String[] args) {
SearchTree.TreeNode root = new SearchTree.TreeNode(30);
Boolean tem = null;
SearchTree.great(root);
tem = SearchTree.search(root,50);
System.out.println(tem);
}
}
运行结果:
二.搜索树的插入
搜索树的插入我们需要用到两个变量 cur 和 par ;cur 初始化为 root(根节点),通过跟搜索树的查找一样的方式,我们让 cur.val 不断地跟 val 比较,来找到适合插入 val 的位置,找到位置之后,我们会发现我们如果想把 cal 插入到 cur 的位置是无法实现的,因为我们不知道前一个节点,所以我们就需要用到 par ,每次 cur 移动之前我们都用 par 记录下当前 cur 的节点之后让 cur 来移动,这之后 cur 找到合适位置之后,我们就可以通过 par 来将 val 插入到 cur 的位置,但由于我们不知道 cur 是往左走了还是往右走了,此时我们就需要将 par.val 的值跟 val 的值比较,如果 par.val 的值要比 val 的值要大,那么 cur 就是往左走了,反之则是往右走了,此时我们就可以把 vla 插入到搜索树中(如果 val 的值已经存在于搜索树中,是无法插入的,此时我们返回的 boolean 是 false)。
//搜索树的插入
public boolean insert(TreeNode root,int val){
if (root == null){
root = new TreeNode(val);
return true;
}
TreeNode cur = root;
TreeNode par = null;
while (cur != null){
if (cur.val < val){
par = cur;
cur = cur.right;
}
if (cur.val > val){
par = cur;
cur = cur.left;
}
if (cur.val == val){
return false;
}
}
if (par.val > val){
par.left.val = val;
}
if (par.val < val){
par.right.val = val;
}
return true;
}
三.搜索树的删除
搜索树的删除分为三大种情况,cur.left == null,cur.right == null 以及 cur.left != null && cur.right == null 的三种情况,比如我们要删除节点 cur,cur 节点又有cur ==root 和 cur != root,两种情况,我们挨个分析,当 cur.left == null 的时候,先说 cur 为根节点的时候,因为 cur 是根节点,所有并没有其他节点指向 cur,所以我们可以直接让 cur = cur.right,这样就可以删除 cur 节点,当 cur 节点不为根节点的时候,我们需要让指向 cur 节点的节点(这里称为par节点)也就是 par节点指向 cur 节点的 right 节点,这里分为两种情况:cur 节点在 par 节点的左边或者 cur 节点在 par 节点的右边,当 cur 节点在 par 节点的左边的时候,我们需要让 par.left = cur.right,反之让par.right= cur.right。根据以上方法,当 cur 节点的右节点为空的时候,采用相同的思路就可以。
最后是 cur 节点的左右节点都不为空的情况,我们需要用到两个新的变量 target 和 targetpar,先说思路,我们这里采用替换删除法,也就是找个节点的值来替换掉要删除的节点,然后删除掉新的节点的值就可以。要找个新节点来替换掉 cur 节点的值的要求要符合搜索树的性质(根节点的值大于所有左子树节点的值,根节点的值小于所有右子树节点的值),我们有两个方向可以去寻找新的节点的值,第一个是在 cur 节点的左子树寻找左子树的最大值的节点来替代,第二种是在 cur 节点的右子树寻找右子树最小值的节点来替代。这样找到的节点就可以满足我们搜索树的性质了。
寻找节点的方法(以第二种为例):我们让 target =cur 节点,target 节点不断地 = target.left,直到 target.left == null,此时找到的节点就是我们用来替换 cur 的节点,直接让 cur.val = target.val就可以,这样就可以完成值的替换。
我们要进行的下一步操作是删除 target 节点,此时我们要用到targertpa节点,targertpar 节点是在targer 节点移动时,记录下 targer 节点(targertpar = target),也就是说 targertpar节点是 targert节点的上一个节点,这边分两种情况:第一种是 targertpar.left == targert,此时 targert 节点是没有左节点的,所以我们让 targertpar.left = targert.right 就可以,第二种情况是 targertpar.right == targert 节点,此时我们需要让 targertpar.right = targert.right 节点。到了此时,我们就完成了搜素树的节点删除操作。
//搜素树的删除
public static void remove(TreeNode root, TreeNode parent, TreeNode cur){
//当 cur 节点的左节点为空
if (cur.left == null){
if (cur == root){
root = root.right;
}
if (cur == parent.left){
parent.left = cur.right;
}
if (cur == parent.right){
parent.right = cur.right;
}
}
//当 cur 节点的右节点为空
if (cur.right == null){
if (cur == root){
cur = cur.left;
}
if (cur == parent.left){
parent.left = cur.left;
}
if (cur == parent.right){
parent.right = cur.left;
}
}else {
//当 cur 节点两边不为空
TreeNode target = cur.right;
TreeNode targetParent = cur;
while (target.left != null){
targetParent = parent;
target = target.left;
}
cur.val = target.val;
if (targetParent.left == parent){
targetParent.left = parent.right;
}
if (targetParent.right == targetParent){
targetParent.right = parent.right;
}
}
}