zoukankan      html  css  js  c++  java
  • 二叉查找树

    二叉查找树的特点                                                                    

    下面的图就是两棵二叉查找树,我们可以总结一下他的特点:

    (1) 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值

    (2) 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值
    (3) 它的左、右子树也分别为二叉查找树

    1

    我们中序遍历这两棵树发现一个有序的数据序列: 【1  2  3  4  5  6  7  8 】

    二叉查找树的操作                                                                    

    • 插入操作:

    现在我们要查找一个数9,如果不存在则,添加进a图。我们看看二叉查找树动态添加的过程:

    1). 数9和根节点4比较(9>4),则9放在节点4的右子树中。

    2). 接着,9和节点5比较(9>5),则9放在节点5的右子树中。

    3). 依次类推:直到9和节点8比较(9>8),则9放在节点8的右子树中,成为节点8的右孩子。

    这个过程我们能够发现,动态添加任何一个数据,都会加在原树结构的叶子节点上,而不会重新建树。 由此可见,动态查找结构确实在这方面有巨大的优势。

    • 删除操作:

    如果二叉查找树中需要删除的结点左、右子树都存在,则删除的时候需要改变一些子树结构,但所需要付出的代价很小。

    二叉查找树的效率分析                                                               

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

    总结一下:最坏情况下,构成的二叉排序树蜕变为单支树,树的深度为n,其查找时间复杂度与顺序查找一样O(N)。最好的情况是二叉排序树的形态和折半查找的判定树相同,其平均查找长度和log2(N)成正比 (O(log2(n)))。

    这说明:同样一组数据集合,不同的添加顺序会导致查找树的结构完全不一样,直接影响了查找效率。

    code                                                                                   

    /** 
     * 二叉树节点结构 
     */  
    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) */  
    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.search(new Integer(11));  
                    tree.InOrderTraverse();  
              
                    tree.delete(new Integer(11));  
            tree.InOrderTraverse();  
      
        }  
      
    }

    我是天王盖地虎的分割线                                                             

    参考:http://hxraid.iteye.com/blog/609312

  • 相关阅读:
    什么是面向对象(OOP)
    Java虚拟机(JVM)你只要看这一篇就够了!
    ES6中新增的Object.assign()方法详解
    微信小程序_专题_脚本之家(小程序全部知识点)
    微信小程序 生命周期详解
    vue 阻止事件冒泡,捕获方法
    Java必备常见单词
    JS夸页面通信极简方案&纯前端实现文件下载
    vue keep-alive以及activated,deactivated生命周期的用法
    JVM实用参数 内存调优
  • 原文地址:https://www.cnblogs.com/yydcdut/p/3919267.html
Copyright © 2011-2022 走看看