zoukankan      html  css  js  c++  java
  • Java数据结构与算法(4):二叉查找树

    一、二叉查找树定义

    二叉树每个节点都不能有多于两个的儿子。二叉查找树是特殊的二叉树,对于树中的每个节点X,它的左子树中的所有项的值小于X中的项,而它的右子树中所有项的值大于X中的项。

    二叉查找树节点的定义:

    private static class BinaryNode<T> {
        T element;    // 节点的值
        BinaryNode<T> left;        // 左子节点
        BinaryNode<T> right;     // 右子节点
    
        public BinaryNode(T element) {
            this(element, null, null);
        }
    
        public BinaryNode(T element, BinaryNode<T> left, BinaryNode<T> right) {
            this.element = element;
            this.left = left;
            this.right = right;
        }
    }
    

    二、树的遍历

    树的三种遍历方式:前序遍历、中序遍历、后序遍历。这里的前中后是相对于根节点而言的:

    • 前序遍历:根节点->左子树->右子树
    • 中序遍历:左子树->根节点->右子树
    • 后序遍历:左子树->右子树->根节点

    对于下面这样一棵树,不同的遍历方式结果如下:

    前序遍历:ABDGHCEIF

    private void preOrder(BinaryNode<T> root) {
        if (root == null) {
            return;
        }
        System.out.printf("%d ", root.element);
        preOrder(root.left);
        preOrder(root.right);
    }
    

    中序遍历:GDHBAEICF

    private void inOrder(BinaryNode<T> root) {
        if (root == null) {
            return;
        }
        inOrder(root.left);
        System.out.printf("%d ", root.element);
        inOrder(root.right);
    }
    

    后序遍历:GHDBIEFCA

    private void postOrder(BinaryNode<T> root) {
        if (root == null) {
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.printf("%d ", root.element);
    }
    

    三、二叉查找树的基本操作

    3.1 contains方法

    /**
     * 判断树t中是否存在含有项x的节点
     *
     * @param x 值
     * @param t 以t为根节点的一棵树
     * @return
     */
    private boolean contains(T x, BinaryNode<T> t) {
        if (t == null) {
            return false;
        }
        int compareResult = x.compareTo(t.element);
        if (compareResult < 0) {
            return contains(x, t.left);
        } else if (compareResult > 0) {
            return contains(x, t.right);
        } else {
            return true;
        }
    }
    
    public boolean contains(T x) {
        return contains(x, root);
    }
    

    3.2 find方法

    /**
     * 查找树t中值为x的节点
     * @param x
     * @param t
     * @return
     */
    private BinaryNode<T> find(T x, BinaryNode<T> t) {
        if (t == null) {
            return t;
        }
        int compareResult = x.compareTo(t.element);
        if (compareResult < 0) {
            return find(x, t.left);
        } else if (compareResult > 0) {
            return find(x, t.right);
        } else {
            return t;
        }
    }
    
    public BinaryNode<T> find(T x) {
        return find(x, root);
    }
    

    3.3 最大值与最小值

    查找树中最大值的节点

    private BinaryNode<T> findMax(BinaryNode<T> t) {
        if (t == null) {
            return null;
        }
        while (t.right != null) {
            t = t.right;
        }
        return t;
    }
    
    public BinaryNode<T> findMax() {
        return findMax(root);
    }
    

    查找树中最小值的节点

    private BinaryNode<T> findMin(BinaryNode<T> t) {
        if (t == null) {
            return null;
        }
        while (t.left != null) {
            t = t.left;
        }
        return t;
    }
    
    public BinaryNode<T> findMin() {
        return findMin(root);
    }
    

    3.4 insert方法

    private BinaryNode<T> insert(T x, BinaryNode<T> t) {
        if (t == null) {
            return new BinaryNode<>(x, null, null);
        }
        int compareResult = x.compareTo(t.element);
        if (compareResult < 0) {
            t.left = insert(x, t.left);
        } else if (compareResult > 0) {
            t.right = insert(x, t.right);
        } else {
            // 出现重复值,忽略不处理
        }
        return t;
    }
    
    public void insert(T x) {
        root = insert(x, root);
    }
    

    3.5 remove方法

    • 如果需要删除的节点是叶节点,那么可以直接删除;
    • 如果节点有一个儿子,则让儿子节点取代该节点即可;
    • 如果节点有两个儿子,通常用其右子树的最小的数据代替该节点的数据并递归地删除那个节点。
      因为右子树的最小节点不可能有左儿子
    public void remove(T x) {
            root = remove(x, root);
    }
    
    private BinaryNode<T> remove(T x, BinaryNode<T> t) {
        if (t == null) {
            return t;
        }
        int compareResult = x.compareTo(t.element);
        if (compareResult < 0) {
            t.left = remove(x, t.left);
        } else if (compareResult > 0) {
            t.right = remove(x, t.right);
        } else if (t.left != null && t.right != null) {
            // 用右子树的最小的数据代替该节点的数据并递归地删除这个节点
            t.element = findMin(t.right).element;
            t.right = remove(t.element, t.right);
        } else {
            // 只有一个儿子,直接用儿子代替该节点
            t = (t.left != null) ? t.left : t.right;
        }
        return t;
    }
    
  • 相关阅读:
    a标签中调用js的几种方法
    IE11浏览器:请不要再叫我IE,谢谢
    IE11浏览器:请不要再叫我IE,谢谢
    浅谈href=#与href=javascript:void(0)的区别
    浅谈href=#与href=javascript:void(0)的区别
    Google Java编程风格指南
    Google Java编程风格指南
    Git学习小结 ~ Lethe's Blog
    Binder机制简析(三)
    Ness
  • 原文地址:https://www.cnblogs.com/xiaoxiaoyihan/p/11640112.html
Copyright © 2011-2022 走看看