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

本文介绍了二叉搜索树(BST)的概念,包括树与二叉树的基本概念,以及BST的特点。详细讲解了BST的Java实现,包括查找、插入和删除操作,并提供了完整的Java代码示例。此外,还提供了测试用例展示如何操作BST。
摘要由CSDN通过智能技术生成

一、树 & 二叉树

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

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

ddfdac2bc1468acdb0c9712b8e75cdf8.png

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

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

25663a4b39b16f7bd918db672b1d151a.png

二、二叉搜索树 BST

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

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

b7baffa8244eb0a5f632db38e1517a30.png

三、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. 节点数据结构

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

a691bb383e7e3e4c55e4641a6365b44a.png

代码如下:

/**

* 节点

*/

class TreeNode {

/**

* 节点值

*/

int value;

/**

* 左节点

*/

TreeNode left;

/**

* 右节点

*/

TreeNode right;

public TreeNode(int value) {

this.value = value;

left = null;

right = null;

}

}

2. 插入

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

6a7b7391f4db63fa9e700a26ff6a46d6.png

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)。如图查找逻辑:

5bf572636cf39416beac18e8d2b93464.png

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. 删除

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

0ad3d55042da710a85fb0df878cd3e90.png

结果为:

ee3db640adad5c644990d635f72bae39.png

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 => 8

value = 1 -> value = 2 -> value = 3 -> value = 4 -> value = 6 -> value = 9 -> value = 10 -> value = 20 -> value = 25 ->

四、小结

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

树,二叉树的概念

BST算法

相关代码分享在 Github 主页

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值