二叉树

一、树

        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;
}
}

            

                 

                            

              

原文地址:https://www.cnblogs.com/cqyp/p/12583947.html