• 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;
    }
    
  • 相关阅读:
    淘宝质量属性场景分析
    关于软件架构师如何工作(阅读架构漫谈感悟)
    06有效需求设计阅读笔记之六
    05有效需求设计阅读笔记之五
    xxx征集系统项目目标文档
    04有效需求设计阅读笔记之四
    03有效需求设计阅读笔记之三
    02有效需求设计阅读笔记之二
    01有效需求设计阅读笔记之一
    问题账户需求分析
  • 原文地址:https://www.cnblogs.com/xiaoxiaoyihan/p/11640112.html
Copyright © 2020-2023  润新知