二叉排序树BST及CRUD操作
摘要
构造一颗二叉排序树(也叫二叉搜索树,BST,Binary Search Tree)十分简单。一般来讲,大于根节点的放在根节点的右子树上,小于根节点的放在根节点的左子树上(如果等于根节点,则可视情况而定),如果写程序的话,可以采用递归的方式,而且由于不存在重叠子问题的情况,因此递归的性能已经足够好(不考虑栈溢出的情况)。
二叉排序树在通常情况下可以达到O(lgN)的静态、动态操作的时间复杂度,但是存在一种特殊情况,即输入的数据本身就是有序的,这时二叉排序树退化成向量。
下面我们系统归纳一下二叉树的特性,以及相关操作及其代码实现。
二叉排序树
简称BST,也称为二叉查找树。其或是一棵空树,或是一棵具有下列特性的非空二叉树:
1)若左子树非空,则左子树上所有结点关键字值均小于根结点的关键字值。
2)若右子树非空,则右子树上所有结点关键字值均大于根结点的关键字值。
3)左、右子树本身也分别是一棵二叉排序树。
其是一个递归的数据结构。
左子树结点值 < 根结点值 < 右子树结点值
对其进行中序遍历可以得到一个递增的有序序列。

图1. 二叉排序树示例图
CRUD操作
Create-构造二叉排序树
构造一棵二叉排序树就是依次输入数据元素,并将它们插入到二叉树中的适当位置上的过程。
具体过程:
1)每读入一个元素,就建立一个新节点。
2)若二叉排序树非空,则将新结点的值与根结点的值比较。如果小于根结点的值,则插入到左子树中,否则插入到右子树中。
3)若二叉排序树为空,则新结点作为二叉树的根结点。
void Create_BST(BiTree &T, KeyType str[], int n) {
//用关键字数组str[]建立一个二叉排序树
T = NULL; //初始时bt为空树
int i = 0;
while(i < n) { //依次将每个元素插入
BST_Insert(T, str[i]);
i++;
}
}
Retrieve-查找二叉排序树的某结点
二叉排序树的查找是从根结点开始,沿某一分支逐层向下进行比较的一个递归的过程。
具体查找过程是:
1)若二叉树非空,将给定值与根结点的关键字比较,若相等,则查找成功;
2)若不等,则当根结点的关键字大于给定关键字值k时,在根结点的左子树中查找;
3)当根结点的关键字小于给定关键字值k时,在根结点的右子树中查找。
二叉排序树的非递归查找算法:
BSTNode *BST_Search(BiTree T,ElemTypr key,BSTNode *&p) {
//查找函数返回值指向关键字值为key的结点指针,若不存在,返回NULL
p = NULL; //p指向被查找结点的双亲,用于插入和删除操作中
while(T != NULL && key != T->data) {
p = T;
if(key < T->data) {
T = T->lchild;
} else {
T = T->rchild;
}
return T;
}
}
Update-插入结点到二叉排序树中
二叉排序树作为一种动态集合,其特点是树的结构通常不是一次生成的,而是在查找过程中,当树中不存在关键字等于给定值的结点时再进行插入。
由于二叉排序树是递归定义的,其插入结点的过程是:
1)若原二叉树为空,则直接插入结点;
2)否则,若关键字k小于根结点关键字,则插入到左子树中;
3)若关键字k大于根结点关键字,则插入到右子树中。
int BST_Insert(BiTree &T, KeyType k) {
//在二叉=排序树T中插入一个关键字为k的结点
if(T == NULL) {
T = (BiTree)malloc(sizeof(BSTNode));
T->key = k;
T->lchild = T->rchild = NULL;
return 1; //返回1,表示成功
} else if(k == T-> key) { //树中存在相同关键字的结点
return 0;
} else if(k < T->key) { //插入到T的左子树中
return BST_Insert(T->lchild, k);
} else {
return BST_Insert(T->rchild, k);
}
}
由此可见,插入的新结点一定是某个叶结点。下图是向二叉树插入结点28的过程,其中虚线表示查找路径。

图2. 向二叉排序树插入结点28
Delete-删除二叉树的结点
在二叉排序树中删除一个结点时,不能把以该结点为根的子树上的结点都删除,必须把被删除结点从存储二叉排序树的链表上摘下,将因删除结点而断开的二叉链表重新链接起来,同时确保二叉排序树的性质不会丢失。
删除操作的实现过程按3种情况来处理:
1)如果被删除结点z是叶结点,则直接删除,不会破坏二叉排序树的性质。
2)若结点z只有一棵左子树或右子树,则让z的子树成为z父结点的子树,替代z的位置。
3)若结点z有左、右两棵子树,则令z的直接后继【中序第一个子女】(或直接前驱)替代z,然后从二叉排序树中删去这个直接后继【中序第一个子女】(或直接前驱),这样就转换成了第一或第二种情况。

