Java数据结构(十三)—— 二叉排序树(BST)
二叉排序树(BST)
需求
给定数列{7,3,10,12,5,1,9},要求能够高效的完成对数据的查询和添加
思路三则
使用数组,缺点:插入和排序速度较慢
链式存储,添加较快,但查找速度慢
使用二叉排序树
基本介绍
对于二叉排序树的任何一个非叶子节点,要求左子节点的值比当前节点的值小,右子节点的值比当前节点的值大
图解

步骤
从数列取出第一个数成为根节点
取出第二个数,从根结点开始比较,大于当前节点,与右子节点比较,小于当前节点与左子节点比较
直到放到叶子节点
取出剩余的数值,重复上述步骤
建立二叉排序树
代码实现:BinarySortTree.java
package com.why.binary_sort_tree;
/**
* @Description TODO 建立二叉排序树
* @Author why
* @Date 2020/12/1 14:38
* Version 1.0
**/
public class BinarySortTreeDemo {
public static void main(String[] args) {
int[] arr = {7,3,10,12,5,1,9};
BinarySortTree bst = new BinarySortTree();
for (int i = 0; i < arr.length; i++) {
Node node = new Node(arr[i]);
bst.add(node);
}
System.out.println("中序遍历二叉排序树;");
bst.midOrder();
}
}
/**
* 二叉排序树
*/
class BinarySortTree{
private Node root;
/**
* 添加节点
* @param node
*/
public void add(Node node){
if (root == null){//直接放上
root = node;
}else {
root.add(node);
}
}
/**
* 中序遍历
*/
public void midOrder(){
if (root != null){
root.midOrder();
}else {
System.out.println("二叉排序树为空");
}
}
}
/**
* 节点类
*/
class Node{
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
/**
* 添加节点,递归形式,需满足二叉排序树的要求
* @param node
*/
public void add(Node node){
if (node == null){
return;
}
//判断传入的节点的值和当前子树的根节点的值的关系
if (node.value < this.value){
if (this.left == null){//当前节点左子节点为空
this.left = node;
}else {//不为空,递归向左子树添加
this.left.add(node);
}
}else {
if (this.right == null){
this.right = node;
}else {
this.right.add(node);
}
}
}
/**
* 中序遍历
*/
public void midOrder(){
if (left != null){
this.left.midOrder();
}
System.out.println(this);
if (this.right != null){
this.right.midOrder();
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
}
二叉排序树删除
删除的节点是叶子节点
思路
先找到要删除的节点targetNode
找到targetNode的父节点parent
确定targetNode是parent的左子节点还是右子节点
根据前面的情况对应删除
删除的节点只有一棵子树的情况
思路
先找到要删除的节点targetNode
找到targetNode的父节点parent
确定targetNode的子节点是左子节点还是右子节点
确定targetNode是parent的左子节点还是右子节点
如果targetNode有左子节点
targetNode是parent的左子节点 parent.left = targetNode.left
targetNode是parent的右子节点parent.right = tsrgetNode.left
如果targetNode有右子节点
targetNode是parent的左子节点parent.left = targetNode.right
targetNode是parent的右子节点parent.right = psrent.right
删除的节点有两颗子树
思路
先找到要删除的节点targetNode
找到targetNode的父节点parent
从targetNode的右子树找到最小的节点
用一个临时变量,将最小的节点的值保存temp
删除最小节点
targetNode.value = temp.value
代码实现
package com.why.binary_sort_tree;
/**
* @Description TODO 建立二叉排序树
* @Author why
* @Date 2020/12/1 14:38
* Version 1.0
**/
public class BinarySortTreeDemo {
public static void main(String[] args) {
int[] arr = {7,3,10,12,5,1,9,0,2,4,6,8,};
BinarySortTree bst = new BinarySortTree();
for (int i = 0; i < arr.length; i++) {
Node node = new Node(arr[i]);
bst.add(node);
}
System.out.println("中序遍历二叉排序树;");
bst.midOrder();
System.out.println("删除后");
bst.deleteNode(5);
bst.midOrder();
}
}
/**
* 二叉排序树
*/
class BinarySortTree{
private Node root;
/**
* 添加节点
* @param node
*/
public void add(Node node){
if (root == null){//直接放上
root = node;
}else {
root.add(node);
}
}
/**
* 中序遍历
*/
public void midOrder(){
if (root != null){
root.midOrder();
}else {
System.out.println("二叉排序树为空");
}
}
/**
* 查找需删除的节点
* @param value
* @return
*/
public Node search(int value){
if (root == null){
return null;
}else {
return root.search(value);
}
}
/**
* 查找父节点
* @param value
* @return
*/
public Node searchParent(int value){
if (root == null){
return null;
}else {
return root.searchParent(value);
}
}
public void deleteNode(int value){
if (root == null){
return;
}else {
//找到需删除的节点
Node targetNode = search(value);
if (targetNode == null){//未找到
return;
}
//如果二叉排序树只有一个节点
if (root.left == null && root.right == null){
return;
}
//查找需删除的节点的父节点
Node parent = searchParent(value);
if (targetNode.left == null && targetNode.right == null){//删除的节点是叶子节点
//判断targetNode是父节点的左子节点还是右子节点
if (parent.left != null && parent.left.value == value){//是左子节点
parent.left = null;
}else if (parent.right != null && parent.right.value == value){//是右子节点
parent.right = null;
}
}else if ((targetNode.left != null && targetNode.right == null) ||
(targetNode.right != null && targetNode.left == null)) {//只有一棵子树
//确定targetNode的节点是左节点还是右节点
if (targetNode.left != null) {//左子节点
if (parent != null){//非根节点
//确定targetNode是parent的左子节点还是右子节点
if (parent.left.value == value) {//左子节点
parent.left = targetNode.left;
} else {//右子节点
parent.right = targetNode.left;
}
}else {
root = targetNode.left;
}
} else {//右子节点
if (parent != null){
//确定targetNode是parent的左子节点还是右子节点
if (parent.left.value == value) {//左子节点
parent.left = targetNode.right;
} else {//右子节点
parent.right = targetNode.right;
}
}else {
root = targetNode.right;
}
}
}else {//删除的节点有两颗子树
//找到最小值并删除
int minValue = deleteRightMin(targetNode.right);
//将最小值赋值给targetNode.value
targetNode.value = minValue;
}
}
}
/**
* 寻找最小值
* @param node
* @return
*/
public int deleteRightMin(Node node){
Node target = node;
while (target.left != null){
target = target.left;
}
//这时target指向最小节点
//删除最小节点
deleteNode(target.value);
//返回最小节点的value
return target.value;
}
}
/**
* 节点类
*/
class Node{
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
/**
* 添加节点,递归形式,需满足二叉排序树的要求
* @param node
*/
public void add(Node node){
if (node == null){
return;
}
//判断传入的节点的值和当前子树的根节点的值的关系
if (node.value < this.value){
if (this.left == null){//当前节点左子节点为空
this.left = node;
}else {//不为空,递归向左子树添加
this.left.add(node);
}
}else {
if (this.right == null){
this.right = node;
}else {
this.right.add(node);
}
}
}
/**
* 中序遍历
*/
public void midOrder(){
if (left != null){
this.left.midOrder();
}
System.out.println(this);
if (this.right != null){
this.right.midOrder();
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
/**
* 寻找需要删除的节点
* @param value
* @return
*/
public Node search(int value){
if (value == this.value){//找到
return this;
}else if (value < this.value){//向左子树查找
if (this.left == null){
return null;
}
return this.left.search(value);
}else {//向右子树查找
if (this.right == null){
return null;
}
return this.right.search(value);
}
}
/**
* 查找需要删除节点的父节点
* @param value
* @return
*/
public Node searchParent(int value){
if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)){
//找到父节点返回当前节点
return this;
}else {
//如果查找的值小于当前节点的值
if (value < this.value && this.left != null){//左子树查找
return this.left.searchParent(value);
}else if (value >= this.value && this.right != null){//右子树查找
return this.right.searchParent(value);
}else {
return null;//没有找到父节点
}
}
}
}
Java数据结构(十三)—— 二叉排序树(BST)的更多相关文章
- Java数据结构和算法(五)二叉排序树(BST)
Java数据结构和算法(五)二叉排序树(BST) 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 二叉排序树(Binary S ...
- 数据结构------------------二叉查找树(BST)的java实现
数据结构------------------二叉查找树(BST)的java实现 二叉查找树(BST)是一种能够将链表插入的灵活性和有序数组查找的高效性相结合的一种数据结构.它的定义如下: 二叉查找树是 ...
- 一文掌握关于Java数据结构所有知识点(欢迎一起完善)
在我们学习Java的时候,很多人会面临我不知道继续学什么或者面试会问什么的尴尬情况(我本人之前就很迷茫).所以,我决定通过这个开源平台来帮助一些有需要的人,通过下面的内容,你会掌握系统的Java学习以 ...
- 二叉排序树(BST)构造与应用
二叉排序树(BST)构造与应用 本文取自<数据结构与算法>(C语言版)(第三版).出版社是清华大学出版社. 本博文作为学习资料整理. 源码是VC+ ...
- Java数据结构和算法(一)树
Java数据结构和算法(一)树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 前面讲到的链表.栈和队列都是一对一的线性结构, ...
- Java数据结构和算法(二)树的基本操作
Java数据结构和算法(二)树的基本操作 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 一.树的遍历 二叉树遍历分为:前序遍 ...
- Java数据结构和算法(七)--AVL树
在上篇博客中,学习了二分搜索树:Java数据结构和算法(六)--二叉树,但是二分搜索树本身存在一个问题: 如果现在插入的数据为1,2,3,4,5,6,这样有序的数据,或者是逆序 这种情况下的二分搜索树 ...
- 【java 数据结构】还不会二叉树?一篇搞定二叉树
二叉树是我们常见的数据结构之一,在学习二叉树之前我们需要知道什么是树,什么是二叉树,本篇主要讲述了二叉树,以及二叉树的遍历. 你能get到的知识点? 1.树的介绍 2.二叉树的介绍 3.二叉树遍历的四 ...
- 二叉排序树(BST)创建,删除,查找操作
binary search tree,中文翻译为二叉搜索树.二叉查找树或者二叉排序树.简称为BST 一:二叉搜索树的定义 他的定义与树的定义是类似的,也是一个递归的定义: 1.要么是一棵空树 2.如果 ...
- Java数据结构之队列的实现以及队列的应用之----简单生产者消费者应用
Java数据结构之---Queue队列 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在 ...
随机推荐
- python的各版本的不同
Python的版本主要分为 2.× . 3.× 两个系列. Python3计划每年发布一个新的子版本,一次只增加一两种新语法. 使用时当然选择越新的Python版本越好,版本越老的代码越难维护. 维护 ...
- 为什么layui表单不显示?
当你使用表单时,Layui会对select.checkbox.radio等原始元素隐藏,从而进行美化修饰处理.但这需要依赖于form组件,所以你必须加载 form,并且执行一个实例.值得注意的是:导航 ...
- 八位“Booth二位乘算法”乘法器
目录 八位"Booth二位乘算法"乘法器 原理 补码乘法器 Booth一位乘 Booth二位乘 设计思路 减法变加法 vivado特性 设计文件 综合电路 测试文件 仿真波形 八位 ...
- 内网渗透 day7-linux信息收集
linux信息搜集 目录 1. linux信息搜集 2. nmap漏洞复现 3. msf linux模块反弹shell 1. linux信息搜集 id 查看当前用户的权限和所在的管理组 python ...
- 数组和list 相互转换中遇到的坑
代码示例: public class ArrayDemo { public static void main(String[] args) { Integer[] arr = {1, 2, 3, 4, ...
- 极客mysql08
1.innodb支持RC和RR隔离级别实现是用的一致性视图(consistent read view) 2.事务在启动时会拍一个快照,这个快照是基于整个库的. 基于整个库的意思就是说一个事务内,整个库 ...
- python3:文件读写+with open as语句(转)
读写文件是最常见的IO操作.Python内置了读写文件的函数,用法和C是兼容的. 读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘, ...
- [LeetCode题解]141. 环形链表 | 快慢指针
题目描述 给定一个链表,判断链表中是否有环. 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的 ...
- 环境安装和pycharm中一些基本设置
一.Pycharm的使用和Python环境 1.python和pycharm的安装 python推荐版本3.7/3.8 pycharm选择社区版本 查看python版本在cmd中输入"pyt ...
- 如何在FL Studio中使用自动剪辑(下)
在上集中我想大家介绍了FL Stduio Automation Clip的创建.播放列表操作及包络线类型介绍,在这篇文章中我将会给大家介绍如何在播放列表中使用Automation,剪辑通道的操作及使用 ...