bst java_图解:二叉搜索树算法(BST)

一、树 & 二叉树

树是由节点和边构成,储存元素的集合。节点分根节点、父节点和子节点的概念。

如图:树深=4; 5是根节点;同样8与3的关系是父子节点关系。

236494ad8e7a503b06cf7fc039681a70.png

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

如图:1/8是左节点;2/3是右节点;

71637eb3c00cb5419cecafdc161a96c4.png

二、二叉搜索树 BST

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

如图:每个节点比它左子树的任意节点大,而且比它右子树的任意节点小

97718cb0809ecdb4132f17419ef5b90a.png

三、BST Java实现

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

BinarySearchTree.javapackage 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. */publicclassBinarySearchTree { /** * 根节点 */publicstaticTreeNode root; publicBinarySearchTree() { this.root = null; } /** * 查找 * 树深(N) O(lgN) * 1. 从root节点开始 * 2. 比当前节点值小,则找其左节点 * 3. 比当前节点值大,则找其右节点 * 4. 与当前节点值相等,查找到返回TRUE * 5. 查找完毕未找到, * @param key * @return */publicTreeNode search ( intkey) { TreeNode current = root;

while(current != null && key != current.value) {

if(key < current.value ) current = current.left;

elsecurrent = current.right; } returncurrent; } /** * 插入 * 1. 从root节点开始 * 2. 如果root为空,root为插入值 * 循环: * 3. 如果当前节点值大于插入值,找左节点 * 4. 如果当前节点值小于插入值,找右节点 * @param key * @return */publicTreeNode insert ( intkey) { // 新增节点TreeNode newNode = newTreeNode(key); // 当前节点TreeNode current = root; // 上个节点TreeNode parent = null; // 如果根节点为空if(current == null) { root = newNode;

returnnewNode; } while( true) { parent = current;

if(key < current.value) { current = current.left;

if(current == null) { parent.left = newNode;

returnnewNode; } } else{ current = current.right;

if(current == null) { parent.right = newNode;

returnnewNode; } } } } /** * 删除节点 * 1.找到删除节点 * 2.如果删除节点左节点为空 , 右节点也为空; * 3.如果删除节点只有一个子节点 右节点 或者 左节点 * 4.如果删除节点左右子节点都不为空 * @param key * @return */publicTreeNode delete( intkey) { 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) {

returncurrent; } } // 如果删除节点左节点为空 , 右节点也为空if(current.left == null && current.right == null) { if(current == root) { root = null; } // 在左子树if(isLeftChild == true) { parent.left = null; } else{ parent.right = null; } } // 如果删除节点只有一个子节点 右节点 或者 左节点elseif(current.right == null) { if(current == root) { root = current.left; } elseif(isLeftChild) { parent.left = current.left; } else{ parent.right = current.left; } }

elseif(current.left == null) {

if(current == root) { root = current.right; } elseif(isLeftChild) { parent.left = current.right; } else{ parent.right = current.right; } } // 如果删除节点左右子节点都不为空elseif(current.left != null && current.right != null) { // 找到删除节点的后继者TreeNode successor = getDeleteSuccessor(current); if(current == root) { root = successor; } elseif(isLeftChild) { parent.left = successor; } else{ parent.right = successor; } successor.left = current.left; } returncurrent; } /** * 获取删除节点的后继者 * 删除节点的后继者是在其右节点树种最小的节点 * @param deleteNode * @return */publicTreeNode 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; }

returnsuccessor; } publicvoidtoString(TreeNode root) {

if(root != null) { toString(root.left); System.out.print( "value = "+ root.value + " -> "); toString(root.right); } }} /** * 节点 */classTreeNode { /** * 节点值 */intvalue; /** * 左节点 */TreeNode left; /** * 右节点 */TreeNode right;

publicTreeNode( intvalue) {

this.value = value; left = null; right = null; }}

1、节点数据结构

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

8f872d651e024592494f9c89900df9d0.png

代码如下:

/** * 节点 */classTreeNode { /** * 节点值 */int value; /** * 左节点 */TreeNode left; /** * 右节点 */TreeNode right; public TreeNode(int value) {

this.value = value; left = null; right = null; }}

2、插入

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

43b0b237b8b955d49f392d0a043e8a2e.png

a. 从root节点开始

b.如果root为空,root为插入值

c.循环:

d.如果当前节点值大于插入值,找左节点

e.如果当前节点值小于插入值,找右节点

代码对应:

3、查找

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

6ee417809b64e8d2f2c09c13ac1e4330.png

a.从root节点开始

b.比当前节点值小,则找其左节点

c.比当前节点值大,则找其右节点

d.与当前节点值相等,查找到返回TRUE

e.查找完毕未找到

代码对应:

/** * 节点 */classTreeNode { /** * 节点值 */intvalue; /** * 左节点 */TreeNode left; /** * 右节点 */TreeNode right;

publicTreeNode( intvalue) {

this.value = value; left = null; right = null; }}

4、删除

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

a7e6e7af8592751ae4792b4d5417b07c.png

结果为:

afe41cb6d0af3d6842c35a6d5fd4e914.png

a.找到删除节点

b.如果删除节点左节点为空 , 右节点也为空;

c.如果删除节点只有一个子节点 右节点 或者 左节点

d.如果删除节点左右子节点都不为空

代码对应见上面完整代码。

案例测试代码如下,BinarySearchTreeTest.javapackage 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. */publicclassBinarySearchTreeTest {

publicstaticvoidmain(String[] args) { BinarySearchTree b = newBinarySearchTree(); 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(); // 是否存在节点值10TreeNode node01 = b.search( 10); System.out.println( "是否存在节点值为10 => "+ node01.value); // 是否存在节点值11TreeNode node02 = b.search( 11); System.out.println( "是否存在节点值为11 => "+ node02); // 删除节点8TreeNode 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 主页 https://github.com/JeffLi1993/algorithm-core-learning返回搜狐,查看更多

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值