图3. 3种情况下的删除过程
参考
[1] miao_zheng. 二叉排序树、平衡二叉树、B树&B+树、红黑树的设计动机、缺陷与应用场景[OL]. cnblogs, 2018-02-28/2020-06-20
[2] 王道论坛. 2019年数据结构考研复习指导[M].北京:电子工业出版社, 2018:153-155.
二叉排序树BST及CRUD操作的更多相关文章
- 二叉排序树(BST)创建,删除,查找操作
binary search tree,中文翻译为二叉搜索树.二叉查找树或者二叉排序树.简称为BST 一:二叉搜索树的定义 他的定义与树的定义是类似的,也是一个递归的定义: 1.要么是一棵空树 2.如果 ...
- 二叉排序树(BST)构造与应用
二叉排序树(BST)构造与应用 本文取自<数据结构与算法>(C语言版)(第三版).出版社是清华大学出版社. 本博文作为学习资料整理. 源码是VC+ ...
- 【翻译】MongoDB指南/CRUD操作(四)
[原文地址]https://docs.mongodb.com/manual/ CRUD操作(四) 1 查询方案(Query Plans) MongoDB 查询优化程序处理查询并且针对给定可利用的索引选 ...
- 【翻译】MongoDB指南/CRUD操作(三)
[原文地址]https://docs.mongodb.com/manual/ CRUD操作(三) 主要内容: 原子性和事务(Atomicity and Transactions),读隔离.一致性和新近 ...
- 【翻译】MongoDB指南/CRUD操作(二)
[原文地址]https://docs.mongodb.com/manual/ MongoDB CRUD操作(二) 主要内容: 更新文档,删除文档,批量写操作,SQL与MongoDB映射图,读隔离(读关 ...
- 【翻译】MongoDB指南/CRUD操作(一)
[原文地址]https://docs.mongodb.com/manual/ MongoDB CRUD操作(一) 主要内容:CRUD操作简介,插入文档,查询文档. CRUD操作包括创建.读取.更新和删 ...
- ASP.NET Core Web API Cassandra CRUD 操作
在本文中,我们将创建一个简单的 Web API 来实现对一个 “todo” 列表的 CRUD 操作,使用 Apache Cassandra 来存储数据,在这里不会创建 UI ,Web API 的测试将 ...
- MongoDB的CRUD操作
1. 前言 在上一篇文章中,我们介绍了MongoDB.现在,我们来看下如何在MongoDB中进行常规的CRUD操作.毕竟,作为一个存储系统,它的基本功能就是对数据进行增删改查操作. MongoDB中的 ...
- 【Java EE 学习 44】【Hibernate学习第一天】【Hibernate对单表的CRUD操作】
一.Hibernate简介 1.hibernate是对jdbc的二次开发 2.jdbc没有缓存机制,但是hibernate有. 3.hibernate的有点和缺点 (1)优点:有缓存,而且是二级缓存: ...
- 使用MyBatis对表执行CRUD操作
一.使用MyBatis对表执行CRUD操作——基于XML的实现 1.定义sql映射xml文件 userMapper.xml文件的内容如下: <?xml version="1.0&quo ...
随机推荐
- allure 报告环境搭建
1.安装 pip install allure-pytest 2.下载allure 地址: https://repo.maven.apache.org/maven2/io/qameta/allure/ ...
- 启动workman stream_socket_server() has been disabled for security reasons
启动workman报错 Workerman[start.php] start in DEBUG mode stream_socket_server() has been disabled for se ...
- PIL或Pillow学习1
PIL( Python Imaging Library)是 Python 的第三方图像处理库,由于其功能丰富,API 简洁易用,因此深受好评. 自 2011 年以来,由于 PIL 库更新缓慢,目前仅支 ...
- 如何在 Github 上获得 1000 star?
作为程序员,Github 是第一个绕不开的网站.我们每天都在上面享受着开源带来的便利,我相信很多同学也想自己做一个开源项目,从而获得大家的关注.然而,理想很丰满,现实却是开发了很久的项目仍然无人问津. ...
- SpringBoot+微信支付-JSAPI{微信支付回调}
引入微信支付SDK Maven: com.github.wechatpay-apiv3:wechatpay-java-core:0.2.12 Maven: com.github.wechatpay-a ...
- linux 根目录扩容方法
准备知识 linux volume 1.(PV)physical volume disk : 物理硬盘 物理硬盘需要转换成lvm(logic volume manage)可识别的状态,将磁盘的syst ...
- golang的条件编译
写c/c++或者rust的开发者应该对条件编译不陌生,条件编译顾名思义就是在编译时让代码中的一部分生效或者失效,从而控制编译时的代码执行路径,进而影响编译出来的程序的行为. 这有啥用呢?通常在编写跨平 ...
- study Python3【3】的函数
Python的函数定义简单,但灵活度非常大.功能强大意味复杂.为了复习,把廖雪峰老师的该课程做个回顾. 参数有:必选参数.默认参数.可变参数.关键字参数.命名关键字参数. 计算x的n次方函数: def ...
- SpringBoot启动方法分析
SpringBoot启动run方法分析 1.场景引入 在项目启动的时候,有时候我们需要在启动的时候,执行一些逻辑. 比如说,项目启动的时候,我想把一些热门商品的数据加载到缓存中去: 比如说,自定义了一 ...
- 第一次3D打印,一个简单的小方块(rhino)
一.建模 打开犀牛,我们选择立方体 我们点击上册的中心点 输入0,然后回车0 而后我们输长度:10,回车确认 同样的,宽度10 高度同样是10 回车确认后,我们得到一个正方形 二.导出模型 我们选择文 ...