数据结构-BST树(镜像&前序&中序&后序&重构)

package com.AdvancedDataStructure.BSTTree;

import java.util.LinkedList;
import java.util.Stack;

/**
 * @Created with IntelliJ IDEA
 * @Description:  BST树代码演示
 * @Package: com.AdvancedDataStructure.BSTTree
 * @author: FLy-Fly-Zhang
 * @Date: 2019/6/26
 * @Time: 19:09
 */
class BSTNode <T extends Comparable<T>>{
    private T data;
    private BSTNode<T> left;
    private BSTNode<T> right;
    public BSTNode(T data,BSTNode<T> left,BSTNode<T> right){
        this.data=data;
        this.left=left;
        this.right=right;
    }
    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public BSTNode<T> getLeft() {
        return left;
    }


    public void setLeft(BSTNode left) {
        this.left = left;
    }

    public BSTNode<T> getRight() {
        return right;
    }

    public void setRight(BSTNode right) {
        this.right = right;
    }
}
class BST <T extends Comparable<T>>{
    private BSTNode<T>  root; //根节点
    /*
     * @Description : BST
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/26 19:12
     */
    public BST(){
        this.root=null;
    }
    /*
     * @Description : 添加节点,前驱实现
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/26 20:20
     */
    public void non_insert(T data){
        //判断如果root是否null,如果为null,直接生成根节点
        if(this.root==null){
            this.root=new BSTNode<T>(data,null,null);
            return;
        }
        //
        BSTNode tmp=root;
        //如果root不为空,从根节点进行搜索。
        while(true){
            if(tmp.getData().compareTo(data)>0){
                if(tmp.getLeft()==null){
                    //生成新结点,把节点的地址,写入父节点相应的地址域
                    tmp.setLeft(new BSTNode<T>(data,null,null));
                    return;
                }
               tmp=tmp.getLeft();
            }else if(tmp.getData().compareTo(data)<0){
                if(tmp.getRight()==null){
                    tmp.setRight(new BSTNode<T>(data,null,null));
                    return;
                }
                tmp=tmp.getRight();
            }else{
                return;
            }
        }
    }
    public void insert(T data){
        if(this.root==null){
            this.root=new BSTNode<>(data,null,null);
            return;
        }
        insert(this.root,data);
    }
    /*
     * @Description : 结点插入,递归实现
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 16:10
     */
    private BSTNode<T> insert(BSTNode<T> root, T data) {
        if(root==null)
            return new BSTNode<T>(data,null,null);
        //左子树递归
        if(root.getData().compareTo(data)>0){
            //在非插入的父节点,没有必要在进行结点赋值
            //但是这样的写,又多了一次判断,指令也更多,
            //没有必要这样写。
            if(root.getLeft()!=null){
                insert(root.getLeft(),data);
            }else{
                root.setLeft(insert(root.getLeft(),data));
            }
        //右子树递归
        }else if(root.getData().compareTo(data)<0){
            root.setRight(insert(root.getRight(),data));
        }
        return root;
    }

