java模拟二叉树

1 篇文章 0 订阅

java模拟二叉树

首先二叉树应该由0至多个节点组成,节点用于存放自身的数据和连接其他叶子节点。

首先我们先创建BST二叉树类,它应是由0至多个节点组成,size属性表明二叉树内实际元素个数。因为我们二叉树是需要根据值进行排序的,所以需要实现Comparable接口。 特别提醒此处的extends是实现接口的作用。泛型E用于表明该节点处的值。

部分代码如下:

public class BST<E extends Comparable<E>> {


    private Node root;
    private int size;

    public BST() {
        root = null;
        size = 0;
    }

其次我们再创建节点类,只用BST类使用,所以我们选择匿名内部类的实现方式。节点中存放的是自身的数据和其下的左右子树。

部分代码:

    private class Node {
        E e;
        Node left;
        Node right;

        public Node(E e) {
            this.e = e;
            this.left = null;
            this.right = null;
        }
    }

然后我们可以写几个基础方法像外部提供信息。

	//	返回二叉树内的实际元素个数
	public int size() {
        return size;
    }
	// 判断二叉树是否为空
    public boolean isEmpty() {
        return size == 0;
    }

下面我们来实现添加二叉树内的元素,不能插入重复值。

	// 添加元素
	 public void add(E e) {
        root = add(root, e);
    }

	//  这里我们使用递归的写法
    private Node add(Node node, E e) {
       // 收敛条件 递归到最后 新建节点返回作为上一节点的左子树或右子树
        if (node == null) {
        	// 元素个数+1
            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;
    }

接下来我们再实现查找元素的方法,如果有返回true ,否则返回false

   public boolean contains(E e) {
        return contains(root, e);
    }
	
	// 按照我们现在的搜索算法 如果是满二叉树那么 算法复杂度为O(logn)
	// 如果十分极端的情况下,一个二叉树只有左子树或者只有右子树
	// 那么这个二叉树将变成链式结构,算法复杂度为O(n)
   private boolean contains(Node node, E e) {
        // 收敛条件 如果找不到该值 返回false
        if (node == null)
            return false;
        // 收敛 如果二值相等 那么返回true
        if (e.compareTo(node.e) == 0)
            return true;
        // 如果改值小于此处节点值 递归值该左节点下
        else if (e.compareTo(node.e) < 0)
            return contains(node.left, e);
         // 如果改值大于此处节点值 递归值该右节点下
        else
            return contains(node.right, e);

    }

接下来我们再去完成删除元素的方法。
我画个图给大家整理一下思路。
前驱节点是它左子树的最右下节点。
后继节点是它右子树的最左下节点。
在这里插入图片描述

在此之前我们先完成两个辅助方法的编写。一是查找该节点下的最小值。二是删除该节点下的最小值。

   // 找到该节点下的最小元素值
   private Node minmum(Node node) {
   		// 收敛条件 如果改节点无左子树了,则其为最小子节点 返回
        if (node.left == null)
            return node;
		// 否则 继续往其左子树下递归
        return minmum(node.left);
    }

    private Node removeMin(Node node) {
        Node root = node;
        // 如果该节点无左子树那么直接删除该节点返回其右子树节点
        if (node.left == null) {
            return node.right;
        }
        // 迭代其下的所有左子树 找到最小的左子树删除
        while (node.left != null) {
            if (node.left.left == null) {
                //将该节点下左子树下的的右子树移至其父节点位置
                node.left = node.left.right;
                size--;
                break;
            }
            // 迭代
            node.left = node.left.left;
        }
        return root;
    }

好了有了这两个辅助方法,我们可以正式的编写二叉树的删除方法了。

    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 rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }
	        // 右子树为空的情况下 直接返回其左子树
            if (node.right == null) {
                Node leftNode = node.left;
                node.left = null;
                size--;
                return leftNode;
            }
            //找到后继
            Node successor = minmum(node.right);
            // 后继的右节点 就是删除完node右子树节点最小左子树后的节点
            successor.right = removeMin(node.right);
            // 后继的左节点就是 原先node处的左子树
            successor.left = node.left;
            node.left = null;
            //返回之前的递归调用
            return successor;
        }
    }

如此一来,我们便完成了所有二叉树的添加,删除和查找。

