【转】二叉查找树[BST]

目录

 

二叉查找树的特点

二叉查找树的操作

插入操作

删除操作

二叉查找树的效率分析

源码


二叉查找树的特点

1. 如果左树不为空,那么左树上所有结点的值小于根结点的值

2. 如果右树不为空,那么右树上所有节点的值大于根结点的值

3. 左树和右树均是二叉查找树,并且树上的结点的值都不相同

二叉查找树的操作

插入操作

将9插入到a图的二叉树

1> 9大于4,插入到4的右树

2> 9大于5,插入到5的右树,接着9还是大于6,将9插入到6的右树

3> 9大于7,插入到7的右树,9大于8,插入到8的右树

在此过程中,动态增加数据都会加在原有数据的叶子节点上。

删除操作

1. 如果这个结点的左树存在,右树不存在

例如

当删除的节点在左树:

例如,删除a图的节点3,只需要将结点4和结点1构成关系。表示为 parent.left = node.left

当删除的结点在右树

例如,删除c图的结点2,只需要将结点1和结点3构成关系,表为parent.right = node.rigtht;

2. 如果这个结点的右树存在,左树不存在,和上面类似。

3. 当删除的结点,左树和右树都存在。

如果删除结点5,需要一个结点能够替换5,结点4和结点6都能够满足要求。

如何找到这个结点替换删除的结点?

当前结点的左结点的走右树,一直找到最右结点  或者是 当前结点的右结点,走左树找到的最左结点。

源码中展示的删除方法,是按照 "当前结点的左结点,走右树,找到最右结点" 的方式,编码的。

二叉查找树的效率分析

很显然,在a,b两图的二叉查找树结构中查找一个数据,并不需要遍历全部的节点元素,查找效率确实提高了。但是有一个很严重的问题:我们在a图中查找8需要比较5次数据,而在B图中只需要比较3次。更为严重的是:如果按有序序列[1 2 3 4 5 6 7 8]建立一颗二叉查找树,整棵树就退化成了一个线性结构(如c输入图:单支树),此时查找8需要比较8次数据,和顺序查找没有什么不同。

最坏的情况,时间复杂度算法是O(N),最好的情况和折半查找的时间复杂度相同,为O(log2 (N))

源码

package net.lingala.zip4j.test;  
import java.util.ArrayList;

import com.sun.corba.se.impl.logging.InterceptorsSystemException;  
  
/** 
 * 二叉树节点结构 
 * @author heartraid 
 */  
class BSTNode<E extends Comparable<E>>{  
    /**结点关键字*/  
    E key=null;  
    /**直接父亲结点*/  
    BSTNode<E> parent=null;  
    /**结点左子树的根节点*/  
    BSTNode<E> lchild=null;  
    /**结点右子树的根节点*/  
    BSTNode<E> rchild=null;  
      
    BSTNode(E k){  
        this.key=k;  
    }  
  
}  
/** 
 * 二叉查找树 Binary Search Tree(BST) 
 * @author heartraid 
 * 
 */  
public class BST<E extends Comparable<E>> {  
    /**树根*/  
    private BSTNode<E> root=null;  
      
    public BST(){  
    }  
      
    /** 
     * BST 查询关键字 
     * @param key 关键字 
     * @return 查询成功/true, 查询失败/false 
     */  
    public boolean search(E key){  
        System.out.print("搜索关键字["+key+"]:");  
        if(key==null||root==null){  
            System.out.println("搜索失败");  
            return false;  
        }  
        else{  
            System.out.print("搜索路径[");  
            if(searchBST(root,key)==null){  
                return false;  
            }  
            else return true;  
                  
        }  
    }  
    /** 
     * BST插入关键字 
     * @param key 关键字 
     * @return 插入成功/true, 插入失败/false 
     */  
    public boolean insert(E key){  
        System.out.print("插入关键字["+key+"]:");  
        if(key==null) return false;  
        if(root==null){  
            System.out.println("插入到树根。");  
            root=new BSTNode<E>(key);  
            return true;  
        }  
        else{  
            System.out.print("搜索路径[");  
            return insertBST(root,key);  
        }  
    }  
      
