【Java BST树 递归和非递归实现】简单理解

BST树

一、基本概念

二叉搜索树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树

二、创建结点类和二叉树类

public class BSTree<T extends Comparable> {
    private Entry<T> root;//根节点
    /**
     *BST树的初始化
     */
    public BSTree(Entry<T> root) {
        this.root = null;
    }
    static class Entry<E extends Comparable>{
        private E value;//数据域
        private Entry<E> left;//左孩子域
        private Entry<E> right;//右孩域
        public Entry(E value, Entry<E> left, Entry<E> right) {
            this.value = value;
            this.left = left;
            this.right = right;
        }
        public Entry(E value) {
            this.value = value;
        }
        @Override
        public String toString() {
            return  value+"";
        }
    }

三、BST树的增删查,前中后层序遍历的递归和非递归等操作

BST树的递归插入:

 public void insert(T value) {
        root= insert(root, value);
    }
    public Entry insert(Entry<T> root,T value){
        if (root==null){
            root = new Entry<>(value);
        }else{
            if (root.value.compareTo(value)>0){
                 root.left=insert(root.left,value);
            }else if(root.value.compareTo(value)<0){
                root.right = insert(root.right,value);
            }
        }
        return root;
    }

BST树的非递归插入:

 public void ninsert(T value){
        if (this.root==null){//根节点为空
            this.root = new Entry<>(value);
            return;
        }
        //树不为空,从root开始找合适h插入
        Entry<T> parent = null;//记录cur的父节点
        Entry<T> cur = this.root;//初始指向根节点
        while (cur!=null){
            if (cur.value.compareTo(value)>0){
                parent = cur;
                cur = cur.left;
            }else if (cur.value.compareTo(value)<0){
                parent = cur;
                cur = cur.right;
            }else {
                return;//不插入相等元素
            }
        }
        /**
         * 退出循环后,cur==null
         * 把新插入的叶子节点写入父节点相应的地址域中
         */
        if (parent.value.compareTo(value)>0){
            parent.left = new Entry<>(value);
        }else {
            parent.right = new Entry<>(value);
        }
    }

BST树的递归删除:

