数据结构 之 二叉树功能的代码实现

二叉搜索树

  • 无序树的查找,就是整个遍历,所以时间复杂度为O(N)。
  • 为了优化无序查找的时间复杂度,我们把树进行排序,这里引入了二叉搜索树。

    二叉搜索树是一个有序树,即左节点的值比根节点的值小,右节点的值比根节点的值大

  • 二叉搜索树的时间复杂度为O(logN)

    因为每次查找都会减少剩余数据一半的数据量

搜索

  • 整体思路

    1、定义一个TreeNode,其中包含该节点的value值,以及左右孩子
    2、如果 搜索值 = 节点值,返回;
    3、如果 搜索值 > 节点值,在右孩子处查找
    4、如果 搜索值 < 节点值,在左孩子处查找

  • 代码截图(完整代码在【代码实现】模块可以查看到)
    在这里插入图片描述
    在这里插入图片描述

删除节点

  • 思路:
    • 1、找到目标节点

    • 2、找到目标节点的父节点

    • 3、删除的节点是叶子节点

      (1)父节点为空
      (2)父节点不为空:判断目标节点是左孩子还是右孩子,
      (3)找到目标节点,将赋值为null
      在这里插入图片描述

    • 4、删除的节点有两个子树

      (1)找到目标节点左子树的最大值(或 右子树的最小值)
      (2)需要先删除最大值,然后将最大值赋值给目标节点赋值:如果不先删除,赋值成功后会有两个最大值
      在这里插入图片描述

    • 5、删除的节点只有一个子树

      (1)删除的节点是根节点,且只有左子树:直接将左子树赋给根节点
      (2)删除的节点是根节点,且只有右子树:直接将右子树赋给根节点
      (3)删除的节点为父节点的左子树,且节点只有左子树:节点的左子树赋值给父节点的左子树
      (4)删除的节点为父节点的左子树,且节点只有右子树:节点的右子树赋值给父节点的左子树
      (5)删除的节点为父节点的右子树,且节点只有左子树:节点的左子树赋值给父节点的右子树
      (6)删除的节点为父节点的右子树,且节点只有右子树:节点的右子树赋值给父节点的右子树
      在这里插入图片描述
      在这里插入图片描述

二叉树的遍历

  • 前序遍历:根 - 左 - 右,借助递归方法传入左节点或右节点

  • 中序遍历:左 - 根 - 右,借助递归方法传入左节点或右节点

  • 后续遍历:左 - 右 - 根,借助递归方法传入左节点或右节点

  • 层序(广度)遍历:借助队列,根节点出队时,将左右孩子入队的思想

在这里插入图片描述

