二叉搜索树详解--实现插入和删除
目录
- BST树概念
- BST树操作
- BST树的查找
- BST树的插入
- BST树的删除
- 实现一个自己的BST树
- BSTNode类和BSTree类
- 查找操作;
- 插入操作:
- 删除操作:
- 应用:
- 二叉搜索树性能分析
对于普通的二叉树来说,能延伸出许多好用的数据结构,二叉搜索树(BST树)就是其中一个;
学习二叉搜索树,将为后续的AVL树与红黑树和map,set等STL容器打下坚实的基础;
BST树概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
BST树操作
BST树的查找
可以看到每步查找都能筛掉一般不符合的元素,有点类似于数组中的二分查找;
这也是二叉搜索树名字的由来,他的查找效率很高;
注意,不难发现,中序遍历BST树,就是一个升序的结构!;
BST树的插入
插入的具体过程如下:
按照二叉搜索树的性质,找到某个val合适的插入点;
BST树的删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回,
否则要删除的结点可能分下面四种情况:
- 要删除的结点无孩子结点 -->直接删除
- 要删除的结点只有左孩子 -->左孩子直接与他的父亲连接(左or右),然后删掉它
- 要删除的结点只有右孩子 -->右孩子直接与他的父亲连接(左or右),然后删掉它
- 要删除的结点左右孩子都有;–>去它的右子树找最左节点,替换它的位置 用替代法删除结点!
实现一个自己的BST树
由于一般具有k-v结构的数据结构底层是BST树,那么我们这里也实现一个K-V结构的BST树;
- K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。 比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
以单词集合中的每个单词作为key,构建一棵二叉搜索树,
在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
KV模型:每一个关键码key,**都有与之对应的值Value,**即的键值对。该种方式在现实生 活中非常常见:
比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英 文单词与其对应的中文就构成一种键值对;
再比如统计单词次数,统计成功后,给定 单词就可快速找到其出现的次数,单词与其出现次数就是就构成一种键值对。
<单词,中文含义>为键值对构造二叉搜索树,注意:二叉搜索树需要比较,键值对比较时只比较Key
查询英文单词时,只需给出英文单词,就可快速找到与其对应的key
BSTNode类和BSTree类
基本框架:
template<class K,class V>
struct BSTNode {BSTNode(const K& key = K(), const V& value = V()): _pLeft(nullptr), _pRight(nullptr), _key(key), _Value(value){}BSTNode<T>* _pLeft;BSTNode<T>* _pRight;K _key;V _value
};
template<class K, class V>
class BSTree {typedef BSTNode<K, V> Node;
private:Node* _root;
}
查找操作;
Node* Find(const K& key) {//根据BST树的特性来find;if (_root == nullptr) return nullptr;Node* cur = _root;//原则上来说 是没有重复key存在的while (cur) {if (key > cur->_key) {cur = cur->_pRight;}else if (key < cur->_key) {cur = cur->_pLeft;}else return cur;}return nullptr;}
插入操作:
bool Insert(const K& key, const V& value){if (_root == nullptr) {_root = new Node({ key,value });return true;}Node* cur = _root;Node* prev = _root;//原则上来说 是没有重复key存在的while (cur) {if (key > cur->_key) {prev = cur;cur = cur->_pRight;}else if (key < cur->_key) {prev = cur;cur = cur->_pLeft;}else return false; //数据冗余,不插入;map,set的普通版本不允许key重复!}Node* newnode = new Node({ key,value });if (prev->_key < key) {prev->_pRight = newnode;}else {prev->_pLeft = newnode;}return true;}
删除操作:
bool Erase(const K& key)
{Node* cur = _root;Node* father = nullptr;while (cur) {if (key > cur->_key) {father = cur;cur = cur->_pRight;}else if (key < cur->_key) {father = cur;cur = cur->_pLeft;}else break;}if (!cur) return false;//处理下特殊情况:需要删root节点if (father == nullptr) {Node* tmp = _root;if (father->_pRight) {_root = father->_pRight;}else if (father->_pLeft) {_root = father->_pLeft;}delete tmp;return true;}//1,无孩子节点,直接删;if (!cur->_pLeft && !cur->_pRight) {if (father->_pLeft == cur){father->_pLeft = nullptr;}else father->_pRight = nullptr;}//2,有左孩子or右孩子;else if ((!cur->_pLeft && cur->_pRight) || (cur->_pLeft && !cur->_pRight)) {if (father->_pLeft == cur) {//cur是father的左 if (cur->_pLeft) father->_pLeft = cur->_pLeft;else father->_pLeft = cur->_pRight;}else {//cur是father的右if (cur->_pLeft) father->_pRight = cur->_pLeft;else father->_pRight = cur->_pRight;}}else {//3.左右都有孩子;//替代法,找右子树最左节点替换他; 及的保存parent 替换的时候树得调整Node* p_replace = cur;Node* replace = cur->right;while (replace->_pLeft) {p_replace = replace;replace = replace->_pLeft;
; }//swap(cur, rmin);//别乱用swap 会出错;if (father->_pLeft == cur) { //注意 这个father是cur的fatherfather->_pLeft = replace;}else {father->_pRight = replace;}cur->_val = replace->_val;//交换要删除节点的值与替代节点的值,之后把replace删了 删的时候替换的时候树得调整if (p_replace->_pLeft == replace) {p_replace->_pLeft = replace->_pLeft;}else {p_replace->_pRight = replace->_pRight;}cur = replace;//改变最后删的对象}delete cur;cur = nullptr;return true;
}
应用:
//统计词语出现的次数
string strs[] = { "苹果", "西瓜", "苹果", "樱桃", "苹果", "樱桃", "苹果", "樱桃", "苹果" };// 统计水果出现的次BSTree<string, int> countTree;for (auto str : strs){auto ret = countTree.Find(str);if (ret == NULL){countTree.Insert(str, 1);}else{ret->_value++;}}countTree.InOrder();
二叉搜索树性能分析
插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的 深度的函数,即结点越深,则比较次数越多
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:log2N
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2
问题:如果退化成单支树,二叉搜索树的性能就失去了。那能否进行改进,不论按照什么次序插入关键码, 都可以是二叉搜索树的性能最佳?
AVL树!后面文章接着写
二叉搜索树详解--实现插入和删除相关推荐
- java二叉搜索树详解
文章目录 一.概念 二.相关操作 2.0节点相关代码: 2.1查找 2.2插入 2.3删除(重难点) 2.4测试用例 三.小结 提示:以下是本篇文章正文内容,下面案例可供参考 一.概念 二叉搜索树又称 ...
- 二叉堆详解实现优先级队列
二叉堆详解实现优先级队列 文章目录 二叉堆详解实现优先级队列 一.二叉堆概览 二.优先级队列概览 三.实现 swim 和 sink 四.实现 delMax 和 insert 五.最后总结 二叉堆(Bi ...
- 二叉树:二叉搜索树的创建和插入
二叉搜索树又名二叉排序树. 大概简略的思维导图如下,方便记忆特性 基本二叉搜索树创建过程如下 /*数据结构如下*/ typedef struct tree {int data;struct tree ...
- 二叉搜索树的创建、插入、遍历、删除
二叉搜索树 本文主要记录自己完成学校课程布置的有关"二叉搜索树"的代码闯关题的代码和思路心得,部分内容有借鉴身边大佬,借鉴部分会有标注. 二叉搜索树的结构体定义 struct no ...
- AVL树(二叉平衡树)详解与实现
公众号文章链接 AVL树概念 前面学习二叉查找树和二叉树的各种遍历,但是其查找效率不稳定(斜树),而二叉平衡树的用途更多.查找相比稳定很多.(欢迎关注数据结构专栏) AVL树是带有平衡条件的二叉查找树 ...
- 第七章 二叉搜索树(b3)BST:删除
转载于:https://www.cnblogs.com/ZHONGZHENHUA/p/10247191.html
- C++初阶学习————二叉树进阶(二叉搜索树)
二叉树进阶 二叉搜索树的概念 二叉搜索树的操作 基本框架 二叉搜索树的插入 二叉搜索树的查找 二叉搜索树的删除 整体代码 循环写法 递归写法 二叉搜索树的应用 二叉搜索树的性能分析 前面的文章介绍过二 ...
- C++ 第八节数据结构 第七节 ——二叉搜索树 AVL树 红黑树(底层原理图+模拟实现)
第一次,C++和数据结构联合推出,倾情献上呦~~ 给个关注吧 23333~~~~~~(现在每天系统就给我一个机器人的粉丝量了55555~~~~~) 本节内容,我们将着重来探讨 二叉树 中特殊的两种树- ...
- 二叉树进阶--二叉搜索树
目录 1.二叉搜索树 1.1 二叉搜索树概念 1.2 二叉搜索树操作 1.3 二叉搜索树的实现 1.4 二叉搜索树的应用 1.5 二叉搜索树的性能分析 2.二叉树进阶经典题: 1.二叉搜索树 1.1 ...
最新文章
- Luogu P1087 FBI树
- 参加51CTO学院软考培训,通过后感想
- 批量处理Excel文件的模块----xlwings
- kafka启动异常:kafka.common.InconsistentClusterIdException: The Cluster ID xxx
- 判断指定目录下的所有[图片]的扩展名, 并打印出文件名.
- 设计模式之静态代理模式实战
- java流与文件——内存映射文件
- Camel 2.11 –没有Spring的Camel Web应用程序
- java字节流分为_Java文件流可分为字节流和字符流。
- 微软开源InnerEye:让医学影像AI普及化
- ZOJ-1010 奇偶剪枝
- 干货 | 我如何考察面试者的机器学习水平
- 看了某LINUX打包规范,没搞明白怎么支持多CPU,自己测试过没有?
- android HandlerThread源码解析
- 数字孪生网络(DTN)架构
- 计算机桌面下方任务栏图标不见了,任务栏显示桌面图标不见怎么办
- 重启MySQL报Unit mysqld.service could not be
- 安装爱剪辑计算机丢失,爱剪辑没保存的视频怎么恢复?
- Linux系统Docker配置阿里云镜像加速器
- 【Tensorflow教程笔记】深度强化学习(DRL)