    //删除有两个孩子的节点:应该找删除节点的前驱结点或者后继结点,
    // 用前驱或者后继把当前删除结点的值覆盖点,然后直接删除前驱或者后继结点
    //前驱结点:待删除结点左子树中,值最大的结点
    //后继结点:待删除结点右子树中,值最小的结点
    //删除有一个孩子的节点
    //删除没有孩子的节点
    /*
     * @Description : 删除结点,前驱实现
     * @param data
     * @return :   void
     * @exception :
     * @date :   2019/6/29 14:49
     */
    public void non_remove(T data){
        //先搜索BST树,找到待删除结点
        BSTNode<T> cur=this.root;
        BSTNode<T> pre=null;
        while(cur!=null){
            if(cur.getData().compareTo(data)>0){
                pre=cur;
                cur=cur.getLeft();
            }else if(cur.getData().compareTo(data)<0){
                pre=cur;
                cur=cur.getRight();
            }else{
                break;
            }
        }
        if(cur==null)
            return;
        //判断删除结点是否有两个结点,如果有则用前驱的值代替,没有直接删除前驱
        //注意,在用前驱结点替换掉要删除结点后,前驱前驱结点是需要被删除的,
        //此时删除前驱结点就变成了有一个孩子的结点或者没有孩子的结点
        if(cur.getLeft()!=null&&cur.getRight()!=null){
            BSTNode<T> old=cur;
            pre=cur;
            //左子树的最大结点
            cur=cur.getLeft();
            while(cur.getRight()!=null){
                pre=cur;
                cur=cur.getLeft();
            }
            //前驱结点的值替代待删结点的值。
            old.setData(cur.getData());
        }
        //删除有一个孩子的结点,或者没有孩子的结点
        BSTNode child=cur.getLeft();
        if(child==null)
            child=cur.getRight();
        //恰好删除的可能是根结点,那么直接进行else里面的操作会报空指针异常。
        if(pre==null){
            this.root=child;
        }else{
            if(pre.getLeft()==cur){
                pre.setLeft(child);
            }else{
                pre.setRight(child);
            }
        }
    }
    /*
     * @Description : 删除结点,后继结点实现
     * @param data
     * @return :   void
     * @exception :
     * @date :   2019/6/29 14:50
     */
    public void non_remove1(T data){
        BSTNode<T> pre=null;
        BSTNode<T> cur=this.root;
        while(cur!=null){
            if(cur.getData().compareTo(data)<0){
                pre=cur;
                cur=cur.getRight();
            }else if(cur.getData().compareTo(data)>0){
                pre=cur;
                cur=cur.getLeft();
            }else{
                break;
            }
        }
        //未找到结点
        if(cur==null)
            return;
        if(cur.getLeft()!=null&&cur.getRight()!=null){
            BSTNode<T> old=cur;
            pre=cur;
            //右子树的最小结点
            cur=cur.getRight();
            while(cur.getLeft()!=null){
                pre=cur;
                cur=cur.getLeft();
            }
            old.setData(cur.getData());
        }
        BSTNode<T> child=cur.getLeft();
        if(child==null)
            child=cur.getRight();
        //要删除结点为根结点,
        if(pre==null){
            this.root=child;
        }else{
            if(pre.getLeft()==cur){
                pre.setLeft(child);
            }else{
                pre.setRight(child);
            }
        }

    }
    public void remove(T val){
        //防止删除的是头结点
        this.root=remove(this.root,val);
    }
    /*
     * @Description :
     *  递归删除BST的结点和循环删除的最大区别是,
     *  循环我们需要始终保证前驱结点的链接,目的在于
     *  删除一个孩子或者没有孩子的结点时,可以让父结点和孩子连接起来
     *  递归的话,我们并没有保存其前驱结点,但是我们在递归的时候,
     *  实际上每一次递归都是重新连接当前的左右结点
     *  root.setLeft(remove(root.getLeft(),pre.getData()));
     *  这一步以及下面的两步实际上就是将左右孩子和父结点连接起来。
     * @param null
     * @return :
     * @exception :
     * @date :   2019/7/3 15:36
     */
    private BSTNode<T> remove(BSTNode<T> root, T val) {
        if(root==null)
            return null;
        //每一步只关注自己应该连接哪些连接
        //要删除的结点在左边
        if(root.getData().compareTo(val)>0){
            root.setLeft(remove(root.getLeft(),val));
        //要删除的结点在右边
        }else if(root.getData().compareTo(val)<0){
            root.setRight(remove(root.getRight(),val));
            //找到要删除的结点
        }else{
            //两个结点的情况的删除
            if(root.getLeft()!=null&&root.getRight()!=null){
                 BSTNode<T> pre=root.getLeft();
                 //找前驱
                 while(pre.getRight()!=null){
                     pre=pre.getRight();
                 }
                 //将前驱结点赋值给要删除结点
                 root.setData(pre.getData());
                 //删除前驱结点==》等效于只有一个孩子的删除或者没有孩子的删除
                 root.setLeft(remove(root.getLeft(),pre.getData()));
            //只有一个孩子或者没有孩子的删除
            }else if(root.getLeft()!=null){
                return root.getLeft();
            }else if(root.getRight()!=null){
                return root.getRight();
            }else{
                return null;
            }
        }
        return root;
    }
    private BSTNode<T> remove1(BSTNode<T> root,T data){
        if(root==null)
            return null;
        if(root.getData().compareTo(data)>0){
            root.setLeft(remove1(root.getLeft(),data));
        }else if(root.getData().compareTo(data)<0){
            root.setRight(remove1(root.getRight(),data));
        }else{
            if(root.getLeft()!=null&&root.getRight()!=null){
                BSTNode<T> cur=root.getRight();
                while(cur.getLeft()!=null){
                    cur=cur.getLeft();
                }
                root.setData(cur.getData());
                root.setRight(remove1(root.getRight(),cur.getData()));
            }else if(root.getLeft()!=null){
                return root.getLeft();
            }else if(root.getRight()!=null){
                return root.getRight();
            }else{
                return null;
            }
        }
        return null;
    }

