Java实现 二叉搜索树算法(BST)

来源:互联网 发布:导航端口和波特率 编辑:程序博客网 时间:2024/06/05 07:25

一、树 & 二叉树

是由节点和边构成,储存元素的集合。节点分根节点、父节点和子节点的概念。
如图:树深=4; 5是根节点;同样8与3的关系是父子节点关系。

1
二叉树binary tree,则加了“二叉”(binary),意思是在树中作区分。每个节点至多有两个子(child),left child & right child。二叉树在很多例子中使用,比如二叉树表示算术表达式。
如图:1/8是左节点;2/3是右节点;

2

二、二叉搜索树 BST

顾名思义,二叉树上又加了个搜索的限制。其要求:每个节点比其左子树元素大,比其右子树元素小。
如图:每个节点比它左子树的任意节点大,而且比它右子树的任意节点小

3

三、BST Java实现

直接上代码,对应代码分享在 Github 主页
BinarySearchTree.java

package org.algorithm.tree;/* * Copyright [2015] [Jeff Lee] * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *   http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//** * 二叉搜索树(BST)实现 * * Created by bysocket on 16/7/7. */public class BinarySearchTree {    /**     * 根节点     */    public static TreeNode root;    public BinarySearchTree() {        this.root = null;    }    /**     * 查找     *      树深(N) O(lgN)     *      1. 从root节点开始     *      2. 比当前节点值小,则找其左节点     *      3. 比当前节点值大,则找其右节点     *      4. 与当前节点值相等,查找到返回TRUE     *      5. 查找完毕未找到,     * @param key     * @return     */    public TreeNode search (int key) {        TreeNode current = root;        while (current != null                && key != current.value) {            if (key < current.value )                current = current.left;            else                current = current.right;        }        return current;    }    /**     * 插入     *      1. 从root节点开始     *      2. 如果root为空,root为插入值     *      循环:     *      3. 如果当前节点值大于插入值,找左节点     *      4. 如果当前节点值小于插入值,找右节点     * @param key     * @return     */    public TreeNode insert (int key) {        // 新增节点        TreeNode newNode = new TreeNode(key);        // 当前节点        TreeNode current = root;        // 上个节点        TreeNode parent  = null;        // 如果根节点为空        if (current == null) {            root = newNode;            return newNode;        }        while (true) {            parent = current;            if (key < current.value) {                current = current.left;                if (current == null) {                    parent.left = newNode;                    return newNode;                }            } else {                current = current.right;                if (current == null) {                    parent.right = newNode;                    return newNode;                }            }        }    }    /**     * 删除节点     *      1.找到删除节点     *      2.如果删除节点左节点为空 , 右节点也为空;     *      3.如果删除节点只有一个子节点 右节点 或者 左节点     *      4.如果删除节点左右子节点都不为空     * @param key     * @return     */    public TreeNode delete (int key) {        TreeNode parent  = root;        TreeNode current = root;        boolean isLeftChild = false;        // 找到删除节点 及 是否在左子树        while (current.value != key) {            parent = current;            if (current.value > key) {                isLeftChild = true;                current = current.left;            } else {                isLeftChild = false;                current = current.right;            }            if (current == null) {                return current;            }        }        // 如果删除节点左节点为空 , 右节点也为空        if (current.left == null && current.right == null) {            if (current == root) {                root = null;            }            // 在左子树            if (isLeftChild == true) {                parent.left = null;            } else {                parent.right = null;            }        }        // 如果删除节点只有一个子节点 右节点 或者 左节点        else if (current.right == null) {            if (current == root) {                root = current.left;            } else if (isLeftChild) {                parent.left = current.left;            } else {                parent.right = current.left;            }        }        else if (current.left == null) {            if (current == root) {                root = current.right;            } else if (isLeftChild) {                parent.left = current.right;            } else {                parent.right = current.right;            }        }        // 如果删除节点左右子节点都不为空        else if (current.left != null && current.right != null) {            // 找到删除节点的后继者            TreeNode successor = getDeleteSuccessor(current);            if (current == root) {                root = successor;            } else if (isLeftChild) {                parent.left = successor;            } else {                parent.right = successor;            }            successor.left = current.left;        }        return current;    }    /**     * 获取删除节点的后继者     *      删除节点的后继者是在其右节点树种最小的节点     * @param deleteNode     * @return     */    public TreeNode getDeleteSuccessor(TreeNode deleteNode) {        // 后继者        TreeNode successor = null;        TreeNode successorParent = null;        TreeNode current = deleteNode.right;        while (current != null) {            successorParent = successor;            successor = current;            current = current.left;        }        // 检查后继者(不可能有左节点树)是否有右节点树        // 如果它有右节点树,则替换后继者位置,加到后继者父亲节点的左节点.        if (successor != deleteNode.right) {            successorParent.left = successor.right;            successor.right = deleteNode.right;        }        return successor;    }    public void toString(TreeNode root) {        if (root != null) {            toString(root.left);            System.out.print("value = " + root.value + " -> ");            toString(root.right);        }    }}/** * 节点 */class TreeNode {    /**     * 节点值     */    int value;    /**     * 左节点     */    TreeNode left;    /**     * 右节点     */    TreeNode right;    public TreeNode(int value) {        this.value = value;        left  = null;        right = null;    }}

1. 节点数据结构
首先定义了节点的数据接口,节点分左节点和右节点及本身节点值。如图

4

代码如下:

/** * 节点 */class TreeNode {    /**     * 节点值     */    int value;    /**     * 左节点     */    TreeNode left;    /**     * 右节点     */    TreeNode right;    public TreeNode(int value) {        this.value = value;        left  = null;        right = null;    }}

 

2. 插入
插入,和删除一样会引起二叉搜索树的动态变化。插入相对删处理逻辑相对简单些。如图插入的逻辑:

5
a. 从root节点开始
b.如果root为空,root为插入值
c.循环:
d.如果当前节点值大于插入值,找左节点
e.如果当前节点值小于插入值,找右节点
代码对应:

    /**     * 插入     *      1. 从root节点开始     *      2. 如果root为空,root为插入值     *      循环:     *      3. 如果当前节点值大于插入值,找左节点     *      4. 如果当前节点值小于插入值,找右节点     * @param key     * @return     */    public TreeNode insert (int key) {        // 新增节点        TreeNode newNode = new TreeNode(key);        // 当前节点        TreeNode current = root;        // 上个节点        TreeNode parent  = null;        // 如果根节点为空        if (current == null) {            root = newNode;            return newNode;        }        while (true) {            parent = current;            if (key < current.value) {                current = current.left;                if (current == null) {                    parent.left = newNode;                    return newNode;                }            } else {                current = current.right;                if (current == null) {                    parent.right = newNode;                    return newNode;                }            }        }    }

 

3.查找

其算法复杂度 : O(lgN),树深(N)。如图查找逻辑:

6
a.从root节点开始
b.比当前节点值小,则找其左节点
c.比当前节点值大,则找其右节点
d.与当前节点值相等,查找到返回TRUE
e.查找完毕未找到
代码对应:

    /**     * 查找     *      树深(N) O(lgN)     *      1. 从root节点开始     *      2. 比当前节点值小,则找其左节点     *      3. 比当前节点值大,则找其右节点     *      4. 与当前节点值相等,查找到返回TRUE     *      5. 查找完毕未找到,     * @param key     * @return     */    public TreeNode search (int key) {        TreeNode current = root;        while (current != null                && key != current.value) {            if (key < current.value )                current = current.left;            else                current = current.right;        }        return current;    }

4. 删除
首先找到删除节点,其寻找方法:删除节点的后继者是在其右节点树种最小的节点。如图删除对应逻辑:7

结果为:

8
a.找到删除节点
b.如果删除节点左节点为空 , 右节点也为空;
c.如果删除节点只有一个子节点 右节点 或者 左节点
d.如果删除节点左右子节点都不为空
代码对应见上面完整代码。

 

案例测试代码如下,BinarySearchTreeTest.java

package org.algorithm.tree;/* * Copyright [2015] [Jeff Lee] * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *   http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//** * 二叉搜索树(BST)测试案例 {@link BinarySearchTree} * * Created by bysocket on 16/7/10. */public class BinarySearchTreeTest {    public static void main(String[] args) {        BinarySearchTree b = new BinarySearchTree();        b.insert(3);b.insert(8);b.insert(1);b.insert(4);b.insert(6);        b.insert(2);b.insert(10);b.insert(9);b.insert(20);b.insert(25);        // 打印二叉树        b.toString(b.root);        System.out.println();        // 是否存在节点值10        TreeNode node01 = b.search(10);        System.out.println("是否存在节点值为10 => " + node01.value);        // 是否存在节点值11        TreeNode node02 = b.search(11);        System.out.println("是否存在节点值为11 => " + node02);        // 删除节点8        TreeNode node03 = b.delete(8);        System.out.println("删除节点8 => " + node03.value);        b.toString(b.root);    }}

运行结果如下:

value = 1 -> value = 2 -> value = 3 -> value = 4 -> value = 6 -> value = 8 -> value = 9 -> value = 10 -> value = 20 -> value = 25 -> 是否存在节点值为10 => 10是否存在节点值为11 => null删除节点8 => 8value = 1 -> value = 2 -> value = 3 -> value = 4 -> value = 6 -> value = 9 -> value = 10 -> value = 20 -> value = 25 ->

四、小结

与偶尔吃一碗“老坛酸菜牛肉面”一样的味道,品味一个算法,比如BST,的时候,总是那种说不出的味道。

树,二叉树的概念

BST算法

相关代码分享在 Github 主页


转载自并发编程网 – ifeve.com本文链接地址: Java实现 二叉搜索树算法(BST)

0 0