二叉搜索树(Java) -- 左小右大

二叉搜索树(Java) – 左小右大

  树的概念应该比较直观,一个根延伸出很多的分支,每个分支又延伸出多个分支,以此类推,直到没有分支的为叶,以此枝繁叶茂;二叉树则是一棵有性格的树,规定了一个节点的分支不能超过2个;二叉搜索树则是在这个基础上再规定了,一个节点的左子节点的值必须小于该节点的值,右子节点的值必须大于该节点的值
  这里二叉搜索树是基于递归实现的,递归实现起来要简便一些,思路是从上至下的,只需确定好递归条件和递归结束条件即可;BST类中主要实现了二叉搜索树的增删改查;
  需要注意的是,二叉搜索树中的每一个节点都是一个对象(这里是内部类class Node),其中存放了键值和值,左节点指针和右节点指针,二叉搜索树中的排序比较是以各节点的键值进行比较的;定义为public中的方法供外部调用,方法功能的实现则定义为private,命名则为前面加go,如插入方法public供外部调用的是insert方法,实际实现则是private的goInsert方法~~

二叉搜索树 – 递归玩法

**
 * 二叉搜索树,类内部的最后面设置了节点的类;
 * 这里的二叉搜索树为大数据做了准备,键值的存在就是为了排位用的,从而不用实际的数据进行排位
 */

public class BST<Key extends Comparable<Key>, Data> {
    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 insert(Key key, Data data) { root = goInsert(root,key,data); }

    // 插入方法的实现方法;向以node为根或父节点的树或子树插入节点,最终返回根节点
    private Node goInsert(Node node, Key key, Data data) {
        // 如果当前的根或父节点为null,则需要新增一个节点存储新数据
        if(node == null) {
            node = new Node(key, data);
            size++;

            return node;
        }

        // 键值一样时更新数据,插入的键值较小时往左子树插入,插入的键值较大时往右子树插入
        if(key.compareTo(node.key) == 0) node.data = data;
        else if(key.compareTo(node.key) < 0) { node.left = goInsert(node.left,key,data); }
        else { node.right = goInsert(node.right,key,data); }

        return node;
    }

    /**
     * 查找元素实现
     */
    // 查找元素方法
    public Boolean find(Key key) {
        assert size != 0;

        return goFind(root,key);
    }

    // 查找元素的实现方法
    private Boolean goFind(Node node, Key key) {
        if(node == null) return false;

        if(key.compareTo(node.key) == 0) return true;
        else if(key.compareTo(node.key) < 0) return goFind(node.left,key);
        else return goFind(node.right,key);
    }

    /**
     * 遍历元素实现
     */
    // 先序遍历
    public void preOrderTraversal() {

        goPreOrderTraversal(root);
    }

    // 先序遍历实现
    private void goPreOrderTraversal(Node node) {
        if(node != null) {
            System.out.print(node.key + " ");

            goPreOrderTraversal(node.left);
            goPreOrderTraversal(node.right);
        }
    }

    // 中序遍历
    public void inOrderTraversal() {

        goInOrderTraversal(root);
    }

    // 中序遍历实现
    private void goInOrderTraversal(Node node) {
        if(node != null) {
            goInOrderTraversal(node.left);

            System.out.print(node.key + " ");

            goInOrderTraversal(node.right);
        }
    }

    // 后序遍历
    public void postOrderTraversal() {

        goInOrderTraversal(root);
    }

    // 后序遍历实现
    private void goPostOrderTraversal(Node node) {
        if(node != null) {
            goPostOrderTraversal(node.left);
            goPostOrderTraversal(node.right);

            System.out.print(node.key + " ");
        }
    }

    // 层序遍历
    public void TierOrderTraversal() {
        if(root == null) return;

        goTierOrderTraversal(root);
    }

    // 层序遍历实现
    private void goTierOrderTraversal(Node node) {
        // 用LinkedList作为队列
        Queue<Node> q = new LinkedList<Node>();
        q.add(node);

        // 只要队列中还有节点
        while(!q.isEmpty()) {
            // 弹出队列第一个元素
            Node hen = q.remove();

            System.out.print(hen.key + " ");

            if(hen.left != null) q.add(hen.left);
            if(hen.right != null) q.add(hen.right);
        }
    }

    /**
     * 查找
     */
    // 获取最大值
    public Key getMax() {
        // 确保有元素
        assert size != 0;

        return goGetMax(root).key;
    }

    // 获取最大值实现
    private Node goGetMax(Node node) {
        // 最右边的子节点为大哥,如果右边没大哥了,说明找到最大值了
        if(node.right == null) return node;
        // 右边还有子节点,继续遍历
        return goGetMax(node.right);
    }

    // 获取最小值
    public Key getMin() {
        // 确保有元素
        assert size != 0;

        return goGetMin(root).key;
    }

    // 获取最小值实现,实现逻辑和获取最大值相似
    private Node goGetMin(Node node) {
        if(node.left != null) return goGetMin(node.left);

        else return node;
    }

    // 是否存在某个元素
    public boolean isExisted(Key key) {

        return goIsExisted(root,key);
    }

    // 是否存在某个元素实现
    private boolean goIsExisted(Node node, Key key) {
        if(node == null) return false;

        if(node.key.compareTo(key) == 0) return true;
        else if(node.key.compareTo(key) > 0) return goIsExisted(node.left,key);
        else return goIsExisted(node.right,key);
    }

    // 获取某个元素的数据
    public Data getData(Key key) {

        return goGetData(root, key).data;
    }

    // 获取某个元素的数据实现
    private Node goGetData(Node node, Key key) {
        if(node == null) return null;

        if(node.key.compareTo(key) == 0) return node;
        else if(node.key.compareTo(key) > 0) return goGetData(node.left,key);
        else return goGetData(node.right,key);
    }

    /**
     * 节点类
     */
    // 节点中存储键值和数据,还要记录左右子节点
    private class Node {
        private Key key;
        private Data data;
        private Node left, right;

        public Node(Key key, Data data) {
            this.key = key;
            this.data = data;
            left = right = null;
        }
    }

}

二叉搜索树 – 性能

  二叉搜索树虽然具有左小右大的特性,但不一定是完全二叉树,甚至在最尴尬的情况下会变成一棵斜二叉树,也就是一个所有子节点都是左节点或都是右节点,说穿了就成了一个链表了;当键值从小到大插入时就会变成一棵右斜二叉树了,从大倒下插入则会变成一棵左斜二叉树,所以顺序插入会使二叉搜索树的性能退化成链表;所以一般情况下,也就是随机插入键值时,BST通常是优于二分查找法的,但是如果退化成链表,那就是一个O(n)级别的选手了,尴尬程度可想而知,所以在二叉搜索树后又催生了基于平衡的平衡二叉搜索树,如AVL和红黑树,下回分解~~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值