代码实现

  • TreeNode类
    public class TreeNode {
        private int value; 		// 节点的值
        private TreeNode left;	// 左节点
        private TreeNode right; // 右节点
        // 构造函数
        public TreeNode(int value) {this.value = value;}
        // get 和 set 方法
        public int getValue() {return value;}
        public void setValue(int value) {this.value = value;}
        public TreeNode getLeft() {return left;}
        public void setLeft(TreeNode left) {this.left = left;}
        public TreeNode getRight() {return right;}
        public void setRight(TreeNode right) {this.right = right;}
    }
    
  • BinaryTree类:搜索、删除、遍历于一体
    import java.util.LinkedList;
    import java.util.Queue;
    
    public class BinaryTree {
    
        public TreeNode root;       // 定义一个二叉树的根节点
        /***
         * 普通插入法:
         * 1、根节点为空,直接赋值,直接返回;
         * 2、根节点不为空,开始遍历,
         */
        public void insert(int value){
            // 创建一个新的节点
            TreeNode newNode = new TreeNode(value);
            // 先来判断root节点是不是为空
            if(root==null){     // root为空,直接赋值,直接返回
                root = newNode;
                return;
            }
            // root节点不为空,所以需要开始遍历了
            TreeNode index = root;
            // 定义个父节点
            TreeNode pre = null;
            while(true){
                pre = index;
                if(value>=index.getValue()){    //  如果插入的值比较大,就一直往右走
                    index = index.getRight();
                    if(index == null){
                        pre.setRight(newNode);
                        return;
                    }
                }else {
                    index = index.getLeft();   //  如果插入的值比较大,就一直往右走
                    if(index==null){
                        pre.setLeft(newNode);
                        return;
                    }
                }
            }
        }
    
        // 【递归插入法】
        public void insertDG(TreeNode node,int value){
            TreeNode newNode = new TreeNode(value);
            if(root==null){
                root = newNode;
                return;
            }
            // root不为空
            if(node.getValue()>=value){
                // 判断当前节点的左节点是否为空
                if(node.getLeft()==null){
                    node.setLeft(newNode);
                    return;
                }
                // 左节点不为空,需要递归
                insertDG(node.getLeft(),value);
            }else{      // 存入的值大,需要往右边遍历
                // 先判断当前节点的右节点是否为空
                if(node.getRight()==null){
                    node.setRight(newNode);
                    return;
                }
                // 右节点不为空,需要递归
                insertDG(node.getRight(),value);
            }
        }
        /***
         * 【前序遍历:父 - 左 - 右】
         * @param node
         */
        public void beforOrder(TreeNode node){
            // 需要遍历的节点为空,直接返回
            if(node==null){return;}
            // 节点不为空
            System.out.print(node.getValue()+" ");
            // 递归遍历左子树
            beforOrder(node.getLeft());
            // 递归遍历右子树
            beforOrder(node.getRight());
        }
        /***
         * 【中序遍历:左 -  父 - 右】
         * @param node
         */
        public void inOrder(TreeNode node){
            // 递归出口
            if(node == null){return;}
            // 递归遍历左子树
            inOrder(node.getLeft());
            System.out.print(node.getValue()+" ");
            // 递归遍历右子树
            inOrder(node.getRight());
        }
    
        /***
         * 【后序遍历:左 - 右 -父】
         * @param node
         */
        public void afterOrder(TreeNode node){
            // 递归出口
            if(node==null){return;}
            // 递归遍历左子树
            afterOrder(node.getLeft());
            // 递归遍历右子树
            afterOrder(node.getRight());
            System.out.print(node.getValue()+" ");
        }
    
        /***
         * 广度遍历
         * @param node
         */
        public void deepOrder(TreeNode node){
            Queue<TreeNode>  queue = new LinkedList<>();    // 定义一个队列
            TreeNode index = null;  // 记录从队列中取出的节点
            if(node==null){
                System.out.println("树为空");
                return;
            }else{
                queue.offer(node);
                while(!queue.isEmpty()){    // 队列不为空时操作
                    index = queue.poll();
                    System.out.print(index.getValue()+" ");
                    if(index.getLeft()!=null){       // 左节点不为空,入队
                        queue.offer(index.getLeft());
                    }
                    if(index.getRight()!=null){      // 右节点不为空,入队
                        queue.offer(index.getRight());
                    }
                }
            }
        }
    
        /***
         * [普通方法:查找]
         * @param value:需要查找的值
         * @return:TreeNode
         */
        public TreeNode search(int value){
            // 定义一个遍历的节点
            TreeNode index = root;
            // 开始遍历,节点不为空
            while(index!=null){
                if(index.getValue()==value){
                    return index;
                }else if(index.getValue()>value){
                    index = index.getLeft();
                }else{
                    index = index.getRight();
                }
            }
            return null;
        }
    
        /***
         * [递归方法:查找]
         * @param node:查找的节点
         * @param value:查找的值
         * @return:TreeNode节点
         */
        public TreeNode searchDG(TreeNode node,int value){
            // 递归出口
            if(node==null){return  null; }
            // 开始递归
            if(node.getValue() == value){
                return node;
            }else if(node.getValue()>value){
                return  searchDG(node.getLeft(),value);
            }else {
                return searchDG(node.getLeft(),value);
            }
        }
    
    
        // 查找父节点
        public TreeNode searchParent(TreeNode node,int value){
            // 递归出口
            if(node==null){
                return null;
            }
            // 判断当前节点是不是目标节点的父节点
            // 是父节点的条件:左节点不为空且等于value  或者 右节点不为空,且等于value
            if((node.getLeft()!=null && node.getLeft().getValue()==value) || (node.getRight()!=null && node.getRight().getValue()==value)){
                return node;
            }else if(node.getValue()>value){
                // 当前
                return searchParent(node.getLeft(),value);
            }else{
                return searchParent(node.getRight(),value);
            }
        }
    
        // 删除节点
        public void delete(int value){
            // 如果跟节点为空,直接返回
            if(root == null){
                System.out.println("空树,无法删除");
                return ;
            }
            // 根节点不为空:
            // 找到目标节点
            TreeNode target = search(value);
            if(target==null){
                System.out.println("不存在的节点");
                return;
            }
            // 找到父节点
            TreeNode parent = searchParent(root,value);
    
            if(target.getLeft()==null && target.getRight()==null){
                // 删除叶子节点
    
                // 1、如果父节点为空,那么这个节点就是根节点
                if(parent == null){
                    root = null;
                    return;
                }
                // 2、父节点不为空,那么需要判断目标节点是左节点 还是 右节点了
    
                if(parent.getLeft()!=null && parent.getLeft()==target){      // (1)目标节点是父节点的左孩子
                    parent.setLeft(null);
                }else{       // (2)目标节点是父节点的右孩子
                    parent.setRight(null);
                }
            }else if(target.getLeft()!=null && target.getLeft()!=null){
                // 删除有两个子树的节点
    
                // 找到目标节点左子树的最大值
                TreeNode index = target.getLeft();
                while(index.getRight()!=null){
                    index = index.getRight();
                }
                int Max = index.getValue();
                // 要先删除后赋值
                delete(Max);
                target.setValue(Max);
    
            }else{
                // 删除只有一个子树的节点
    
                //没有父节点,即是根节点
                if(parent==null){
                    // 判断是左子树还是右子树
                    if(target.getLeft()!=null){
                        // 根节点,只有左子树
                        root = target.getLeft();
                    }else{
                        // 根节点,只有右子树
                        root = target.getRight();
                    }
                    return;
                }
                // 有父节点,即非根节点
                if(parent.getLeft()!=null && parent.getLeft().getValue()==value){
                    // 删除节点是父节点的左子树。判断要删除的节点的子节点是左子树还是右子树
    
                    if(target.getLeft()!=null){
                        // 要删除的节点的唯一节点只有左子树
                        parent.setLeft(target.getLeft());
                    }else{
                        // 要删除的节点的唯一节点只有右子树
                        parent.setLeft(target.getRight());
                    }
                }else{
                    // 删除节点是父节点的右子树
    
                    if(target.getLeft()!=null){
                        // 要删除的节点的唯一节点只有左子树
                        parent.setRight(target.getLeft());
                    }else{
                        // 要删除的节点的唯一节点只有右子树
                        parent.setRight(target.getRight());
                    }
                }
            }
        }
    
    }
    
  • Test类
    public class Test {
        public static void main(String[] args) {
            BinaryTree forest = new BinaryTree();
            forest.insert(10);
            forest.insertDG(forest.root,15);
            forest.insert(7);
            forest.insertDG(forest.root,3);
            forest.insert(20);
            forest.insertDG(forest.root,12);
            forest.insert(9);
            forest.insertDG(forest.root,25);
            forest.insert(17);
            forest.insertDG(forest.root,2);
            forest.delete(10);
            System.out.println("前序遍历:");
            forest.beforOrder(forest.root);
            System.out.println("\n广度遍历:");
            forest.deepOrder(forest.root);
        }
    }
    
  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值