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

2024-05-13 01:08
文章标签 算法 搜索 图解 二叉 bst

本文主要是介绍图解:二叉搜索树算法(BST),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!“岁月极美,在于它必然的流逝”“春花 秋月 夏日 冬雪”— 三毛

一、树 & 二叉树

是由节点和边构成,储存元素的集合。节点分根节点、父节点和子节点的概念。如图:树深=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;elsecurrent = 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.与当前节点值相等,查找到返回TRUEe.查找完毕未找到代码对应:

    /*** 查找*      树深(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;elsecurrent = 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();// 是否存在节点值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 => 8
value = 1 -> value = 2 -> value = 3 -> value = 4 -> value = 6 -> value = 9 -> value = 10 -> value = 20 -> value = 25 ->

四、小结

与偶尔吃一碗“老坛酸菜牛肉面”一样的味道,品味一个算法,比如BST,的时候,总是那种说不出的味道。树,二叉树的概念BST算法相关代码分享在 Github 主页

如以上文章或链接对你有帮助的话,别忘了在文章结尾处评论哈~ 你也可以点击页面右边“分享”悬浮按钮哦,让更多的人阅读这篇文章。

这篇关于图解:二叉搜索树算法(BST)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/984253

相关文章

龙蜥操作系统Anolis OS-23.x安装配置图解教程(保姆级)

《龙蜥操作系统AnolisOS-23.x安装配置图解教程(保姆级)》:本文主要介绍了安装和配置AnolisOS23.2系统,包括分区、软件选择、设置root密码、网络配置、主机名设置和禁用SELinux的步骤,详细内容请阅读本文,希望能对你有所帮助... ‌AnolisOS‌是由阿里云推出的开源操作系统,旨

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

C# ComboBox下拉框实现搜索方式

《C#ComboBox下拉框实现搜索方式》文章介绍了如何在加载窗口时实现一个功能,并在ComboBox下拉框中添加键盘事件以实现搜索功能,由于数据不方便公开,作者表示理解并希望得到大家的指教... 目录C# ComboBox下拉框实现搜索步骤一步骤二步骤三总结C# ComboBox下拉框实现搜索步骤一这

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

hdu1240、hdu1253(三维搜索题)

1、从后往前输入,(x,y,z); 2、从下往上输入,(y , z, x); 3、从左往右输入,(z,x,y); hdu1240代码如下: #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#inc

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig