• C++ 之二叉搜索树


    目录

    学习目标:

    1.二叉搜索树

    1.1二叉搜索树的概念

     1.2二叉搜索树的操作

    1.二叉搜索树的查找

    2.二叉树的插入

    3.二叉树的删除*

    2.二叉搜索树的实现

    3.二叉树性能分析



    1.二叉搜索树

    1.1二叉搜索树的概念

    二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

    若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

    若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

    它的左右子树也分别为二叉搜索树

     1.2二叉搜索树的操作

    1.二叉搜索树的查找

    我们根据二叉树的性质可以知道,每棵树的左子树上的节点的值都小于根,右子树上的节点的值都大于根所以我们可以这样查找

    a.从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。

    b、最多查找高度次,走到到空,还没找到,这个值不存在

    2.二叉树的插入

    a. 树为空,则直接新增节点,赋值给root指针

    b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

     

    3.二叉树的删除*

    二叉树的删除分为四种情况:

    1.要删除的节点 为叶子节点,这一种我们直接删除,没有任何影响

    2.要删除的节点 的左子树为空,这个时候我们需要记录一下要删除节点的父节点,让他的父节点来继承它的子树

    3.要删除的节点 的右子树为空,这个时候我们需要记录一下要删除节点的父节点,让他的父节点来继承它的子树

    4.要删除的节点 左右子树都不为空,这种情况最为麻烦,我们可以使用替换删除法

    找到要删除节点的右子树的最左节点或者 左子树的左右节点,替换删除的节点,并记录cur的父节点。

    代码如下:

    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. if (cur->_left == nullptr)//左子树为空
    20. {
    21. if (cur == _root)
    22. {
    23. _root = cur->_right;
    24. }
    25. else
    26. {
    27. if (cur == parent->_right)
    28. {
    29. parent->_right = cur->_right;
    30. }
    31. else
    32. {
    33. parent->_left = cur->_right;
    34. }
    35. }
    36. delete cur;
    37. return true;
    38. }
    39. else if (cur->_right == nullptr)//右子树为空
    40. {
    41. if (cur == _root)
    42. {
    43. _root = cur->_left;
    44. }
    45. else
    46. {
    47. if (cur == parent->_right)
    48. {
    49. parent->_right = cur->_left;
    50. }
    51. else
    52. {
    53. parent->_left = cur->_left;
    54. }
    55. }
    56. delete cur;
    57. return true;
    58. }
    59. else //左右子树都为空的情况 用右子树的最左节点替代
    60. {
    61. // 替换法
    62. Node* rightMinParent = cur;//不初始化为空是为了防止删除根结点
    63. Node* rightMin = cur->_right;
    64. while (rightMin->_left)
    65. {
    66. rightMinParent = rightMin;
    67. rightMin = rightMin->_left;
    68. }
    69. cur->_key = rightMin->_key;
    70. if (rightMin == rightMinParent->_left)//被替换的节点的父节点来继承左右子树
    71. rightMinParent->_left = rightMin->_right;
    72. else
    73. rightMinParent->_right = rightMin->_right;
    74. delete rightMin;
    75. return true;
    76. }
    77. }
    78. }
    79. return false;
    80. }

    2.二叉搜索树的实现

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

    3.二叉树性能分析

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

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

     

    如果二叉树成为了单支树,搜索和查找效率就会变得非常差。

  • 相关阅读:
    甬矽电子在科创板上市:市值达到122亿元,王顺波为实际控制人
    linux查看端口是否开放
    如何修复 HTML 中的乱码
    Java8 Stream流式操作接口详解
    作图从此不求人,代谢组学宝藏作图能力提升班你来不来?
    DVWA通关攻略零到一【全】
    OpenGL纹理转换谜团:纹理写入FRAMEBUFFER后的镜像现象
    贝锐蒲公英异地组网方案,如何阻断网络安全威胁?
    【数据结构与算法】- 图(算法)
    cuda和cuDNN的安装
  • 原文地址:https://blog.csdn.net/qq_74732628/article/details/138163984