  • 说明:删除有两种大的情况:一、删除的节点有一个子节点和没有子节点的;二、删除的节点左右两个子节点都在,这时候我们寻找前驱(左子树的最大值)或者后继(右子树的最小值)节点,我们把前驱或者后继的值赋给要删除的节点,再删除前驱或者后继节点,因为前驱或者后继节点要么没孩子,要么最多一个孩子,随意删除前驱或者后继节点就可以回到第一种大的情况。
 public void remove(T value){
        root = remove(root,value);
    }
    public Entry<T> remove(Entry<T> root,T value){
        if (root==null){
            return null;
        }
        if (root.value.compareTo(value)>0){
            //当前节点的值比待删节点的值大,则继续在左子树中寻找
            root.left = remove(root.left,value);
        }else if (root.value.compareTo(value)<0){
            //当前节点的值比待删节点的值小,则继续在右子树中寻找
            root.right = remove(root.right,value);
        }else {
     //已找到待删除节点root,考虑有两个孩子的情况--》寻找前驱节
            if (root.right!=null &&  root.left!=null){
                //标记待删除节点的前驱节点,(左子树最大节点)
                Entry<T> pre = root.left;
                while (pre.right != null) {
                    //使pre指向待删节点的前驱节点
                    pre = pre.right;
                }
                root.value = pre.value;
                //继续递归删除节点的前驱节点
                root.left = remove(root.left, pre.value);
            }else {
                if (root.left!=null){
                    return root.left;
                }else if (root.right!=null){
                    return root.right;
                }else {
                    return null;
                }
            }
        }
        return root;
    }

BST树非递归删除:

public void nremove(T value){
        if (this.root == null){
            return;
        }
        Entry<T> parent=null;
        Entry<T> cur = this.root;
        while (cur!=null){
            if (cur.value.compareTo(value)>0){
                parent = cur;
                cur = cur.left;
            }else if(cur.value.compareTo(value)<0){
                parent = cur;
                cur = cur.right;
            }else{
                break;//结束while循环,但是否找到,要看cur是否为空
            }
            if (cur==null){//没找到
                return;
            }
        }
   /**
   * 找到了待删value节点,cur指向待删节点
   * 先处理 待删节点有两个孩子:及就是要删除的节点有左右两个孩子
   */
        if(cur.left != null && cur.right != null){
            //找前驱节点代替待删除节点的值,然后删除前驱节点
            Entry<T> old = cur; //记录待删节点
            parent = cur;
            cur = cur.left;  //cur指向待删节点的左孩子域
            while (cur.right != null){ //找前驱结点
                parent = cur;
                cur = cur.right;
            }
            //此时cur指向前驱结点
            old.value = cur.value;
        }
        /**
         * 统一删除cur指向的节点  即:有一个节点或者没有节点的情况
         * child指向待删节点的不为空的孩子,可能为null
         */
        Entry<T> child = cur.left;
        if(child == null){
            child = cur.right;
        }
        if (parent== null){//说明是根节点
            this.root = child;
        }else if (parent.left ==cur){
            parent.left = child;
        }else {
            parent.right = child;
        }
    }

BST树的递归查找

public boolean search(T value) {
        return search(root, value);
    }
    public boolean search(Entry<T> root,T value){
        if (root==null){
            return false;
        }
        if (root.value==value){
            return true;
        }else if (root.value.compareTo(value)>0){
            return search(root.left,value);
        }else{
            return search(root.right,value);
        }
    }

BST树的非递归查找

public boolean nsearch(T value){
        Entry<T> cur = this.root;//让cue先指向根节点root
        while (cur!=null){
            if (cur.value.compareTo(value)>0){
                cur = cur.left;
            }else if(cur.value.compareTo(value)<0){
                cur = cur.right;
            }else {
                return true;//找到了
            }
        }
        return false;
    }

递归前序遍历:

   public void preOrder() {
        System.out.print("递归实现前序遍历"+" ");
        preOrder(root);
        System.out.println();
    }
    /**
     * 前序递归实现BST树的前序遍历
     */
    public void preOrder(Entry<T> root){
        if (root==null){
            return;
        }
        System.out.print(root.value+" ");
        preOrder(root.left);
        preOrder(root.right);

    }

非递归前序遍历:

 public void npreOrder(){
        Stack<Entry> stack1 = new Stack<>();
        if (root!=null){
            stack1.push(root);//把根节点入栈
            while (!stack1.empty()){
                Entry<T> node = stack1.pop();//node为根节点 底下不断地把左右节点入栈
                System.out.println(node.value);
                if (node.right!=null) stack1.push(node.right);
                if (node.left!=null) stack1.push(node.left);
            }
        }
    }

递归中序遍历:

 public void inOrder(){
        System.out.print("递归实现中序遍历:");
        inOrder(this.root);
        System.out.println();
    }

    /**
     * 以root指向的节点为起始节点进行中序遍历访问
     * @param root
     */
    private void inOrder(Entry<T> root) {
        if(root ==null){
            return;
        }
        inOrder(root.left);
        System.out.print(root.value+"  ");
        inOrder(root.right);
    }

非递归中序遍历:

 public void ninOrder(){
        Stack<Entry> stack2 = new Stack<>();
        Entry<T> node = root;
        while (node!=null || !stack2.empty()){
            //左子树一直入栈
            while (node!=null){
                stack2.push(node);
                node = node.left;
            }
            node = stack2.pop();
            System.out.println(node.value);
            node = node.right;
        }
    }

递归后序遍历:

public void postOrder(){
        System.out.print("递归实现后序遍历:");
        postOrder(this.root);
        System.out.println();
    }

