zoukankan      html  css  js  c++  java
  • 算法-树(1)—BST(二叉搜索树)

    本文基于BST结构主要实现查找,删除功能
    此种数据结构较为简单,主要分析添加查找删除功能
    后附完整代码

    1.BST定义:
    1).每个结点均有键值对,其中键值实现排序;
    2).每个结点的都大于它的左结点,小于它的右结点。
    2. 主要实现(递归)

    结点内部类Node:
    `private class Node
    {
        private Key key;
        private Value value;
        private Node left ,right;
        private int N;
    
        public Node(Key key,Value value,int N)
        {
            this.key = key;
            this.value = value;
            this.N = N;
        }
    }
    `
    

    1).添加put
    思想:键值不能相同的原则,所以先递归查找是否存在这样的键值,若存在,则更新value值,否则添加相应的键值对到对应的位置。
    实现:

        private Node put(Node x,Key key,Value value)
        {
            if(x == null) 
                return new Node(key,value,1);
            int cmp = key.compareTo(x.key);
            if (cmp<0)
                x.left = put(x.left,key,value);
            else if (cmp>0)
                x.right = put(x.right,key,value);
            else 
                x.value = value;
            x.N = size(x.left)+size(x.right)+1;
            return x;
        }

    2).删除deleteMin,delete
    1.删除最小值:
    查找最小值:递归查找左子树,若左子树为null,则递归右子树,查找Node.left==null的结点,次结点即为树的最小值。
    删除最小值:删除最小值后,最小结点的右子树,接到最小值父结点的左子树中。

        private Node deleteMin(Node x)
        {
            if(x.left == null)
                //此处返回需要删除的最小结点的右子树(这样才能保证后面结点不丢失).
                return x.right;
            //递归到最小结点时,返回了x.right,此处令最小结点的父结点的左子树等于返回的x.right.
            //而需要删除的结点,被当成垃圾系统回收.
            x.left = deleteMin(x.left);
            //更新计数器.
            x.N = size(x.left)+size(x.right)+1;
                return x;
        }

    2.删除任意结点(传入键值):
    思想:首先肯定先递归查找的删除的键值(假设x结点),删除结点x时,我们需要使用到deleteMin,找到以x为父结点的子树的,用于替换x位置的结点

        private Node delete(Node x,Key key)
        {
            if(x == null)
                return null;
            int cmp = key.compareTo(x.key);
            if(cmp < 0)
                x.left = delete(x.left,key);
            else if(cmp > 0)
                x.right = delete(x.right,key);
            else
            {
                //此处x为需要删除的结点.判断x是否为单结点,若为单结点,返回x.left或者x.right即能删除x结点.
                if(x.right == null)
                    return x.left;
                if(x.left == null)
                    return x.right;
                //若不为单结点.创建t结点,保存x的左右连接状态,再查找x右子树的最小结点(此结点即为新的取代x结点的结点).
                Node tmp = x;
                x = min(tmp.right);
                x.right = deleteMin(tmp.right);
                x.left = tmp.left;
            }
            x.N = size(x.left)+size(x.right)+1;
            return x;
        }

    3.性能分析:
    二分查找法(有序数组):
    最坏:查找—lgN。插入—N
    平均:查找—lgN。插入—N/2
    二叉查找树:
    最坏:查找—N。插入—N
    平均:查找—1.39lgN。插入—1.39lgN
    BST的性能与树的高度成正比。
    3. 完整代码

    package search;
    /**
      * @author : 罗正 
      * @date time:2016年9月7日 下午9:47:08 
    **/
    public class BSTsearch <Key extends Comparable<Key> ,Value>{
    
        private Node root;
        /**
         * 内部类:树结点——Node
         * @param args
         */
        private class Node
        {
            private Key key;
            private Value value;
            private Node left ,right;
            private int N;
    
            public Node(Key key,Value value,int N)
            {
                this.key = key;
                this.value = value;
                this.N = N;
            }
        }
    
        public int size(){
            return size(root);
        }
    
        private int size(Node x)
        {
            if (x == null) 
                return 0;
            else 
                return x.N;
        }
    
        /**
         * funtion:根据传入的key值,递归查找二叉树,无则返回null.
         * @param key
         * @return
         */
    
        public Value get (Key key)
        {
            return get(root,key);
        }
    
        private Value get(Node x,Key key)
        {
            if(x == null)
                return null;
            int cmp = key.compareTo(x.key);
            if (cmp<0)
                return get(x.left,key);
            else if (cmp>0)
                return get(x.right,key);
            else
                return x.value;
        }
    
        /**
         * 查找key值,找到则更新,没有则添加.
         * @param key
         * @param value
         */
        public void put(Key key,Value value)
        {
    
            root = put(root,key,value);
        }
    
        /**
         * 没有则插入root的子树当中
         * @param x
         * @param key
         * @param value
         * @return
         */
        private Node put(Node x,Key key,Value value)
        {
            if(x == null) 
                return new Node(key,value,1);
            int cmp = key.compareTo(x.key);
            if (cmp<0)
                x.left = put(x.left,key,value);
            else if (cmp>0)
                x.right = put(x.right,key,value);
            else 
                x.value = value;
            x.N = size(x.left)+size(x.right)+1;
            return x;
        }
    
        public Key min()
        {
            return min(root).key;
        }
        private Node min(Node x)
        {
            if(x.left == null)
                return x;
            return min(x.left);
        }
    
        /**
         * 返回小于等于key的最大键.
         * @param key
         * @return
         */
        public Key floor(Key key)
        {
            Node x = floor(root,key);
            if(x == null)
                return null;
            return x.key;
        }
        private Node floor(Node x,Key key)
        {
            if( x == null)
                return x;
            int cmp = key.compareTo(x.key);
            if(cmp == 0)
                return x;
            if(cmp<0)
                return floor(x.left,key);
            Node t = floor(x.right,key);
            if(t != null)
                return t;
            else
                return x;
    
        }
    
        /**
         * 根据传入的int k值,查找在树中的key值,并返回
         * @param k
         * @return
         */
        public Key select(int k)
        {
            return select(root,k).key;
        }
        private Node select(Node x,int k)
        {
            if(x == null)
                return null;
            int num = size(x.left);
            if(num > k)
                return select(x.left,k);
            else if(num < k)
                return select(x.right,k-num-1);
            else 
                return x;
        }
    
        /**
         * 根据传入的key,查找在树中的rank.
         * @param key
         * @return
         */
        public int rank(Key key)
        {
            return rank(root,key);
        }
    
        private int rank(Node x,Key key)
        {
            if( x == null)
                return 0;
            int cmp = key.compareTo(x.key);
            if(cmp > 0)
                //此处不要忘了加上1+size(x.left)
                return 1+size(x.left)+rank(x.right,key);
            if(cmp < 0)
                return rank(x.left,key);
            else
                return size(x.left);
        }
    
        /**
         * 以下为较难实现的BST删除操作.
         * 实现步骤如下:
         * 1.保存要删除的结点链接.(如删除A,保存t = B.left).
         * 2.A指向X = min(A.left).<这个结点就是删A后,取代A位置的结点!>
         * 3.X取代A的操作,以及X位置抽取后,树变动的操作
         * 
         * deletemMin().
         * delete().
         */
        public void deleteMin()
        {
            root = deleteMin(root);
        }
        private Node deleteMin(Node x)
        {
            if(x.left == null)
                return x.right;
            x.left = deleteMin(x.left);
            x.N = size(x.left)+size(x.right)+1;
            return x;
        }
    
        /**
         * 删除给定的键值对key.
         * @param key
         */
        public void delete(Key key)
        {
            root = delete(root,key);
        }
    
        /**
         * 递归删除key,
         * 返回Node值,便于实现递归而不丢失链接.
         * @param x
         * @param key
         * @return
         */
        private Node delete(Node x,Key key)
        {
            if(x == null)
                return null;
            int cmp = key.compareTo(x.key);
            if(cmp < 0)
                x.left = delete(x.left,key);
            else if(cmp > 0)
                x.right = delete(x.right,key);
            else
            {
                //此处x为需要删除的结点.判断x是否为单结点,若为单结点,返回x.left或者x.right即能删除x结点.
                if(x.right == null)
                    return x.left;
                if(x.left == null)
                    return x.right;
                //若不为单结点.创建t结点,保存x的左右连接状态,再查找x右子树的最小结点(此结点即为新的取代x结点的结点).
                Node tmp = x;
                x = min(tmp.right);
                x.right = deleteMin(tmp.right);
                x.left = tmp.left;
            }
            x.N = size(x.left)+size(x.right)+1;
            return x;
        }
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
            BSTsearch bst = new BSTsearch<>();
            bst.put("B", "b");
            bst.put("A", "a");
            bst.put("D", "d");
            bst.put("W", "w");
            bst.put("X", "x");
            bst.put("Z", "z");
            System.out.println(bst.select(0));
            System.out.println("rank A:"+bst.rank("A"));
            System.out.println("bst size :"+bst.size());
            System.out.println("floor:"+bst.floor("Z"));
            System.out.println("min :"+bst.min());
            bst.deleteMin();
            System.out.println("min (mid):"+bst.min());
            bst.delete("B");
            System.out.println("min :"+bst.min());
            System.out.println("bst size:"+bst.size());
        }
    
    }
    

    算法第四版—二叉查找树

  • 相关阅读:
    Navicat 总是断开连接
    MySQL 重连机制
    优化 一
    python之 paramiko模块 连接服务器
    变量值的修改
    Python使用APScheduler实现定时任务
    Linux命令 清空文件
    输入法 | 输入法如何打出直角引号
    Java | Java字节码
    英语 | 图片学习单词
  • 原文地址:https://www.cnblogs.com/l0zh/p/13739770.html
Copyright © 2011-2022 走看看