当前位置: 首页 > ops >正文

【C++高阶一】二叉搜索树

【C++高阶一】二叉搜索树剖析

  • 1.什么是二叉搜索树
  • 2.二叉搜索树非递归实现
    • 2.1插入
    • 2.2删除
      • 2.2.1删除分析一
      • 2.2.2删除分析二
    • 2.3查找
  • 3.二叉搜索树递归实现
    • 3.1插入
    • 3.2删除
    • 3.3查找
  • 4.完整代码

1.什么是二叉搜索树

任何一个节点,他的左子树的所有节点都比他小,右子树的所有节点都比他大

在这里插入图片描述

二叉搜索树是有序的,中序遍历这棵二叉搜索树刚好是升序
时间复杂度为O(N),因为会出现这种极端情况
在这里插入图片描述
二叉搜索树中不能出现值相同的节点

2.二叉搜索树非递归实现

大致框架

template<class K>
struct BSTreeNode //二叉搜索树节点
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr),_right(nullptr),_key(key){}
};template<class K>
class BSTree//二叉搜索树
{typedef BSTreeNode<K> Node;
public:private:Node* _root = nullptr;
};

2.1插入

插入的值比根大就往右走,比根小就往左走,如果遇见和插入值相同的值就返回false

bool insert(const k& key){if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(key);if (parent->_key > key){parent->_left = cur;}else {parent->_right = cur;}return true;}

parent保存每一步的父节点,在插入之后起到父子节点连接作用

2.2删除

2.2.1删除分析一

  1. 被删除节点无孩子:
    直接将此节点删除,不用做特殊处理
  2. 被删除节点只有左孩子:
    此节点被删除后,将此节点的左孩子连接到此节点的父亲节点
  3. 被删除节点只有右孩子:
    此节点被删除后,将此节点的右孩子连接到此节点的父亲节点
bool erase(const k& key)
{Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if(cur->_key > key){parent = cur;cur = cur->_right;}else//找到了{if (cur->_left == nullptr)//左孩子为空{if (cur == _root)_root = cur->_right;else{if (cur == parent->_right)parent->_right = cur->_right;elseparent->_left = cur->_right;}delete cur;}else if (cur->_right == nullptr)//右孩子为空{if (cur == _root)_root = cur->_left;else{if (cur == parent->_right)parent->_right = cur->_leftelseparent->_left = cur->_left;}delete cur;}//第四种情况 //else{}}}return false}

表面只写了两种情况,其实已经把无孩子的情况包括了

2.2.2删除分析二

当被删除的节点存在左右孩子时,我们要使用替换法
被替换的节点一定要满足一个条件:
是左子树的最大值 || 是右子树的最小值
在这里插入图片描述

假设使用右子树中最小的节点来替换,其左孩子为空,但右孩子未知,还需要分情况讨论

else//左右孩子都不为空
{//用右子树最小值来替换Node* Temp_parent = cur;//临时父节点Node* R_subtree_min = cur->_right;//右子树最小值while (R_subtree_min->_left){Temp_parent = R_subtree_min;R_subtree_min = R_subtree_min->_left;}swap(cur->_key, R_subtree_min->_key);if (R_subtree_min == Temp_parent->_left){Temp_parent->_left = R_subtree_min->_right;}else{Temp_parent->_right = R_subtree_min->_right;}delete R_subtree_min;
}

2.3查找

bool find(const K& key)
{Node* cur = _root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return true;}}return false;
}

3.二叉搜索树递归实现

递归实现全都使用了函数嵌套的方式,是为了使用_root这个定义在类中的成员变量

3.1插入

插入的基本思路一样,但递归到空时构建新节点的链接有三种方式:
1.多传一个参数,记录父节点
2.递归到空节点的上一层,比如if(root->_left==NULL) 开始构建节点
3.传引用
前两个方法和循环写法没什么区别,下面都使用传引用

bool Re_insert(const K& key)
{return _Re_insert(_root, key);
}bool _Re_insert(Node*& root, const K& key)
{if (root == nullptr){root = new Node(key);return true;}if (root->_key > key){return _Re_insert(root->_left, key);}else if (root->_key < key){return _Re_insert(root->_right, key);}else{return false;}
}

3.2删除

bool Re_erase(const K& key)
{return _Re_erase(_root, key);
}
bool _Re_erase(Node*& root, const K& key)
{if (root == nullptr)return false;if (root->_key > key){return _Re_erase(root->_left, key);}else if (root->_key < key){return _Re_erase(root->_right, key);}else//找到了,准备删除{if (root->_left == nullptr)//左孩子为空{Node* temp = root;root = root->_right;delete temp;return true;}else if (root->_right == nullptr)//右孩子为空{Node* temp = root;root = root->_left;delete temp;return true;}else//左右孩子都不为空{//找右子树的最小值Node* temp = root->_right;while (temp->_left){temp = temp->_left;}swap(root->_key, temp->_key);return _Re_erase(root->_right, key);}}
}

