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

C++——二叉搜索树

1.二叉搜索树概念

二叉搜索树(Binary Search Tree,BST) 是一种特殊的二叉树,它具有以下性质:

  1. 每个节点有一个值(通常是数字或者可以比较大小的其他数据类型)。
  2. 对于每个节点,左子树中的所有节点值都小于该节点的值,右子树中的所有节点值都大于该节点的值。
  3. 每个节点的左、右子树也都是二叉搜索树。

1.1 二叉搜索树的基本操作:

  1. 插入:从根节点开始,找到合适的位置(比当前节点小的去左子树,比当前节点大的去右子树),直到空节点处插入新节点。
  2. 查找:从根节点开始,若目标值小于当前节点值,继续在左子树查找;若目标值大于当前节点值,继续在右子树查找。
  3. 删除:有三种情况:
    1. 删除的节点是叶子节点(没有子节点):直接删除。
    2. 删除的节点有一个子节点:用该子节点替代被删除的节点。
    3. 删除的节点有两个子节点:用右子树中的最小节点或左子树中的最大节点替代被删除节点。

1.2 性能分析

  1. 时间复杂度(Time Complexity)

    • 最优情况:当树保持平衡时,每个操作的时间复杂度为O(log n),其中n是树中的节点数。
    • 最坏情况:如果树退化成一个链表(例如每次插入的值都比当前节点大或者小),那么操作的时间复杂度为O(n)。
    • 平均情况:对于随机插入的节点,树的平均高度接近log n,因此操作的时间复杂度通常是O(log n)。
  2. 空间复杂度(Space Complexity)

        二叉搜索树的空间复杂度主要取决于树的高度。对于n个节点的树,空间复杂度为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:BSTree(const BSTree<K>& t){_root = Copy(t._root);}BSTree<K>& operator=(BSTree<K> t){swap(_root, t._root);return *this;}~BSTree(){Destory(_root);_root == nullptr;}//中序遍历void InOrder(){_InOrder(_root);cout << endl;}private:void _InOrder(Node* root){if (root->_key == nullptr){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}void Destory(Node* root){if (root == nullptr){return;}Destory(root->_left);Destory(root->_right);delete(root);}Node* Copy(Node* root){if (root == nullptr){return nullptr;}Node* copy = new Node(root->_key);copy->_left = Copy(root->_left);copy->_right = Copy(root->_right);return copy;}private:Node* _root = nullptr;
};

2.1二叉搜索树的插入

在二叉搜索树中,每个节点都有一个键值。其插入操作遵循特定的规则:

  • 左子树的节点值小于根节点的值
  • 右子树的节点值大于根节点的值

过程:

  1. 如果树为空,则直接创建一个新的节点,并将其赋值给根指针 _root

  2. 如果树不为空,按照二叉搜索树的规则,若插入的值大于当前节点的值,则向右子树移动;若插入的值小于当前节点的值,则向左子树移动,直到找到一个空位来插入新节点。

  3. 如果允许插入相等的值,遇到与当前节点值相等的情况时,可以选择将其插入到右子树或左子树。这时,确保插入逻辑的一致性,避免重复值总是被插入到某一侧。

这样,我们保证插入操作能够在符合二叉搜索树规则的同时,保持树的结构合理性。

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

这段代码使用了迭代方式来插入二叉搜索树的节点,避免了递归的深度。在树的查找过程中,迭代地比较当前节点与目标值的大小,决定向左子树还是右子树递归。如果插入位置为空,则创建新的节点并将其连接到父节点。插入操作会检查是否插入重复的节点,如果有相同的键值,则返回 false,避免重复插入,并且插入操作中判断左右子树的顺序不能随意交换。

2.2二叉搜索树的查找

在二叉搜索树中,查找操作是非常高效的,因为树的结构保持了一定的排序规则:左子树所有节点的值小于当前节点的值,右子树所有节点的值大于当前节点的值。

二叉搜索树的查找过程:

  1. 比较根节点与目标值

    • 如果目标值等于当前节点的值,则查找成功。
    • 如果目标值小于当前节点的值,则继续在当前节点的左子树查找。
    • 如果目标值大于当前节点的值,则继续在当前节点的右子树查找。
  2. 时间复杂度

    • 最好的情况是树是完全平衡的,此时查找时间复杂度是 O(log n)
    • 最坏的情况是树退化成链表(例如每次插入的值都比当前节点大或小),此时查找的时间复杂度是 O(n)
bool Find(const K& key)
{Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{cout << "找到了" << endl;return true;	}}cout << "没找到了" << endl;return false;
}

2.3二叉搜索树的删除

