• <C++>手撕搜索二叉树


    目录

    一、搜索二叉树的性质

    二、搜索二叉树的结构定义

    三、手撕搜索二叉树非递归

    1)Insert()

    2)Find()

    3)Erase()

    4)InOder()

    5)BSTree(const BSTree& t) 拷贝构造

    6)~BSTree()析构函数

    四、手撕搜索二叉树递归

    1)InsertR()

    2)FindR()

    3)EraseR()

    五、搜索二叉树完整代码


    一、搜索二叉树的性质

    • 左子树上所有的节点的值都小于根节点的值
    • 右子树上所有节点的值都大于根节点的值
    • 它的左右子树分别为二叉搜索树

    二、搜索二叉树的结构定义

    搜索二叉树主要实现的是K或K/Value模型,这里我们使用K模型来定义,即可以用O(N)的时间复杂度来进行K值的搜索。

     

    使用模板来定义

    1. template<class K>
    2. struct BSTreeNode
    3. {
    4. BSTreeNode<K>* _left;
    5. BSTreeNode<K>* _right;
    6. K _key;
    7. BSTreeNode(const K& key)
    8. :_left(nullptr)
    9. ,_right(nullptr)
    10. ,_key(key)
    11. {
    12. }
    13. };

    三、手撕搜索二叉树非递归

    1)Insert()

    插入有两种情况:

    • _root == nullptr 根节点等于空

    直接new a Node插入即可

    1. if (_root == nullptr)
    2. {
    3. _root = new Node(key);
    4. return true;
    5. }
    • _root != nullptr 根节点不等于空

    我们需要找到适合key值的空节点位置,通过搜索二叉树的性质进行排查位置

    1. Node* parent = nullptr;
    2. Node* cur = _root;
    3. while (cur)
    4. {
    5. if (cur->_key < key)
    6. {
    7. parent = cur;
    8. cur = cur->_right;
    9. }
    10. else if (cur->_key > key)
    11. {
    12. parent = cur;
    13. cur = cur->_left;
    14. }
    15. else
    16. {
    17. return false;
    18. }
    19. }
    20. //开始插入
    21. cur = new Node(key);
    22. if (parent->_key < key)
    23. {
    24. parent->_right = cur;
    25. }
    26. else
    27. {
    28. parent->_left = cur;
    29. }

     

     

     

    2)Find()

    直接通过搜索二叉树的性质就可以进行查找,当key值大于cur->_key的值时,就查找cur的右子树,key值小于cur->_key的值时,就查找cur的左子树,直到找到,或者找不到cur == nullptr结束,即逻辑和Inser中的逻辑大同小异;

    1. bool Find(const K& key)
    2. {
    3. Node* cur = _root;
    4. while (cur)
    5. {
    6. if (cur->_key < key)
    7. {
    8. cur = cur->_right;
    9. }
    10. else if (cur->_key > key)
    11. {
    12. cur = cur->_left;
    13. }
    14. else
    15. {
    16. return true;
    17. }
    18. }
    19. }

    3)Erase()

    删除分三种情况:

    • 删除节点没有孩子
    • 删除节点有一个孩子
    1. 有一个左孩子
    2. 有一个右孩子
    • 删除节点有两个孩子

    前面两种代码可以合并处理

    1. bool Erase(const K& key)
    2. {
    3. Node* parent = nullptr;
    4. Node* cur = _root;
    5. while (cur)
    6. {
    7. if (cur->_key < key)
    8. {
    9. parent = cur;
    10. cur = cur->_right;
    11. }
    12. else if (cur->_key > key)
    13. {
    14. parent = cur;
    15. cur = cur->_left;
    16. }
    17. else
    18. {
    19. //开始删除
    20. if (cur->_left == nullptr)
    21. {
    22. if (cur == _root)
    23. {
    24. _root = cur->_right;
    25. }
    26. else
    27. {
    28. if (cur == parent->_left)
    29. {
    30. parent->_left = cur->_right;
    31. }
    32. else
    33. {
    34. parent->_right = cur->_right;
    35. }
    36. }
    37. delete cur;
    38. cur = nullptr;
    39. }
    40. else if (cur->_right == nullptr)
    41. {
    42. if (cur == _root)
    43. {
    44. _root = cur->_left;
    45. }
    46. else
    47. {
    48. if (cur == parent->_left)
    49. {
    50. parent->_left = cur->_left;
    51. }
    52. else
    53. {
    54. parent->_right = cur->_left;
    55. }
    56. }
    57. delete cur;
    58. cur = nullptr;
    59. }
    60. else
    61. {
    62. Node* minParent = cur;
    63. Node* min = cur->_right;
    64. while (min->_left)
    65. {
    66. minParent = min;
    67. min = min->_left;
    68. }
    69. swap(cur->_key, min->_key);
    70. if (minParent->_left == min)
    71. {
    72. minParent->_left = min->_right;
    73. }
    74. else
    75. {
    76. minParent->_right = min->_right;
    77. }
    78. delete min;
    79. min = nullptr;
    80. }
    81. return true;
    82. }
    83. }
    84. return false;
    85. }

    4)InOder()

    使用二叉树的中序遍历--midorder traverse

    特点:

    中序遍历后的值排列是有序的

    1. void InOrder()
    2. {
    3. _InOrder(_root);
    4. return;
    5. }
    6. void _InOrder(Node* root)
    7. {
    8. if (root == nullptr)
    9. {
    10. return;
    11. }
    12. _InOrder(root->_left);
    13. cout << root->_key << " ";
    14. _InOrder(root->_right);
    15. }

    5)BSTree(const BSTree& t) 拷贝构造

    使用前序遍历构造

    1. BSTree(const BSTree<K>& t)
    2. {
    3. _Copy(t._root);
    4. }
    5. Node* _Copy(Node* root) // 使用前序遍历构造
    6. {
    7. if (root == nullptr)
    8. {
    9. return;
    10. }
    11. Node* copyRoot = new Node(root->_key);
    12. copyRoot->_left = _Copy(root->_left);
    13. copyRoot->_left = _Copy(root->_right);
    14. return copyRoot;
    15. }

    6)~BSTree()析构函数

    使用后序销毁

    1. ~BSTree()
    2. {
    3. _Destory(_root);
    4. }
    5. void _Destory(Node* root) // 使用后序销毁
    6. {
    7. if (root == nullptr)
    8. {
    9. return;
    10. }
    11. _Destory(root->_left);
    12. _Destory(root->_right);
    13. delete root;
    14. root = nullptr;
    15. }

    四、手撕搜索二叉树递归

    1)InsertR()

    1. bool InertR(const K& key)
    2. {
    3. return _InsertR(_root, key);
    4. }
    5. bool _InsertR(Node*& root, const K& key)
    6. {
    7. if (root == nullptr)
    8. {
    9. root = new Node(key);
    10. return true;
    11. }
    12. if (root->_key < key)
    13. {
    14. return _InsertR(root->_right, key);
    15. }
    16. else if (root->_key > key)
    17. {
    18. return _InsertR(root->_left, key);
    19. }
    20. else
    21. {
    22. return false;
    23. }
    24. }

    2)FindR()

    1. bool FindR(const K& key)
    2. {
    3. return _FindR(_root, key);
    4. }
    5. bool _FindR(Node* root, const K& key)
    6. {
    7. if (root == nullptr)
    8. {
    9. return false;
    10. }
    11. if (root->_key < key)
    12. {
    13. return _FindR(root->_right);
    14. }
    15. else if (root->_key > key)
    16. {
    17. return _FindR(root->_left);
    18. }
    19. else
    20. {
    21. return true;
    22. }
    23. }

    3)EraseR()

    1. bool EraseR(const K& key)
    2. {
    3. return _EraseR(_root, key);
    4. }
    5. bool _EraseR(Node*& root, const K& key)
    6. {
    7. if (root == nullptr)
    8. {
    9. return false;
    10. }
    11. if (root->_key < key)
    12. {
    13. return _EraseR(root->_right, key);
    14. }
    15. else if (root->_key > key)
    16. {
    17. return _EraseR(root->_left, key);
    18. }
    19. else
    20. {
    21. Node* del = root;
    22. if (root->_left == nullptr)
    23. {
    24. root = root->_right;
    25. }
    26. else if (root->_right == nullptr)
    27. {
    28. root = root->_left;
    29. }
    30. else
    31. {
    32. //找右数的最左节点
    33. Node* min = root->_right;
    34. while (min->_left)
    35. {
    36. min = min->_left;
    37. }
    38. swap(root->_key, min->_key);
    39. return _InserR(root->_right, key);
    40. }
    41. delete del;
    42. return true;
    43. }
    44. }

    五、搜索二叉树完整代码

    1. template<class K>
    2. struct BSTreeNode
    3. {
    4. BSTreeNode<K>* _left;
    5. BSTreeNode<K>* _right;
    6. K _key;
    7. BSTreeNode(const K& key)
    8. :_left(nullptr)
    9. ,_right(nullptr)
    10. ,_key(key)
    11. {
    12. }
    13. };
    14. template<class K>
    15. class BSTree
    16. {
    17. typedef BSTreeNode<K> Node;
    18. public:
    19. bool Insert(const K& key)
    20. {
    21. if (_root == nullptr)
    22. {
    23. _root = new Node(key);
    24. return true;
    25. }
    26. else
    27. {
    28. Node* parent = nullptr;
    29. Node* cur = _root;
    30. while (cur)
    31. {
    32. if (cur->_key < key)
    33. {
    34. parent = cur;
    35. cur = cur->_right;
    36. }
    37. else if (cur->_key > key)
    38. {
    39. parent = cur;
    40. cur = cur->_left;
    41. }
    42. else
    43. {
    44. return false;
    45. }
    46. }
    47. //开始插入
    48. cur = new Node(key);
    49. if (parent->_key < key)
    50. {
    51. parent->_right = cur;
    52. }
    53. else
    54. {
    55. parent->_left = cur;
    56. }
    57. }
    58. }
    59. void InOrder()
    60. {
    61. _InOrder(_root);
    62. return;
    63. }
    64. bool Find(const K& key)
    65. {
    66. Node* cur = _root;
    67. while (cur)
    68. {
    69. if (cur->_key < key)
    70. {
    71. cur = cur->_right;
    72. }
    73. else if (cur->_key > key)
    74. {
    75. cur = cur->_left;
    76. }
    77. else
    78. {
    79. return true;
    80. }
    81. }
    82. return false;
    83. }
    84. bool Erase(const K& key)
    85. {
    86. Node* parent = nullptr;
    87. Node* cur = _root;
    88. while (cur)
    89. {
    90. if (cur->_key < key)
    91. {
    92. parent = cur;
    93. cur = cur->_right;
    94. }
    95. else if (cur->_key > key)
    96. {
    97. parent = cur;
    98. cur = cur->_left;
    99. }
    100. else
    101. {
    102. //开始删除
    103. if (cur->_left == nullptr)
    104. {
    105. if (cur == _root)
    106. {
    107. _root = cur->_right;
    108. }
    109. else
    110. {
    111. if (cur == parent->_left)
    112. {
    113. parent->_left = cur->_right;
    114. }
    115. else
    116. {
    117. parent->_right = cur->_right;
    118. }
    119. }
    120. delete cur;
    121. cur = nullptr;
    122. }
    123. else if (cur->_right == nullptr)
    124. {
    125. if (cur == _root)
    126. {
    127. _root = cur->_left;
    128. }
    129. else
    130. {
    131. if (cur == parent->_left)
    132. {
    133. parent->_left = cur->_left;
    134. }
    135. else
    136. {
    137. parent->_right = cur->_left;
    138. }
    139. }
    140. delete cur;
    141. cur = nullptr;
    142. }
    143. else
    144. {
    145. Node* minParent = cur;
    146. Node* min = cur->_right;
    147. while (min->_left)
    148. {
    149. minparnt = min;
    150. min = min->_left;
    151. }
    152. swap(cur->_key, min->_key);
    153. if (minParent->_left == min)
    154. {
    155. minParent->_left = min->_right;
    156. }
    157. else
    158. {
    159. minParent->_right = min->_right;
    160. }
    161. delete min;
    162. min = nullptr;
    163. }
    164. return true;
    165. }
    166. }
    167. return false;
    168. }
    169. BSTree() = default;
    170. BSTree(const BSTree<K>& t)
    171. {
    172. _Copy(t._root);
    173. }
    174. ~BSTree()
    175. {
    176. _Destory(_root);
    177. }
    178. //
    179. bool FindR(const K& key)
    180. {
    181. return _FindR(_root, key);
    182. }
    183. bool InertR(const K& key)
    184. {
    185. return _InsertR(_root, key);
    186. }
    187. bool EraseR(const K& key)
    188. {
    189. return _EraseR(_root, key);
    190. }
    191. private:
    192. void _InOrder(Node* root)
    193. {
    194. if (root == nullptr)
    195. {
    196. return;
    197. }
    198. _InOrder(root->_left);
    199. cout << root->_key << " ";
    200. _InOrder(root->_right);
    201. }
    202. void _Destory(Node* root)
    203. {
    204. if (root == nullptr)
    205. {
    206. return;
    207. }
    208. _Destory(root->_left);
    209. _Destory(root->_right);
    210. delete root;
    211. root = nullptr;
    212. }
    213. Node* _Copy(Node* root)
    214. {
    215. if (root == nullptr)
    216. {
    217. return;
    218. }
    219. Node* copyRoot = new Node(root->_key);
    220. copyRoot->_left = _Copy(root->_left);
    221. copyRoot->_left = _Copy(root->_right);
    222. return copyRoot;
    223. }
    224. bool _FindR(Node* root, const K& key)
    225. {
    226. if (root == nullptr)
    227. {
    228. return false;
    229. }
    230. if (root->_key < key)
    231. {
    232. return _FindR(root->_right);
    233. }
    234. else if (root->_key > key)
    235. {
    236. return _FindR(root->_left);
    237. }
    238. else
    239. {
    240. return true;
    241. }
    242. }
    243. bool _InsertR(Node*& root, const K& key)
    244. {
    245. if (root == nullptr)
    246. {
    247. root = new Node(key);
    248. return true;
    249. }
    250. if (root->_key < key)
    251. {
    252. return _InsertR(root->_right, key);
    253. }
    254. else if (root->_key > key)
    255. {
    256. return _InsertR(root->_left, key);
    257. }
    258. else
    259. {
    260. return false;
    261. }
    262. }
    263. bool _EraseR(Node*& root, const K& key)
    264. {
    265. if (root == nullptr)
    266. {
    267. return false;
    268. }
    269. if (root->_key < key)
    270. {
    271. return _EraseR(root->_right, key);
    272. }
    273. else if (root->_key > key)
    274. {
    275. return _EraseR(root->_left, key);
    276. }
    277. else
    278. {
    279. Node* del = root;
    280. if (root->_left == nullptr)
    281. {
    282. root = root->_right;
    283. }
    284. else if (root->_right == nullptr)
    285. {
    286. root = root->_left;
    287. }
    288. else
    289. {
    290. //找右数的最左节点
    291. Node* min = root->_right;
    292. while (min->_left)
    293. {
    294. min = min->_left;
    295. }
    296. swap(root->_key, min->_key);
    297. return _InserR(root->_right, key);
    298. }
    299. delete del;
    300. return true;
    301. }
    302. }
    303. private:
    304. Node* _root = nullptr;
    305. };

  • 相关阅读:
    Vue Slot插槽:组件化的艺术
    死锁的成因和对应的解决方案
    大家一起来学习如何使用spring.factories
    你需要的导航网站,这里都有
    TS编译器选项——指定编译ES版本和模块化使用规范
    计算机学院院长第一课——前辈的经验
    Labelme安装以及使用教程
    前端面试真题
    图片链接打不开检测工具-免费链接失败检测软件
    C++算法:分发糖果
  • 原文地址:https://blog.csdn.net/weixin_63246064/article/details/128122126