3.3查找

bool Re_find(const K& key)
{return _Re_find(_root, key);
}
private:
bool _Re_find(Node* root,const K& key)
{if (root == nullptr)return false;if (root->_key > kry){return _Re_find(root->_left, key);}else if (root->_key < kry){return _Re_find(root->_right, key);}else{return true;}
}

4.完整代码

template<class K>
struct BSTreeNode //二叉搜索树节点
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr),_right(nullptr),_key(key){}
};template<class K>
class BSTree//二叉搜索树
{typedef BSTreeNode<K> Node;
public:bool insert(const K& key){if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(key);if (parent->_key > key){parent->_left = cur;}else {parent->_right = cur;}return true;}bool erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if(cur->_key < key){parent = cur;cur = cur->_right;}else//找到了,准备删除{if (cur->_left == nullptr)//左孩子为空{if (cur == _root)_root = cur->_right;else{if (cur == parent->_right)parent->_right = cur->_right;elseparent->_left = cur->_right;}delete cur;}else if (cur->_right == nullptr)//右孩子为空{if (cur == _root)_root = cur->_left;else{if (cur == parent->_right)parent->_right = cur->_leftelseparent->_left = cur->_left;}delete cur;}else//左右孩子都不为空{//用右子树最小值来替换Node* Temp_parent = cur;//临时父节点Node* R_subtree_min = cur->_right;//右子树最小值while (R_subtree_min->_left){Temp_parent = R_subtree_min;R_subtree_min = R_subtree_min->_left;}swap(cur->_key, R_subtree_min->_key);if (R_subtree_min == Temp_parent->_left){Temp_parent->_left = R_subtree_min->_right;}else{Temp_parent->_right = R_subtree_min->_right;}delete R_subtree_min;}return true;}}return false;}bool find(const K& key){Node* cur = _root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return true;}}return false;}bool Re_insert(const K& key){return _Re_insert(_root, key);}bool Re_erase(const K& key){return _Re_erase(_root, key);}bool Re_find(const K& key){return _Re_find(_root, key);}
private:bool _Re_insert(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (root->_key > key){return _Re_insert(root->_left, key);}else if (root->_key < key){return _Re_insert(root->_right, key);}else{return false;}}bool _Re_erase(Node*& root, const K& key){if (root == nullptr)return false;if (root->_key > key){return _Re_erase(root->_left, key);}else if (root->_key < key){return _Re_erase(root->_right, key);}else//找到了,准备删除{if (root->_left == nullptr)//左孩子为空{Node* temp = root;root = root->_right;delete temp;return true;}else if (root->_right == nullptr)//右孩子为空{Node* temp = root;root = root->_left;delete temp;return true;}else//左右孩子都不为空{//找右子树的最小值Node* temp = root->_right;while (temp->_left){temp = temp->_left;}swap(root->_key, temp->_key);return _Re_erase(root->_right, key);}}}bool _Re_find(Node* root,const K& key){if (root == nullptr)return false;if (root->_key > kry){return _Re_find(root->_left, key);}else if (root->_key < kry){return _Re_find(root->_right, key);}else{return true;}}
private:Node* _root = nullptr;
};
http://www.xdnf.cn/news/9073.html

相关文章:

  • Speech Synthesis/Text to Speech(TTS)
  • 写给这个阶段自我的一封信
  • Solr搜索:比传统数据库强在哪?
  • 【Ai】使用Ultralytics yolo做图片检测+使用roboflow做数据标注
  • 机器学习与深度学习5:pytorch前馈神经网络FNN实现手写数字识别
  • Halcon仿射变换---个人笔记
  • PySide6 GUI 学习笔记——常用类及控件使用方法(光标类图标QCursor)
  • 918. 环形子数组的最大和
  • 消费电子卷入“技术军备竞赛”
  • shell脚本基础
  • 记忆上传与自我同一性的哲学-技术综合分析
  • AI日报 - 2025年05月26日
  • 快速了解GO之Channel 通道
  • uv ——新的python包管理工具
  • 如何在 ONLYOFFICE 演示文稿中调整段落首行缩进
  • 第10章 网络与信息安全基础知识
  • 【分治】数组中的逆序对
  • 格恩朗管段超声波流量计:流量测量先锋
  • SD-WAN与传统网络结合:轨道交通网络优化的高效实践与深度解析
  • Day37打卡 @浙大疏锦行
  • 数据库入门:以商品订单系统为例
  • Nuxt.js vs Next.js:Vue 与 React 阵营的 SSR 双雄对比
  • python25-递归算法
  • 人工智能第一币AISPF,首发BitMart交易所
  • P5734 【深基6.例6】文字处理软件
  • Netty学习专栏(六):深度解析Netty核心参数——从参数配置到生产级优化
  • Lines of Thought in Large Language Models
  • (10)-java+ selenium->元素之By class name
  • window 显示驱动开发-Direct3D 呈现性能改进(一)
  • P1068 [NOIP 2009 普及组] 分数线划定