    /*
     * @Description : 查询二叉树中是否存在某个元素
     * @param data
     * @return :   boolean
     * @exception :
     * @date :   2019/6/29 14:52
     */
    public BSTNode<T> non_query(T data){

        BSTNode cur=this.root;
        while(cur!=null){
            if(cur.getData().compareTo(data)>0){
                cur=cur.getLeft();
            }else if(cur.getData().compareTo(data)<0){
                cur=cur.getRight();
            }else{
                return cur;
            }
        }
        return null;
    }
    /*
     * @Description : 递归实现查找元素
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 16:19
     */
    public boolean query(T data){
        return query(this.root,data);
    }
    private boolean query(BSTNode<T> root, T data) {
        if(root==null)
            return false;
        if(root.getData().compareTo(data)>0){
            return query(root.getLeft(),data);
        }else if(root.getData().compareTo(data)<0){
            return query(root.getRight(),data);
        }else{
            return true;
        }

    }

    /*
     * @Description : 前序遍历BST树API接口
     *  VLR:
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 9:55
     */
    public void preOrder(){
        System.out.print("前序遍历: ");
        preOrder(this.root);
    }
    /*
     * @Description : 前序遍历递归调用
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 9:57
     */
    private void preOrder(BSTNode<T> root){
        if(root!=null){
            System.out.print(root.getData()+" ");
            preOrder(root.getLeft());
            preOrder(root.getRight());
        }
    }
    /*
     * @Description :前序遍历,非递归实现
     * 使用栈作为存储结构
     * @param null
     * @return :
     * @exception :
     * @date :   2019/7/1 13:29
     */
    public void non_preOrder(){
        if(this.root==null)
            return;
        BSTNode<T> tmp=this.root;
        Stack<BSTNode<T>> stack=new Stack();
        stack.push(tmp);
        while(!stack.empty()){
            //VLR因为是先取出L在取出,R
            //根据stack的数据结构需要先存R在取L才能保证先遍历L
            tmp=stack.pop();//V
            System.out.print(tmp.getData());
            if(tmp.getRight()!=null)
                stack.push(tmp.getRight());
            if(tmp.getLeft()!=null)
                stack.push(tmp.getLeft());
        }
        System.out.println();
    }
    /*
     * @Description : 中序
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 10:04
     */
    public void inOder(){
        System.out.print("中序遍历:");
        inOder(this.root);
    }
    private void inOder(BSTNode<T>  root){
         if(root!=null){
             inOder(root.getLeft()); //L
             System.out.print(root.getData()+" "); //V
             inOder(root.getRight()); //R
         }

    }
    public void non_inOrder(){
        if(this.root==null)
            return;
        BSTNode<T> tmp=this.root;
        //linkedlist的pop和push操作都是采用头插头删除
        //这样其实也是一个类似与栈的数据结构
        LinkedList<BSTNode<T>> stack=new LinkedList<>();
        //LVR
        while(!stack.isEmpty()|| tmp!=null){
            //当前结点不为空,一直寻找左孩子
            if(tmp!=null){
                stack.push(tmp);
                tmp=tmp.getLeft();
            }else{
                //为空时,找到V,然后在将R压入栈里面
                tmp=stack.pop();
                System.out.print(tmp.getData());
                tmp=tmp.getRight(); //R可能也有自己的左孩子
            }
        }
        System.out.println();
    }
    /*
     * @Description : 后序遍历
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 10:20
     */
    public void postOrder(){
        System.out.print("后序遍历: ");
        postOrder(this.root);
    }
    private void postOrder(BSTNode<T> root){
        if(root!=null){
            postOrder(root.getLeft());//L
            postOrder(root.getRight());//R
            System.out.print(root.getData()+" "); //V
        }
    }
    public void non_postOrder(){
        if(this.root==null)
            return;
        Stack<BSTNode<T>> stack=new Stack();
        Stack<BSTNode<T>> stack1=new Stack();
        BSTNode<T> tmp=this.root;
        stack.push(tmp);
        //对于后序遍历LRV,采用的两个栈的模式,将V
        //先压入stack1栈中,然后再将左右孩子压入一个stack中,
        //在下一次循环的时候,右孩子先出栈,然后再将其压入
        //stack1。
        //这样相当于实现了VRL的入栈顺序,根据栈的数据结构,
        //那么出栈的顺序为LRV。
        while(!stack.empty()){
            tmp=stack.pop();
            stack1.push(tmp);
            if(tmp.getLeft()!=null){
                stack.push(tmp.getLeft());
            }
            if(tmp.getRight()!=null){
                stack.push(tmp.getRight());
            }
        }
        while(!stack1.empty()){
            System.out.print(stack1.pop().getData());
        }
        System.out.println();
    }
    /*
     * @Description : 返回BST树中所有节点个数的API
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 10:08
     */
    public int number(){
         return number(this.root);
    }
    private int number(BSTNode<T> root){
        if(root!=null){
            return number(root.getLeft())+number(root.getRight())+1;
        }
        return 0;
    }
    /*
     * @Description : 树的高度
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 10:19
     */
    public int level(){
        return level(this.root);
    }
    private int level(BSTNode<T> root){
        int l=0;
        int r=0;
        if(root!=null){
            l=level(root.getLeft())+1;
            r=level(root.getRight())+1;
        }
        return l>r? l:r;
    }
    /*
     * @Description : 层序遍历BST
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 10:24
     */
    public void levelOrder(){
        int level=level();
        //有多少层遍历多少次
        for (int i = 0; i <level ; i++) {
            levelOrder(this.root,i);
        }
    }
    /*
     * @Description : 层序遍历递归实现
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 10:33
     */
    private void levelOrder(BSTNode<T> root,int i){
         if(root!=null){
             //到达要遍历的层。
             if(i==0){
                 System.out.print(root.getData()+" ");
                 return; //这里return需要+,要不然会继续深度遍历。
             }
             //当前层数不是需要遍历的层数,继续进行深入
             levelOrder(root.getLeft(),i-1);
             levelOrder(root.getRight(),i-1);
         }
    }
    /*
     * @Description : BST镜像的递归实现
     *  总结下来就是左右子树互换
     * @param root
     * @return :   void
     * @exception :
     * @date :   2019/6/29 14:58
     */
    public void mirror(BSTNode<T> root){
        if(root==null){
            return ;
        }
        //左右子树互换
        BSTNode<T> tmp=root.getLeft();
        root.setLeft(root.getRight());
        root.setRight(tmp);
        //继续将子树的左右子树进行互换
        mirror(root.getLeft());
        mirror(root.getRight());
    }
    /*
     * @Description : 区间元素的查找
     * 使用的是中序遍历的方式因为中序遍历是有序的
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 11:28
     */
    public void printAreaDatas(T begin,T end){
            printAreaDatas(begin,end,this.root);
    }
    private void printAreaDatas(T begin,T end,BSTNode<T> root){
        if(root==null){
            return;
        }
        //当前节点的值小于begin,不用再递归左子树
        if(root.getData().compareTo(begin)>0){
            printAreaDatas(begin,end,root.getLeft()); //L
        }
        if(root.getData().compareTo(begin)>=0&& root.getData().compareTo(end)<=0){
            System.out.print(root.getData()); //V
        }
        //当前节点的值小于end,才有必须要进行右子树递归
        if(root.getData().compareTo(end)<0){
            printAreaDatas(begin,end,root.getRight()); //R
        }
    }
    /*
     * @Description : 判断二叉树是不是BST树
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 11:34
     */
    public boolean isBSTree(){
        T value=null;
        return isBSTree(this.root,value);
    }
    /*
    * @Description :
    * 判断一个数是不是BST树,我们采用中序遍历的方式
    * 每次保留前一个V,当其满足前面小于后面的要求时,
    * 那么其就是BST树
    * @param root
    * @param value
    * @return :   boolean
    * @exception :
    * @date :   2019/6/29 12:03
    */
    private boolean isBSTree(BSTNode<T> root,T value){
        if(root==null){
            return true;
        }
        T val=root.getData();
        //左子树不满足BST树性质,直接返回,不用递归
        //这里的value不用更新,因为此value只是传进来上一个value
        //当在下面和val比较后再将val进行更新
        //在最深度的左边遍历中,root==null,直接返回true。
        if(!isBSTree(root.getLeft(),value))
            return false;
        //当前节点与中序遍历的前一个节点进行比较
        //value!=null,主要是为了过滤root==null是返回的value==null的值
        if(value!=null&&value.compareTo(val)>0)
            return false;
        //当前结点满足中序,将当前结点值传入与下一个V进行比较。
        return isBSTree(root.getRight(),val);

    }
    /*
     * @Description : 返回两个节点的最近祖先节点。
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 12:10
     */
    public T  getLCA(T data1,T data2){
          return getLCA(this.root,data1,data2);
    }
    private T getLCA(BSTNode<T> root,T data1,T data2){
        if(root==null){
            return null;
        }
        //两个节点均在当前节点的左子树
        if(root.getData().compareTo(data1)> 0&& root.getData().compareTo(data2)>0){
            return getLCA(root.getLeft(),data1,data2);
            //两个节点均在当前节点的右子树
        }else if(root.getData().compareTo(data1)<0&&root.getData().compareTo(data2)<0){
            return getLCA(root.getRight(),data1,data2);
            //一个在左子树一个在右子树,那么当前节点恰好是其最近的公共祖先节点
        }else{
            return root.getData();
        }
    }
    /*
     * @Description : 返回中序遍历的倒数第k个节点。
     * 中序遍历是LVR,其结果为升序
     * 那么我们采用RVL.那么其结果为降序。
     * 那么第k个元素,就是其倒数第k个结点。
     * @param null
     * @return :
     * @exception :
     * @date :   2019/6/29 12:30
     */
    private int k;
    public T getOrderValue(int k){
        this.k=k;
        // return getOrderValue(this.root);
        return getOrderValue1( this.root, k);
    }
    private T getOrderValue(BSTNode<T> root) {
        if(root==null){
            return null;
        }
        T val=getOrderValue(root.getRight());
        if(val!=null){
            return val;
        }
        if(k--==1) {
            return root.getData();
        }
        return getOrderValue(root.getLeft());
    }
    private int i=1;
    private T getOrderValue1(BSTNode<T> root,int k){
        if(root==null){
            return null;
        }
        T val=getOrderValue1(root.getLeft(),k);
        if(val!=null)
            return val;
        if(i++==k){
            return root.getData();
        }
        return getOrderValue1(root.getRight(),k);
    }
    public void rebuild(T[] pre,T[] in){
        this.root=rebuild(pre,0,pre.length-1,in,0,in.length-1);
    }
    private BSTNode<T> rebuild(T[] pre, int i, int j, T[] in, int m, int n) {
        if(i>j||m>n)
            return null;
        //前序数组当前第一个结点为当前树的root结点。
        BSTNode<T> tmp=new BSTNode<>(pre[i],null,null);
        //中序遍历,找到当前子树根结点
        for(int k=m;k<=n;k++){
            if(in[k].compareTo(pre[i])==0){
                //当在中序遍历中找到当前根节点时,中序m--k之间为其左子树中序,k--n为其右子树中序
                //对于左子树来说,前序的(k-m)个结点为其左子树前序结点,剩余的为其右子树结点
                tmp.setLeft(rebuild(pre,i+1,i+(k-m),in,m,k-1));
                tmp.setRight(rebuild(pre,i+(k-m)+1,j,in,k+1,n));
                return tmp;
            }
        }
        return tmp; //走到这,说明中序没有找到。
    }
    /*
     * @Description : 判断是不是子树
     * 首先在主树中看能不能找到子树的根结点
     * 在找到的情况下判断每个结点是否相等。
     * @param null
     * @return :
     * @exception :
     * @date :   2019/7/3 18:54
     */
    public boolean isChildTree(BST<T> tree){
        //找到当前树中与之匹配的根结点
        BSTNode<T> tmp=non_query(tree.root.getData());
        if(tmp!=null){ //找到进行比较
            return isChildTree(tmp,tree.root);
        }
        return false; //没找到
    }

    private boolean isChildTree(BSTNode<T> father, BSTNode<T> child) {
        if(father==null&&child==null)
            return true;
        if(father==null)
            return false;
        if(child==null)
            return true;
        if(father.getData().compareTo(child.getData())==0){
            return isChildTree( father.getLeft(),  child.getLeft())&&isChildTree( father.getRight(),  child.getRight());
        }
        return false;

    }

}
public class BSTDemo {
    public static void main(String[] args) {
        BST<Integer> bst = new BST();
        int[] ar = {58,23,82,12,35,69,87,18,47,74,95};
        for (int val : ar) {
            bst.non_insert(val);
        }
        System.out.println(bst.level());
        System.out.println(bst.number());
        bst.preOrder();
        bst.inOder();
        bst.postOrder();
        bst.levelOrder();
        System.out.println();
        System.out.println(bst.getOrderValue(3));


    }
}

猜你喜欢

转载自blog.csdn.net/Fly_Fly_Zhang/article/details/94594010