• 什么是二叉搜索树
  • 二叉搜索树的性能分析
  • 模拟实现搜索二叉树
    • 插入操作
    • 查找
    • 删除节点
    • 二叉搜索树的遍历
    • 完整代码

什么是二叉搜索树

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树


如图所示二叉树就是二叉搜索树。

二叉搜索树的性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。

但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:log₂N
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2\

二叉树的中序遍历就是一个升序遍历

模拟实现搜索二叉树

给二叉树的每一个节点加上kv模型,即每一个节点有两个值,key和value,存储和查找根据key值来操作,使用时可以根据key值找到对应的value值,类似于字典,每一个词语对应一个单词。这里我们为每一个节点都加上kv

插入操作

插入的步骤,从根节点往下遍历,要插入的节点的k值大于根节点则遍历右子树,否则遍历左子树(搜索二叉树里面没有重复值),直到遍历到空,则为插入位置。遍历时要定义prev保存前驱节点方便插入。

新插入一个k值为3的节点的过程

代码实现:

bool Insert(const K& key, const V& value) {Node* cur = _root;Node* prev = _root;while (cur) {if (cur->_key == key) {//遍历树,树中已经有对应值,插入失败返回falsereturn false;}if (key < cur->_key) {//当前节点的key > 要插入的key,遍历左子树prev = cur;cur = cur->_left;}else {//否则遍历右子树prev = cur;cur = cur->_right;}}Node* newNode = new Node(key, value);//创建新的节点if (!prev) {//当前树为空树,直接插入_root = newNode;}else {if (prev->_key > newNode->_key) {//插入对应位置prev->_left = newNode;}else {prev->_right = newNode;}}return true;}

查找

查找相对简单,遍历树,等于根节点直接返回,大于向右查找,小于向左查找,遍历结束没有找到返回空

代码实现

Node* Find(const K& key) {Node* cur = _root;while (cur) {if (key == cur->_key) {//找到对应节点,返回该节点return cur;}else if (key < cur->_key) {//当前节点的key > 要查找的key,到左子树中找cur = cur->_left;}else {//否则到右子树中找cur = cur->_right;}}return nullptr;}

删除节点

删除节点比较复杂需要考虑两种情况:
第一种要删除的节点为叶子节点或者只有一个孩子

假设现在要删除key值为4的节点,我们可以删除他,然后让父亲节点原来指向4的域指向4的孩子(4只有一个孩子,叶子节点的孩子为空),这样就完成了删除操作。

删除后2的right域指向key值为3的节点。

第二种情况:要删除的节点的左右孩子存在

假设要删除key值为8的节点,删除8号节点以后则左子树与右子树都没有了父亲节点,所以要从他们俩里面找出一个可以替代父亲节点的节点,根据二叉搜索树的性质可得,符合条件的节点就是左子树的最大节点或者右子树的最小节点满足。但是直接删除父亲节点在让新的节点旋转至父亲节点的位置戴杰过高,所以我们可以先找到符合条件的节点,然后将各节点的值赋值到要删除的节点上,在删除原来的节点(符合条件的节点不会有两个孩子,删除该节点可复用第一种方法),这样就逻辑上删除了目标节点。


左子树符合要求的节点为7,则将7赋值到8,然后删除原来位置的7号节点。

代码实现:

bool Erase(const K& key) {Node* cur = _root;Node* parent = _root;while (cur) {if (key == cur->_key) {//找到要删除的节点if (cur->_left && cur->_right) {//要删除的节点有左右两个孩子Node* max = cur->_left;//找到左树的最大节点while (max->_right) {max = max->_right;}cur->_key = max->_key;//将左树最大节点的值复制到当前节点cur->_left = deleteNode(cur->_left, cur->_key);//删除左树最大节点(左树最大节点不可能有两个孩子)return true;}else {//要删除地节点为叶子节点或只有一个孩子if (cur->_key == _root->_key) {//若要删除地节点为根节点,则更新根节点_root = _root->_left ? _root->_left : _root->_right;delete cur;}else if (cur->_left) {//否则更新父亲节点cur->_key > parent->_key ? parent->_right = cur->_left : parent->_left = cur->_left;delete cur;}else {cur->_key > parent->_key ? parent->_right = cur->_right : parent->_left = cur->_right;delete cur;}return true;}}if (key < cur->_key) {//寻找要删除的节点parent = cur;cur = cur->_left;}else {parent = cur;cur = cur->_right;}}return false;}

二叉搜索树的遍历

中序遍历为升序遍历,直接递归遍历即可

void _InOrder(Node* root) {if (root == nullptr) {return;}_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}void InOrder() {_InOrder(_root);}

完整代码

#pragma once
#include <iostream>
#include <string>
using namespace std;template<class K, class V>
struct BSTreeNode
{BSTreeNode<K, V>* _left;BSTreeNode<K, V>* _right;K _key;V _value;BSTreeNode(const K& key, const V& value):_left(nullptr), _right(nullptr), _key(key), _value(value){}
};template<class K, class V>
class BSTree
{typedef BSTreeNode<K, V> Node;
public:bool Insert(const K& key, const V& value) {Node* cur = _root;Node* prev = _root;while (cur) {if (cur->_key == key) {//遍历树,树中已经有对应值,插入失败返回falsereturn false;}if (key < cur->_key) {//当前节点的key > 要插入的key,遍历左子树prev = cur;cur = cur->_left;}else {//否则遍历右子树prev = cur;cur = cur->_right;}}Node* newNode = new Node(key, value);//创建新的节点if (!prev) {//当前树为空树,直接插入_root = newNode;}else {if (prev->_key > newNode->_key) {//插入对应位置prev->_left = newNode;}else {prev->_right = newNode;}}return true;}Node* Find(const K& key) {Node* cur = _root;while (cur) {if (key == cur->_key) {//找到对应节点,返回该节点return cur;}else if (key < cur->_key) {//当前节点的key > 要查找的key,到左子树中找cur = cur->_left;}else {//否则到右子树中找cur = cur->_right;}}return nullptr;}bool Erase(const K& key) {Node* cur = _root;Node* parent = _root;while (cur) {if (key == cur->_key) {//找到要删除的节点if (cur->_left && cur->_right) {//要删除的节点有左右两个孩子Node* max = cur->_left;//找到左树的最大节点while (max->_right) {max = max->_right;}cur->_key = max->_key;//将左树最大节点的值复制到当前节点cur->_left = deleteNode(cur->_left, cur->_key);//删除左树最大节点(左树最大节点不可能有两个孩子)return true;}else {//要删除地节点为叶子节点或只有一个孩子if (cur->_key == _root->_key) {//若要删除地节点为根节点,则更新根节点_root = _root->_left ? _root->_left : _root->_right;delete cur;}else if (cur->_left) {//否则更新父亲节点cur->_key > parent->_key ? parent->_right = cur->_left : parent->_left = cur->_left;delete cur;}else {cur->_key > parent->_key ? parent->_right = cur->_right : parent->_left = cur->_right;delete cur;}return true;}}if (key < cur->_key) {//寻找要删除的节点parent = cur;cur = cur->_left;}else {parent = cur;cur = cur->_right;}}return false;}void _InOrder(Node* root) {if (root == nullptr) {return;}_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}void InOrder() {_InOrder(_root);}
private:Node* _root = nullptr;
};

二叉搜索树(kv模型)的模拟实现相关推荐

  1. Boring Homework 二叉搜索树的打印,模拟

    写了好长时间,注意递归的使用,思路一定要清晰. 还有注意的地方:打印的时候一定要先打印到缓存buffer中,然后再输出到屏幕上面. #include <bits/stdc++.h> usi ...

  2. C++ 第八节数据结构 第七节 ——二叉搜索树 AVL树 红黑树(底层原理图+模拟实现)

    第一次,C++和数据结构联合推出,倾情献上呦~~ 给个关注吧 23333~~~~~~(现在每天系统就给我一个机器人的粉丝量了55555~~~~~) 本节内容,我们将着重来探讨 二叉树 中特殊的两种树- ...

  3. 中级C++:二叉搜索树、key-Value模型

    文章目录 二叉搜索树的特征 搜索树的添加 搜索树的遍历打印 搜索树的查找 搜索二叉树的删除 递归版本 递归插入 递归查找 递归删除 接口总览 key-Value 模型 基建 key-Value的添加 ...

  4. 【C++进阶:二叉树进阶】二叉搜索树的操作和key模型、key/value模型的实现 | 二叉搜索树的应用 | 二叉搜索树的性能分析

    [写在前面] 从这里开始 C++ 的语法就告一段落了.二叉树在前面的数据结构和算法初阶中就讲过,本文取名为二叉树进阶是因为: 二叉树进阶有着承上启下的作用,承上就是借助二叉搜索树,对二叉树初阶部分进行 ...

  5. 数组模拟二叉搜索树(二叉排序树)

    文章目录 1. 二叉搜索树的定义 2. 二叉搜索树经典模板 2.1 插入操作(建树操作) 2.2 删除操作 2.3 查询二叉搜索树中值为 w 的前驱/后继数值 3. 经典例题 1. 二叉搜索树的定义 ...

  6. 二叉树进阶--二叉搜索树

    目录 1.二叉搜索树 1.1 二叉搜索树概念 1.2 二叉搜索树操作 1.3 二叉搜索树的实现 1.4 二叉搜索树的应用 1.5 二叉搜索树的性能分析 2.二叉树进阶经典题: 1.二叉搜索树 1.1 ...

  7. 【C++】二叉搜索树解析

    二叉搜索树 概念 二叉搜索树的概念(特征) 二叉搜索树的性能分析 操作 查找 插入 删除 模拟实现 搜索二叉树类的构建 查找操作实现 插入操作实现 删除操作实现 递归版本 二叉搜索树的应用 K模型 K ...

  8. 【C++】二叉搜索树

    目录 一.二叉搜索树概念 1.概念 2.结构 3.性质 二.二叉搜索树模拟实现 1.二叉搜索树节点 2.二叉搜索树构造函数 3.二叉搜索树查找 (1)迭代版本 (2)递归版本 4.二叉搜索树插入 (1 ...

  9. 【C++】二叉树进阶(二叉搜索树)

    文章目录 前言 1.二叉搜索树 1-1. 二叉搜索树概念 2.二叉搜索树操作 2-1.树和节点的基本框架 2-2.二叉搜索树的查找 2-3.中序遍历 2-4.二叉搜索树的插入 2-5.二叉搜索树的删除 ...

  10. 高级数据结构与算法 | 二叉搜索树(Binary Search Tree)

    文章目录 二叉搜索树的概念 二叉搜索树的作用 排序 查找 实现思路 查找 插入 删除 删除.拷贝等 代码实现 K模型 KV模型 二叉搜索树的概念 二叉搜索树又叫做二叉排序树,他是一个具有以下特性的二叉 ...

最新文章

  1. 突然就懵了!面试官问我:线程池中多余的线程是如何回收的?
  2. Inversion Sequence(csu 1555)
  3. 岗位推荐 | 深圳大学胡瑞珍博士组招收计算机图形学访问硕士/博士
  4. 常用Jquery前端操作
  5. Spark实战之读写HBase
  6. hdu3526(最小费用流)
  7. Spring(1)-IOC
  8. ktor HTTP API 练习
  9. java 弹弹堂源码_弹弹堂s应用宝版下载
  10. 02325《计算机系统结构》自考复习重点目录
  11. PHP语言之MySQL操作
  12. 斗鱼显示弹幕服务器连接失败,斗鱼看不到弹幕的解决方法步骤
  13. html5仿ios底部菜单栏,仿苹果电脑任务栏菜单
  14. 【CSS 字体 属性(Font)】
  15. 声纹识别数据:让疫情期间的“闻声识人”更安全
  16. 常见负载均衡服务器介绍
  17. 区块链自由意志数据隐私安全
  18. 基于区域生长的图像分割算法!
  19. [raspberry]树莓派无线鼠标延迟问题
  20. echarts 日历图calender

热门文章

  1. java流分类_什么是流分类-JAVA中什么是流?流经常按照哪几种方式分类,每种方式又将流各分? 爱问知识人...
  2. select函数使用细节
  3. python中控脚本_python连接中控考勤机分析数据
  4. 【转】AB实验设计思路及实验落地 ABtest不平衡
  5. 被动语态 动词的过去分词
  6. 2020年Java面试题(3年的工作总结)
  7. 如何Diskgenius将U盘分区
  8. 计算机主机中的硬件组成部分,电脑的硬件组成部分及其作用各是什么
  9. cocos2d js 别出白线游戏上线
  10. GDI+ 绘制曲线方法总结