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

    一、树

            1.定义:树是由n(n>=1)个有限结点组成一个具有层次关系的集合

            2.特点:1)每个结点有零个或多个子结点

                          2)没有父结点的为根结点

                          3)每一个非根结点只有一个父结点

            3.树的相关术语

                 1)结点的度:一个结点的子结点个数

                 2)叶节点:度为零的结点,也叫终端结点

                 3)结点的层次:从根结点开始为1,一次往下为2....

                 4)树的度:树中所有结点的度的最大值

                 5)树的高度:树中结点的最大层次

    二、二叉树

           1.定义:二叉树是指度不超过二的树。

           2.满二叉树:一个二叉树,每一层的结点都达到最大值,每一层节点最大值为2的k-1次方

              

             3.完全二叉树:叶结点只能出现在下层或者次下层,并且最下层的结点都集中在该层的左边

             4.二叉查找树的基本实现

                  1)插入:如果当前树中没有节点,则直接把新结点作为根节点

                                  如果树不为空,则从根节点开始:如果新结点的key小于当前节点的key,则继续找当前节点的左子节点(递归)

                                                                                        如果新结点的key大于当前节点的key,则继续找当前节点的右子节点(递归)

                  2)查找:从根节点开始

                      如果查询的key小于当前节点的key,则继续找当前节点的左子节点(递归)

                      如果查询的key大于当前节点的key,则继续找当前节点的右子节点(递归)

                      如果查询的key等于于当前节点的key,则直接返回当前的value

                  3)删除:*  先找到删除的节点

                                   *  找到要删除的节点的右子树中的最小节点minNode,记录此节点并删除

                                   *  然后让最小的节点minNode指向被删除节点的左子树和右子树,再让被删除的节点的父节点指向最小节点minNode

                   4)  输出最小键:从根节点开始一直遍历左子树,直到没有左子树时输出当前节点的key,此结点的key为最小键

                   5)输出最大键:从根节点开始一直遍历右子树,直到没有右子树时输出当前节点的key,此结点的key为最大键

                   6)先序遍历:   先访问根节点,再访问左子树,最后访问右子树。

                                         核心实现步骤:*  把根节点放入队列,队列的创建:https://www.cnblogs.com/cqyp/p/12576340.html   

                                                                  *  递归遍历左子树 

                                                                  *  递归遍历右子树

                    7)中序遍历:先访问左子树,再访问根节点,最后访问右子树。

                    8)后续遍历:先访问左子树,再访问右子树,最后访问根节点。

                    9)层序遍历:从上往下,从左往右一次遍历

                                          遍历思路:首先创建一个辅助队列,让根节点E入队,判断E是否有左右子树,有则入队,一次类推,直到找完。如下图:

                          

               10)最大深度

                       递归遍历左子树和右子树,求出左右子树的深度,然后比较,大的加一则为树的深度。

    public class BinaryTree<Key extends Comparable<Key>,Value> {
        //根节点
        private Node root;
        //树的个数
        private int N;
        public class Node{
            //存储的键
            public Key key;
            //存储的值
            public Value value;
            //记录左子节点
            public Node left;
            //记录右子节点
            public Node right;
            public Node(Key key, Value value, Node left, Node right) {
                this.key = key;
                this.value = value;
                this.left = left;
                this.right = right;
            }
        }
    
        public BinaryTree() {
            this.root=null;
            this.N=0;
        }
    
        //获取树中的个数
        public int size(){
            return N;
        }
        //向树中添加一个元素key-value
        public void put(Key key,Value value){
            root=put(root,key,value);
        }
        //向指定的树x中添加一个元素key-value,并返回添加后的树
        public Node put(Node x,Key key,Value value){
            //如果x的子树为空
            if (x==null){
                N++;
                return new Node(key, value, null, null);
            }
            //如果子树不为空
            //比较x.key和key的大小
             int cmp=key.compareTo(x.key);
            //如果大于0,则继续找x的右子树
            if(cmp>0){
               x.right=put(x.right,key,value);
            }
            //如果小于0,则继续找x的左子树
            if (cmp<0){
                x.left=put(x.left,key,value);
            }else{
                //如果相等,则将此结点的value替换
                x.value=value;
            }
            N++;
            return x;
        }
        //查询树中指定key对应的value
        public Value get(Key key){
    
            return get(root,key);
        }
        //从指定的树x中查找key对应的值
        public Value get(Node x,Key key){
            //如果x为null
            if (x==null){
                return null;
            }
            //如果x不为null
            //比较x.key和key的大小
            int cmp=key.compareTo(x.key);
            //如果大于0,则继续找x的右子树
            if(cmp>0){
                return get(x.right,key);
            }
            //如果小于0,则继续找x的左子树
            if (cmp<0){
               return get(x.left,key);
            }else{
                //如果相等,则找到
               return x.value;
            }
        }
        //删除树中key对应的value值
        public void delete(Key key){
            root=delete(root,key);
        }
        //删除指定树x中的key对应的value,并返回删除后的新树
        public Node delete(Node x,Key key){
            if (x==null){
                return null;
            }
            //如果不为null
            //比较x.key和key的大小
            int cmp=key.compareTo(x.key);
            //如果大于0,则继续找x的右子树
            if(cmp>0){
                x.right=delete(x.right,key);
            }
            //如果小于0,则继续找x的左子树
            if (cmp<0){
                x.left=delete(x.left,key);
            }else{
                N--;
                //如果相等,则找到,删除x
                //找到右子树最小的节点
     //1.如果x的右子树为空,直接返回左子树不用找最小
                if (x.right==null){
                    return x.left;
                }
                //2.如果x的左子树为空,直接返回右子树,不用找最小
                if (x.left==null){
                    return x.right;
                }
                //3.如果左右子树都不为空,找最小节点
                Node minNode=x.right;
                while (minNode.left!=null){
                   minNode=minNode.left;
                }
                //删除右子树的最小节点
    //            Node n=x.right;
                while (n.left!=null){
                   if (n.left.left==null){
                       n.left=null;
                   }else{
                       n=n.left;
                   }
                }
                //让x的左子树成为minNode的左子树
                   minNode.left=x.left;
                //让x的右子树成为minNode的右子树
                    minNode.right=x.right;
                //让x的父节点指向minNode
                  x=minNode;
            }
            return x;
        }
    
        //查找整个树中最小的键
        public Key min(){
            return min(root).key;
        }
        //在指定树x中找出最小键所在的节点
        public Node min(Node x){
            //判断x的左子节点是否为空
            if (x.left!=null){
                return min(x.left);
            }else{
                return x;
            }
        }
        //查找整个树中最大的键
        public Key max(){
            return max(root).key;
        }
        //在指定树x中找出最大键所在的节点
        public Node max(Node x){
            //判断x的右子节点是否为空
            if (x.right!=null){
                return max(x.right);
            }else{
                return x;
            }
        }
    //先序遍历
    public Queue<Key> preErgodic(){
        Queue<Key> keys=new Queue<>();
         preErgodic(root,keys);
         return keys;
    }
    public void preErgodic(Node x,Queue<Key> keys){
        //判断x是否为null
        if(x==null){
            return;
        }
        //把x节点的key放到队列中
        keys.insert(x.key);
        //把x的左子树递归放到队列中
        if(x.left!=null){
            preErgodic(x.left,keys);
        }
        //把x的右子树递归放到队列中
        if(x.right!=null){
            preErgodic(x.right,keys);
        }
    
    }
    //中序遍历
    public Queue<Key> midErgodic(){
        Queue<Key> keys=new Queue<>();
        midErgodic(root,keys);
        return keys;
    }
    public void midErgodic(Node x,Queue<Key> keys){
        if (x==null){
            return;
        }
        //递归遍历左子树并放到队列中
        if(x.left!=null){
            midErgodic(x.left,keys);
        }
        //把x放到对列中
        keys.insert(x.key);
        //把x的右子树递归放到队列中
        if(x.right!=null){
           midErgodic(x.right,keys);
        }
    }
    //后序遍历
    public Queue<Key> hErgodic(){
        Queue<Key> keys=new Queue<>();
        hErgodic(root,keys);
        return keys;
    }
    public void hErgodic(Node x,Queue<Key> keys){
        if (x==null){
            return;
        }
        //递归遍历左子树并放到队列中
        if(x.left!=null){
            hErgodic(x.left,keys);
        }
        //把x的右子树递归放到队列中
        if(x.right!=null){
            hErgodic(x.right,keys);
        }
        //把x放到对列中
        keys.insert(x.key);
    
    }
    //使用层次遍历
    public Queue<Key> layerErgodic(){
        //定义两个队列,分别存储节点和key值
        Queue<Node> nodes = new Queue<>();
        Queue<Key> keys=new Queue<>();
        //先把根节点放入队列nodes中
          nodes.insert(root);
        //当nodes队列不为null时从中弹出节点
        while (!nodes.isEmpty()){
            Node n = nodes.remove();
            keys.insert(n.key);
            //判断节点是否有左子节点,有,则进入nodes的队列
                if (n.left!=null){
                    nodes.insert(n.left);
                }
            //判断节点是否有右子节点,有,则进入keys的队列
                if (n.right!=null){
                    nodes.insert(n.right);
                }
        }
        return keys;
    }
    //最大深度
    public int maxDepth(){
        return maxDepth(root);
    }
    public int maxDepth(Node x){
        if (x==null){
            return 0;
        }
        //树的最大深度
        int max=0;
        //左子树最大深度
        int maxL=0;
        //右子树最大深度
        int maxR=0;
        //计算左子树的最大深度
        if (x.left!=null){
            maxL=maxDepth(x.left);
        }
        //计算右子树的最大深度
        if (x.right!=null){
            maxR=maxDepth(x.right);
        }
        //比较左右子树的深度大小,大的加1则为树的最大深度
        max=maxL>maxR ? maxL+1 : maxR+1;
        return max;
    }
    }

                

                     

                                

                  

  • 相关阅读:
    Android Design Support Library(三)用CoordinatorLayout实现Toolbar隐藏和折叠
    Android Design Support Library(二)用NavigationView实现抽屉菜单界面
    Android Design Support Library(一)用TabLayout实现类似网易选项卡动态滑动效果
    Android5.x Notification应用解析
    了解ViewFlipper工作机制
    OkHttp自定义重试次数
    OkHttp实现全局过期token自动刷新
    Android5.0新控件
    Android4.0新控件
    用typedef给结构体一个别名
  • 原文地址:https://www.cnblogs.com/cqyp/p/12583947.html
Copyright © 2011-2022 走看看