前中后遍历我们下次再继续讲。

完整代码

public class BST<E extends Comparable<E>> {


    private Node root;
    private int size;

    public BST() {
        root = null;
        size = 0;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public void add(E e) {
        root = add(root, e);
    }

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

    public boolean contains(E e) {
        return contains(root, e);
    }

    private boolean contains(Node node, E e) {
        if (node == null)
            return false;
        if (e.compareTo(node.e) == 0)
            return true;
        else if (e.compareTo(node.e) < 0)
            return contains(node.left, e);
        else
            return contains(node.right, e);

    }

    public void preOder() {
        preOder(root);
    }

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

    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 rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }

            if (node.right == null) {
                Node leftNode = node.left;
                node.left = null;
                size--;
                return leftNode;
            }
            //找到后继
            Node successor = minmum(node.right);
            successor.right = removeMin(node.right);
            successor.left = node.left;
            node.left = null;
            return successor;
        }
    }

    private Node removeMin(Node node) {
        Node root = node;
        // 如果该节点无左子树那么直接删除该节点返回其右子树节点
        if (node.left == null) {
            return node.right;
        }
        // 迭代其下的所有左子树 找到最小的左子树删除
        while (node.left != null) {
            if (node.left.left == null) {
                //将该节点下左子树下的的右子树移至其父节点位置
                node.left = node.left.right;
                size--;
                break;
            }
            // 迭代
            node.left = node.left.left;
        }
        return root;
    }

    private Node minmum(Node node) {
        if (node.left == null)
            return node;

        return minmum(node.left);
    }


    private class Node {
        E e;
        Node left;
        Node right;

        public Node(E e) {
            this.e = e;
            this.left = null;
            this.right = null;
        }
    }
  
}


之前的代码元素不支持重复,最近有人问我重复元素怎么添加,所以修改了部分代码。以下是修改之后的完整代码

public class BST<E extends Comparable<E>> {


    private Node root;
    private int size;

    public BST() {
        root = null;
        size = 0;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public void add(E e) {
        root = add(root, e);
    }

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

    public boolean contains(E e) {
        return contains(root, e);
    }

		// 搜索元素 返回list
    public List<Node> selectNodes(E e) {

        List<Node> nodes = new ArrayList<>();

        Node node = root;
        while (node != null) {
            if (e.compareTo(node.e) < 0) {
                node = node.left;
            } else if (e.compareTo(node.e) > 0) {
                node = node.right;
            } else {
                nodes.add(node);
                node = node.right;
            }
        }

        return nodes;
    }


    private boolean contains(Node node, E e) {
        if (node == null)
            return false;
        if (e.compareTo(node.e) == 0)
            return true;
        else if (e.compareTo(node.e) < 0)
            return contains(node.left, e);
        else
            return contains(node.right, e);
    }

    public void preOder() {
        preOder(root);
    }

    // 中序遍历 就是从小到大输出排序 用于测试
    public void minOder() {
        minOder(root);
    }


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

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

    public void remove(E e) {
        List<Node> nodes = selectNodes(e);
        // 多删几次而已。。。偷闲
        for (Node node : nodes) {
            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 rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }

            if (node.right == null) {
                Node leftNode = node.left;
                node.left = null;
                size--;
                return leftNode;
            }
            //找到后继
            Node successor = minmum(node.right);
            successor.right = removeMin(node.right);
            successor.left = node.left;
            node.left = null;
            return successor;
        }
    }

    private Node removeMin(Node node) {
        Node root = node;
        // 如果该节点无左子树那么直接删除该节点返回其右子树节点
        if (node.left == null) {
            return node.right;
        }
        // 迭代其下的所有左子树 找到最小的左子树删除
        while (node.left != null) {
            if (node.left.left == null) {
                //将该节点下左子树下的的右子树移至其父节点位置
                node.left = node.left.right;
                size--;
                break;
            }
            // 迭代
            node.left = node.left.left;
        }
        return root;
    }

    private Node minmum(Node node) {
        if (node.left == null)
            return node;

        return minmum(node.left);
    }


    private class Node {
        E e;
        Node left;
        Node right;

        public Node(E e) {
            this.e = e;
            this.left = null;
            this.right = null;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "e=" + e +
                    '}';
        }
    }


}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值