news 2026/10/26 10:17:37

【C++】搜索二叉树

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【C++】搜索二叉树

目录

1. 二叉搜索树的概念

2. 时间复杂度分析

3. 插入,查找,删除的代码实现

删除的代码实现:

4. 二叉搜索树的使用场景

1. key搜索场景

2. key / value搜索场景

5. Insert 和 Find 的递归写法(了解)


1. 二叉搜索树的概念

(1)定义

二叉搜索树(Binary Search Tree,简称 BST)是一棵二叉树,满足对任意节点:

  • 左子树中所有节点的值<该节点的值

  • 右子树中所有节点的值>该节点的值

  • 左右子树本身也都是二叉搜索树

⚠️ 注意:是比较整棵子树,不是只比较左右孩子。

(2)核心性质

  1. 中序遍历(左-根-右)结果一定是升序序列——这是 BST 最重要的性质,很多题都靠它。

  2. 一般不允许插入重复值。


2. 时间复杂度分析

最优:二叉搜索树为完全二叉树,其高度为 logN 。

最差:二叉搜索树退化为单只树,其高度为 N 。

所以二叉搜索树增删查改的时间复杂度为 O(N) 。


3. 插入,查找,删除的代码实现

插入查找的代码较简单,不做赘述。

bool Insert(const K& key) { if (_root == nullptr) { _root = new Node(key); return true; } Node* parent = nullptr; // 用于最后链接到一起 Node* cur = _root; while (cur) { if (key < cur->_key) // 要插入的值小于当前结点的值,应该插入到左子树 { parent = cur; cur = cur->_left; } else if (key > cur->_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 Find(const K& key) { Node* cur = _root; while (cur) { if (key < cur->_key) { cur = cur->_left; } else if (key > cur->_key) { cur = cur->_right; } else return true; } return false; }

删除的代码实现:

bool Erase(const K& key) { Node* parent = nullptr; Node* cur = _root; while (cur) { if (key < cur->_key) { parent = cur; cur = cur->_left; } else if(key > cur->_key) { parent = cur; cur = cur->_right; } else { if (cur->_left == nullptr) // 左为空 { if (cur == _root) { _root = _root->_right; } else { if (key < parent->_key) parent->_left = cur->_right; else parent->_right = cur->_right; } delete cur; } else if (cur->_right == nullptr) // 右为空 { if (cur == _root) { _root = _root->_left; } else { if (key < parent->_key) parent->_left = cur->_left; else parent->_right = cur->_left; } delete cur; } else // 左右均不为空 { Node* replaceparent = cur; // 不能为nullptr,因为删除的节点是根节点时 Node* replace = cur->_left; while (replace->_right) { replaceparent = replace; replace = replace->_right; } // 找到了要替换的值 swap(replace->_key, cur->_key); if (replace == replaceparent->_left) replaceparent->_left = replace->_left; else replaceparent->_right = replace->_left; delete replace; } return true; } } return false; }

思路:


4. 二叉搜索树的使用场景

1. key搜索场景

只以key作为关键码,结构中只存储key即可。

例如:检查单词是否拼写正确:将词库中的所有单词放入二叉搜索树,读取文章中的单词,查找是否存在二叉搜索树中。


2. key / value搜索场景

每一个key,都有与之对应的value。

树的结构中需要存储关键码key和对应的value。

例如:

(1)中英互译:输入英文(key),找到了对应的英文(value)

(2)统计一篇文章中某单词的出现次数:单词(key),出现次数(value)

代码举例:

template<class K,class V> struct BSTNode { BSTNode<K,V>* _left; BSTNode<K,V>* _right; K _key; V _value; BSTNode(const K& key, const V& value) :_left(nullptr) , _right(nullptr) , _key(key) , _value(value) {} }; template<class K, class V> class BST { typedef BSTNode<K, V>Node; public: BST(){} // _Destroy 和 _Copy 最好设为私有,这里为了方便观察设为公有 void _Destroy(Node* root) { if (root == nullptr) return; _Destroy(root->_left); _Destroy(root->_right); delete root; // 最好用后序遍历删除节点,否则还需额外保存孩子指针 } Node* _Copy(Node* root) { if (root == nullptr) return root; Node* copy = new Node(root->_key, root->_value); copy->_left = _Copy(root->_left); copy->_right = _Copy(root->_right); return copy; } // 拷贝构造 BST(const BST& t) { _root = _Copy(t._root); } // 析构 ~BST() { _Destroy(_root); _root = nullptr; } // 拷贝赋值 BST& operator=(BST t) { swap(t._root, _root); return *this; } 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 (key < cur->_key) { parent = cur; cur = cur->_left; } else if (key > cur->_key) { parent = cur; cur = cur->_right; } else return false; // 不允许插入重复的值 } cur = new Node(key, value); if (parent->_key > key) { parent->_left = cur; } else parent->_right = cur; return true; } Node* Find(const K& key) { Node* cur = _root; while (cur) { if (key < cur->_key) { cur = cur->_left; } else if (key > cur->_key) { cur = cur->_right; } else return cur; } return nullptr; } void InOrder() { _InOrder(_root); cout << endl; } void _InOrder(Node* root) { if (root == nullptr) { return; } _InOrder(root->_left); cout << root->_key << ":" << root->_value << endl;; _InOrder(root->_right); } bool Erase(const K& key) { Node* parent = nullptr; Node* cur = _root; while (cur) { if (key < cur->_key) { parent = cur; cur = cur->_left; } else if (key > cur->_key) { parent = cur; cur = cur->_right; } else { if (cur->_left == nullptr) // 左为空 { if (cur == _root) { _root = _root->_right; } else { if (key < parent->_key) parent->_left = cur->_right; else parent->_right = cur->_right; } delete cur; } else if (cur->_right == nullptr) // 右为空 { if (cur == _root) { _root = _root->_left; } else { if (key < parent->_key) parent->_left = cur->_left; else parent->_right = cur->_left; } delete cur; } else // 左右均不为空 { Node* replaceparent = cur; // 不能为nullptr,如果 cur->_left 本身没有右孩子,循环一次都不执行 Node* replace = cur->_left; while (replace->_right) { replaceparent = replace; replace = replace->_right; } // 找到了要替换的值 swap(replace->_key, cur->_key); if (replace == replaceparent->_left) replaceparent->_left = replace->_left; else replaceparent->_right = replace->_left; delete replace; } return true; } } return false; } private: Node* _root = nullptr; }; } ////////////////////////////////////// int main() { keyvalue::BST<string, string> dict; dict.Insert("left", "左边"); dict.Insert("right", "右边"); dict.Insert("insert", "插入"); dict.Insert("string", "字符串"); keyvalue::BST<string, string> copy = dict; copy.InOrder(); string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" }; keyvalue::BST<string, int> countTree; for (auto& str : arr) { auto ret = countTree.Find(str); if (ret == nullptr) { countTree.Insert(str, 1); } else { ret->_value++; } } countTree.InOrder(); return 0; }

5. Insert 和 Find 的递归写法(了解)

bool _InsertR(Node*& root, const K& key) { if (root == nullptr) { root = new Node(key); // 用引用,直接在当前节点上修改,不需手动链接;对它赋值 = 直接改父节点成员 = 挂上新节点。 return true; } if (root->_key > key) return _InsertR(root->_left, key); if (root->_key < key) return _InsertR(root->_right, key); else return false; } bool InsertR(const K& key) { return _InsertR(_root,key); } bool _FindR(Node* root,const K& key) { if (root == nullptr) return false; if (root->_key == key) return true; if (root->_key > key) return _FindR(root->_left, key); else return _FindR(root->_right, key); } bool FindR(const K& key) { return _FindR(_root, key); }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 10:14:07

基于机器学习的网络入侵检测系统:从NSL-KDD到实时抓包

简介&#xff1a;面向网络安全与机器学习交叉领域的Python实战项目&#xff0c;以网络入侵检测为核心任务&#xff0c;基于卷积神经网络&#xff08;CNN&#xff09;在NSL-KDD数据集上完成数据预处理、模型构建、训练与预测全流程。项目附带完整源码与项目说明文档&#xff0c;…

作者头像 李华
网站建设 2026/10/26 10:13:29

vn.py 量化交易框架完整指南:四步跑通事件驱动与 AI 选股流水线

vn.py 量化交易框架完整指南&#xff1a;四步跑通事件驱动与 AI 选股流水线 【免费下载链接】vnpy 基于Python的开源量化交易平台开发框架 项目地址: https://gitcode.com/vnpy/vnpy vn.py 是一个基于 Python 的开源量化交易框架&#xff0c;把行情接入、订单管理、数据…

作者头像 李华
网站建设 2026/10/26 10:07:56

2022德语跨保西北大学新传:三校面试、专业题与择校复盘

&#x1f4cc; 大一保研必看&#xff5c;从入学准备到推免录取的全流程攻略 绩点、英语、科研竞赛&#xff0c;先抓哪一项&#xff1f; 按大一到大三梳理准备顺序&#xff0c;讲清夏令营、预推免、申请材料和面试要点。 &#x1f449; 点击阅读完整攻略 → 2022年&#xff0c;我…

作者头像 李华