删除过程分析:

  1. 删除叶子节点
    如果节点没有左右子树,直接将其父节点指向空,删除该节点。

  2. 删除只有一个子节点的节点
    将其父节点的指针指向它的唯一子节点,然后删除该节点。

  3. 删除有两个子节点的节点
    需要找到一个替代节点。通常我们选择右子树的最小节点(中序后继)或左子树的最大节点(中序前驱)。然后将该节点的值替换到要删除的节点,并递归删除该替代节点。

bool Erase(const K& key)
{Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{if (cur->_left == nullptr){if (cur == _root){_root = cur->_right;}else{if (cur = parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}delete cur;}}else if (cur->_right == nullptr){if (cur == _root){_root = cur->_right;}else{if (cur = parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}delete cur;}}//两个孩子else{Node* pMinRight = cur;Node* minRight = cur->_right;while (minRight->_left){pMinRight = minRight;minRight = minRight->_left;}swap(cur->_key, minRight->_key);if (pMinRight->_left = minRight){pMinRight->_left = minRight->_right;}else{pMinRight->_right = minRight->_right;}delete minRight;}return true;}}return false;
}

3.key/value搜索

每个关键码(key)都有对应的值(value),其中值(value)可以是任意类型的对象。在树的结构中,每个节点除了存储关键码(key),还需要存储与之对应的值(value)。在进行插入、删除或查找操作时,仍然遵循以关键码(key)为关键字的二叉搜索树规则,可以快速地查找到对应关键码(key)所对应的值(value)。

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:BSTree() = default;BSTree(const BSTree<K, V>& t){_root = Copy(t._root);}BSTree<K, V>& operator=(BSTree<K, V> t){swap(_root, t._root);return *this;}~BSTree(){Destory(_root);_root = nullptr;}bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node(key, value);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(key, value);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return cur;}}return nullptr;}bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{if (cur->_left == nullptr){if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}delete cur;}else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;}else{Node* pMinRight = cur;Node* minRight = cur->_right;while (minRight->_left){pMinRight = minRight;minRight = minRight->_left;}swap(cur->_key, minRight->_key);if (pMinRight->_left == minRight){pMinRight->_left = minRight->_right;}else{pMinRight->_right = minRight->_right;}delete minRight;}return true;}}return false;}void InOrder(){_InOrder(_root);cout << endl;}
private:void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}void Destory(Node* root){if (root == nullptr){return;}Destory(root->_left);Destory(root->_right);delete root;}Node* Copy(Node* root){if (root == nullptr)return nullptr;Node* copy = new Node(root->_key, root->_value);copy->_left = Copy(root->_left);copy->_right = Copy(root->_right);return copy;}private:Node* _root = nullptr;
};

http://www.dtcms.com/a/588954.html

相关文章:

  • 青少年机器人技术等级考试理论综合试卷(一级)2020年9月
  • Redis_9_Set
  • 计算机网络培训课程大庆网站建设优化
  • 网站正在建设中永久wordpress 前台文章
  • Electron 桌面应用开发入门指南:从零开始打造 Hello World
  • 深入解析手机快充技术原理与实现
  • JavaScript 数组方法大全
  • 电子商务网站建设与管理的实验报告个人怎样免费建网站
  • STM32F103学习笔记-16-RCC(第3节)-使用HSE配置系统时钟并使用MCO输出监控系统时钟
  • LeRobot 入门教程(十五)从Hub加载环境
  • HTML DOM 总结
  • 社群经济下开源链动2+1模式AI智能名片S2B2C商城小程序的信任重构机制研究
  • Git 命令大全:从基础到高级操作
  • Git_Rebase
  • 【深度学习|学习笔记】异常检测概论 — 从经典算法到深度学习(含实用 Python 示例)
  • 如何建立一个视频网站html5 手机网站页面实例
  • FlutterPlugin接口实现与插件架构设计
  • 图漾GM461-E1相机专栏
  • Flutter与鸿蒙原生MethodChannel通信机制深度解析
  • Navigation2 行为树架构源码级分析与设计原理
  • 基于时频域霍夫变换的汽车雷达互干扰抑制——论文阅读
  • 贵阳网站建设建站系统怎么找网站是由什么建的
  • 一本通网站1128题:图像模糊处理
  • DrissionPage遇到iframe
  • 基于信号分解的FMCW雷达相互干扰抑制——论文阅读
  • 未来的一些想法和规划
  • 线代强化NO3|线性方程组|特征值和特征向量|矩阵的相似性|实对称矩阵|二次型
  • K8S RD: Docker与Kubernetes运维核心技术整合指南
  • PERL Docker 容器化部署指南
  • root@lll:/data# sudo docker compose up -d 输入这个命令 控制台一直没有任何的反应 我需要如何排查呢?