手写JAVA代码实现二分搜索树

一、二分搜索树简介

二分搜索树(英语:Binary Search Tree),也称为 二叉查找树 、二叉搜索树 、有序二叉树或排序二叉树。满足以下几个条件:

  • 若它的左子树不为空,左子树上所有节点的值都小于它的根节点。
  • 若它的右子树不为空,右子树上所有的节点的值都大于它的根节点。
    它的左、右子树也都是二分搜索树。
    如下图所示:
    在这里插入图片描述

二、具体实现

如上图所示:二分搜索树是由一个个节点组成,
节点由俩部分组成:

  • 1.元素
  • 2.指向左右子节点的指针
    根据上面节点的组成,定义节点如下:
private class Node{
        public E e;
        public Node left,right;
        public  Node(E e){
            this.e = e;
            left = null;
            right =null;
        }
    }

由于二分搜索树是由根节点进行排序,则需要记录根节点
则创建一个二分搜索树类BST:

//为了使元素支持各种类型,采用泛型
//因为需要排序,而元素E还应支持比较大小,则继承Comparable
public class BST<E extends Comparable<E>> {
	private Node root;
    private int size;
    public BST(){
        root = null;
        size = 0;
    }

1.添加元素

a.分析业务逻辑

在进行添加元素时,跟当前元素进行比较,
若小,则看其左节点是否为null,为null直接赋值到左节点上,否则继续递归。
若大,则看其右节点是否为null,为null直接赋值到右节点上,否则继续递归。

b.代码实现

方式一

//向二分搜索树中添加某一元素
    public void add(E e){
        if(root ==null){
            root = new Node(e);
            size++;
        }else{
            add(root,e);
        }
    }
    private void add(Node node,E e){
      if(e.equals(node.e)){
          return;
      } else if(e.compareTo(node.e)<0 && node.left == null){
          node.left = new Node(e);
          size++;
          return;
      }else if(e.compareTo(node.e)>0 && node.right == null){
          node.right = new Node(e);
          size ++;
          return;
      }
      if(e.compareTo(node.e)<0){
          add(node.left,e);
      }else if(e.compareTo(node.e)>0){
          add(node.right,e);
      }

    }

方式二

	//向二分搜索树中添加某一元素
    public void add(E e){
    	root = add(root,e);
    }
	private Node add(Node node,E e){
        if(node == null){
            size ++;
            return new Node(e);
        }
        if(e.compareTo(node.e)<0){
            node.left = add(node.left,e);
        }else if(e.compareTo(node.e)>0){
            node.right = add(node.right,e);
        }
        return node;
    }

2.遍历二分搜索树

方式一:深度优先遍历

//二分搜索树前序遍历
    public void preOrder(){
        preOrder(root);
    }

    private void preOrder(Node node){
        if(node ==null){
            return;
        }
        System.out.println(node.e);
        preOrder(node.left);
        preOrder(node.right);
    }

方式二:广度优先遍历(由上到下一层层遍历)

a.分析业务逻辑

1.当程序走到根节点时,节点中的元素可以拿到
2.当遍历第二层时,需要通过上一步节点中的左右节点获取元素
3.当遍历第三层时,还是需要通过上一步节点中的左右节点获取元素

由此看出,再执行第一步时,需要将根节点的左右节点放在一个地方进行存储,再执行第二步时,取出上一步放的节点node1,从而获取元素,并将node1节点的左右节点存储方便下一步进行取用。
根据以上特性,可以将左右节点存放在队列
逻辑如下:读取root节点,取出root节点的元素,将root节点的左节点、右节点分别放入队列中,遍历第二层时,先取出左节点,取出节点元素,将此节点的左右节点分别放入队列中;再取出root的右节点执行上面操作…当队列中没有节点时,也就遍历结束。

b.代码实现
//广度优先遍历
    public void levelOrder(){
        Queue<Node> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()){
            Node cur = queue.remove();
            System.out.println(cur.e);
            if(cur.left != null){
                queue.add(cur.left);
            }
            if(cur.right != null){
                queue.add(cur.right);
            }
        }
    }

3.删除元素

a.分析业务逻辑

1.删除的节点没有左右节点时,直接删除
2.删除的节点node有左节点或者右节点时,将node的左节点挂在node父节点上、或将node的右节点挂在node父节点上
3.删除的节点左右节点都存在时,这时就不能直接将该节点的左右节点挂在父节点上。需要从删除的节点node下,找出最小元素所在的节点放在node节点位置处。

b.代码实现
	//删除二分搜索树中元素e
    public void remove(E e){
        root = remove(root,e);
    }

    private Node remove(Node node,E e){
    	//需要删除的元素未找到
        if(node == null){
            return null;
        }
        //需要删除的元素比当前节点上元素小,则需要去其左节点进行删除
        if(e.compareTo(node.e)<0){
            node.left = remove(node.left,e);
            return node;
         //需要删除的元素比当前节点上元素大,则需要去其右节点进行删除
        }else if(e.compareTo(node.e)>0){
            node.right = remove(node.right,e);
            return node;
         //当前节点就是需要删除的
        }else {
        	//如果只存在右节点,则将右节点返回
            if(node.left == null){
                Node nodeRight = node.right;
                node.right = null;
                size --;
                return nodeRight;
            }
            //如果只存在左节点,则将左节点返回
            if(node.right == null){
                Node nodeLeft = node.left;
                node.left = null;
                size--;
                return nodeLeft;
            }
			//找到当前节点的右节点下最小元素所在节点
            Node middleNode = findMinimum(node.right);
            //将需要删除的node节点的左节点挂载
            middleNode.left = node.left;
            middleNode.right = removeMin(node.right);
            node.right = node.left = null;
            return middleNode;
        }
    }
    //查询node节点下最小的元素,返回最小元素所在的节点
    private Node findMinimum(Node node){
        if(node.left == null){
            return node;
        }
        return findMinimum(node.left);
    }
    //删除最小元素所在节点,返回其右节点
    private Node removeMin(Node node){
        if(node.left == null){
            Node nodeRight = node.right;
            node.right = null;
            size --;
            return nodeRight;
        }
        node.left =  removeMin(node.left);
        return node;
    }
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值