    /**
     * 以root指向的节点为起始节点进行后序遍历访问
     * @param root
     */
    private void postOrder(Entry<T> root) {
        if(root ==null){
            return;
        }
        postOrder(root.left);  //L
        postOrder(root.right);  //R
        System.out.print(root.value+"  ");  //V
    }

非递归后序遍历:

 public void npostOrder(){
        Entry<T> node = root;
        Entry<T> cur =null;//记录之前走过的右节点
        Stack<Entry> stack3 = new Stack<>();
        while (node!=null || !stack3.empty()){
            while (node!=null){//一直把左节点入栈
                stack3.push(node);
                node = node.left;
            }
            node = stack3.peek();
            if (node.right==null || node.right== cur){
                System.out.print(node.value+ " ");
                node = stack3.pop();
                cur = node;
                node = null;
            }else {
                node = node.right;
            }
        }
    }

递归层序遍历:

 public int level(){
        return level(this.root);
    }
     //从root指向的节点开始,计算BST树的层数
    private int level(Entry<T> root) {
        if(root == null){
            return 0;
        }
        int left = level(root.left);
        int right = level(root.right);
        return left > right ? left+1 : right+1;
    }
     /**
     * 以root指定的节点为起始节点,进行深度遍历,打印指定的第i层的节点
     * @param root
     * @param i
     */
    private void levelOrder(Entry<T> root, int i) {
        if(root == null){
            return;
        }
        if(i == 0){
            System.out.print(root.value+"  ");
            return;
        }
        levelOrder(root.left,i-1);//i-1最终是0 就是打印当前层元素
        levelOrder(root.right,i-1);
    }
     /**
     * 递归实现BST树的层序遍历
     */
    public void levelOrder(){
        System.out.print("递归实现层序遍历:");
        int l = level();
        for(int i = 0;i<l;i++){
            levelOrder(this.root,i);
        }
        System.out.println();
    }

非递归层序遍历:

 public void nleveOrder(){
        if (root==null){
            return;
        }
        LinkedList<Entry<T>> queue = new LinkedList<>();
        queue.offer(root);//把根节点root加入队列   先进先出的原则
        while (!queue.isEmpty()){
            Entry<T> front = queue.poll();//弹出队列
            System.out.println(front.value+" ");
            if (front.left!=null){
                queue.offer(front.left);//把当前节点的左孩子加入队列
            }
            if (front.right!=null){
                queue.offer(front.left);//把当前节点的右孩子加入队列
            }
        }
    }

输出节点个数:

 public int num(){
        return num(this.root);
    }
    private int num(Entry<T> root){
        if (root==null){
            return 0;
        }else {
            return num(root.left)+num(root.right)+1;
        }
    }

判断一个树是否是二叉节点树

 * 思路:也就是看左右孩子和父节点比较,然后递归就好
 public boolean isBstree() {
        return isBstree(root);
    }
    public boolean isBstree(Entry<T> root){
       if (root==null){
           return true;
       }
       if (root.left!=null&& root.left.value.compareTo(root.value)>0){
           return false;
       }
       if (root.right!=null&&root.right.value.compareTo(root.value)<0)    {
           return false;
       }
       return isBstree(root.left)&&isBstree(root.right);
    }

中序遍历方式,求第k个节点

 public Entry ngetValue(int k){
        return ngetValue(root,5);
    }
    public Entry ngetValue(Entry<T> root,int k){
        if (root==null|| k<=0 ){
            return null;
        }
        Stack<Entry<T>> stack = new Stack<>();
        Entry<T> cur = root;
        while (cur!=null || !stack.isEmpty()) {//中序遍历的方式
            if (cur!=null){
                stack.push(cur);//把的左孩子一直入栈
                cur=cur.left;
            }else {
               cur = stack.pop();//当前节点null则弹出栈顶元素,
               //相当于按顺序输出最小
                if (--k==0){
                    return cur;
                }
                cur = cur.right;
            }
        }
        return null;
    }
while(true){
   输出("谢谢大家观看=-=");
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值