    public boolean delete(E key){  
        System.out.print("删除关键字["+key+"]:");  
        if(key==null||root==null){  
            System.out.println("删除失败");  
            return false;  
        }  
        else{  
            System.out.print("搜索路径[");  
              
            //定位到树中待删除的结点  
            BSTNode<E> nodeDel=searchBST(root,key);  
            if(nodeDel==null){  
                return false;  
            }  
            else{  
                //nodeDel的右子树为空,则只需要重接它的左子树  
                if(nodeDel.rchild==null){  
                      
                    BSTNode<E> parent=nodeDel.parent;  
                    if(parent.lchild.key.compareTo(nodeDel.key)==0)  
                        parent.lchild=nodeDel.lchild;  
                    else  
                        parent.rchild=nodeDel.lchild;  
                }  
                //左子树为空,则重接它的右子树  
                else if(nodeDel.lchild==null){  
                    BSTNode<E> parent=nodeDel.parent;  
                    if(parent.lchild.key.compareTo(nodeDel.key)==0)  
                        parent.lchild=nodeDel.rchild;  
                    else  
                        parent.rchild=nodeDel.rchild;  
                }  
                //左右子树均不空  
                else{  
                    BSTNode<E> q=nodeDel;  
                    //先找nodeDel的左结点s  
                    BSTNode<E> s=nodeDel.lchild;  
                    //然后再向s的右尽头定位(这个结点将替代nodeDel),其中q一直定位在s的直接父亲结点  
                    while(s.rchild!=null){   
                        q=s;  
                        s=s.rchild;  
                    }  
                    //换掉nodeDel的关键字为s的关键字  
                    nodeDel.key=s.key;  
                    //重新设置s的左子树  
                    if(q!=nodeDel)   
                        q.rchild=s.lchild;  
                    else  
                        q.lchild=s.lchild;  
                }  
                return true;  
            }  
        }  
    }  
      
    /** 
     * 递归查找关键子 
     * @param node 树结点 
     * @param key 关键字 
     * @return 查找成功,返回该结点,否则返回null。 
     */  
    private BSTNode<E> searchBST(BSTNode<E> node, E key){  
        if(node==null){  
            System.out.println("].  搜索失败");  
            return null;  
        }  
        System.out.print(node.key+" —>");  
        //搜索到关键字  
        if(node.key.compareTo(key)==0){  
            System.out.println("].  搜索成功");  
            return node;  
        }  
        //在左子树搜索  
        else if(node.key.compareTo(key)>0){  
                return searchBST(node.lchild,key);  
        }  
        //在右子树搜索  
        else{  
            return searchBST(node.rchild,key);  
        }  
    }  
      
    /** 
     * 递归插入关键字 
     * @param node 树结点 
     * @param key 树关键字 
     * @return true/插入成功,false/插入失败 
     */  
    private boolean insertBST(BSTNode<E> node, E key){  
        System.out.print(node.key+" —>");  
        //在原树中找到相同的关键字,无需插入。  
        if(node.key.compareTo(key)==0)   
        {  
            System.out.println("].  搜索有相同关键字,插入失败");  
            return false;  
        }  
        else{  
            //搜索node的左子树  
            if(node.key.compareTo(key)>0){  
                //如果当前node的左子树为空,则将新结点key node插入到左孩子处  
                if(node.lchild==null) {  
                    System.out.println("].  插入到"+node.key+"的左孩子");  
                    BSTNode<E> newNode=new BSTNode<E>(key);   
                    node.lchild=newNode;  
                    newNode.parent=node;  
                    return true;  
                }  
                //如果当前node的左子树存在,则继续递归左子树  
                else return insertBST(node.lchild, key);  
            }  
            //搜索node的右子树  
            else{  
                if(node.rchild==null){  
                    System.out.println("].  插入到"+node.key+"的右孩子");  
                    BSTNode<E> newNode=new BSTNode<E>(key);   
                    node.rchild=newNode;  
                    newNode.parent=node;  
                    return true;  
                }  
                else return insertBST(node.rchild,key);  
            }  
        }  
          
    }  
    /** 
     * 得到BST根节点 
     * @return BST根节点f 
     */  
    public BSTNode<E> getRoot(){  
        return this.root;  
    }  
    /** 
     * 非递归中序遍历BST 
     */  
    public void InOrderTraverse(){  
        if(root==null)  
            return;  
        BSTNode<E> node=root;  
        ArrayList<BSTNode<E>> stack=new ArrayList<BSTNode<E>>();      
        stack.add(node);  
        while(!stack.isEmpty()){  
            while(node.lchild!=null){  
                node=node.lchild;  
                stack.add(node);  
            }  
            if(!stack.isEmpty()){  
                BSTNode<E> topNode=stack.get(stack.size()-1);  
                System.out.print(topNode.key+" ");  
                stack.remove(stack.size()-1);  
                if(topNode.rchild!=null){  
                    node=topNode.rchild;  
                    stack.add(node);  
                }  
            }  
        }  
          
          
    }  
      
    /** 
     * 测试 
     */  
    public static void main(String[] args) {  
        BST<Integer> tree=new BST<Integer>();  
        tree.insert(new Integer(100));  
        tree.insert(new Integer(52));  
        tree.insert(new Integer(166));  
        tree.insert(new Integer(74));  
        tree.insert(new Integer(11));  
        tree.insert(new Integer(13));  
        tree.insert(new Integer(66));  
        tree.insert(new Integer(121));  
        tree.insert(new Integer(10));
                tree.search(new Integer(11));  
                tree.InOrderTraverse();  
          
                tree.delete(new Integer(11));  
        tree.InOrderTraverse();  
  
    }  
  
}  

参考博客:https://blog.csdn.net/zxnsirius/article/details/52131433?utm_source=blogxgwz0 (关于删除结点的查找方法)

                  http://hxraid.iteye.com/blog/609312(二叉查找树介绍)

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值