• 【数据结构】二叉搜索树


    目录

    一、二叉搜索树

    ⭐1.1 二叉搜索树的概念

    ⭐1.2 二叉搜索树具有的性质:

    ⭐ 二、二叉搜索树的相关操作

    ⭐2.1二叉搜索树的节点的类型

    ⭐2.2二叉搜索树的查找(非递归)

    ⭐ 2.3二叉搜索树的查找(递归)

    ⭐2.4二叉搜索树的插入(非递归)

    ⭐2.5二叉搜索树的插入(递归)

    ⭐2.6二叉搜索树的删除(非递归)

    ⭐2.7二叉搜索树的删除(递归)

    ⭐2.8二叉搜索树的遍历

    ⭐2.9二叉树的拷贝构造及构造,赋值重载

    ⭐三、二叉搜索树的全部代码


    一、二叉搜索树

    ⭐1.1 二叉搜索树的概念

    二叉搜索树又称二叉排序树,是一种特殊有序的二叉树。

    ⭐1.2 二叉搜索树具有的性质:

    • 左子树不为空时,左子树所有节点的值都小于根节点的值
    • 右子树不为空时,右子树所有节点的值都大于根节点的值
    • 当然它的左右子树也满足该性质

    d5cc776e54e64213a80051f8edf149a1.png

    ⭐ 二、二叉搜索树的相关操作

    ①二叉搜索树的查找

    ②二叉搜索树的插入

    ③二叉搜索树的删除

    ⭐2.1二叉搜索树的节点的类型

    1. template <class K>//类模板
    2. struct BSTNode
    3. {
    4. BSTNode* left;
    5. BSTNode* right;
    6. K _key;
    7. BSTNode(K key)
    8. :left(nullptr)
    9. , right(nullptr)
    10. , _key(key)
    11. {}
    12. };

    ⭐2.2二叉搜索树的查找(非递归

    从根开始查找,如果要查找的值比根节点大就往右子树走,如果比根节点小就往左子树走,依次循环,直到找到或走到空,则结束。找到则返回true,找不到返回false。

     

    1. bool find(const K& key)
    2. {
    3. BSTNode* cur = _root;
    4. while (cur)
    5. {
    6. if (cur->_key == key)
    7. return true;
    8. else if (cur->_key < key)
    9. cur = cur->right;
    10. else
    11. cur = cur->left;
    12. }
    13. return false;
    14. }

    ⭐ 2.3二叉搜索树的查找(递归)

    思路和非递归是一样的,如果查找的节点为空表示该树中没有该节点,返回false,如果找到了就返回true

    1. bool _findR(BSTNode* root, const K& key)
    2. {
    3. if (!root)return false;
    4. if (root->_key == key)
    5. return true;
    6. else if (root->_key > key)
    7. return _findR(root->left, key);//往左子树走
    8. else
    9. return _findR(root->right, key);//往右子树走
    10. }

    ⭐2.4二叉搜索树的插入(非递归)

    判断树是否为空,如果树为空的话,那么直接新增一个节点,并把该节点的地址赋给_root指针(指向根节点的指针)。如果树不为空,那么就按照二叉搜索树的查找方法,找到插入的位置,然后将新节点插入。注意:如果相等那么将返回false,不能插入

     

    1. bool insert(const K& key)
    2. {
    3. if (_root == nullptr)
    4. {
    5. _root= new BSTNode(key);
    6. return true;
    7. }
    8. BSTNode* cur = _root, *parent=nullptr;
    9. while (cur)
    10. {
    11. if (_root->_key < key)
    12. {
    13. parent = cur;
    14. cur = cur->right;
    15. }
    16. else if (_root->_key > key)
    17. {
    18. parent = cur;
    19. cur = cur->left;
    20. }
    21. else
    22. return false;
    23. }
    24. BSTNode* newnode = new BSTNode(key);
    25. if (parent->_key < key)
    26. { //插入的节点大于该插入位置的父节点,往右边插入
    27. parent->right = newnode;
    28. }
    29. else
    30. { //插入的节点小于该插入位置的父节点,往左边插入
    31. parent->left = newnode;
    32. }
    33. return true;
    34. }

    ⭐2.5二叉搜索树的插入(递归)

    这里传的是引用,形参的改变可以影响实参,所以直接给root赋值了

    1. bool _InsertR(BSTNode*& root, const K& key)
    2. { //如果根节点为空,直接把值赋给root
    3. if (!root)
    4. BSTNode* root = new BSTNode(key);
    5. if (root->_key > key)
    6. {
    7. return _InsertR(root->left, key);
    8. }
    9. else if (root->_key < key)
    10. {
    11. return _InsertR(root->right, key);
    12. }
    13. else
    14. return false;
    15. }

    ⭐2.6二叉搜索树的删除(非递归)

    首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情
    况:

    1.  要删除的结点无孩子结点
    2.  要删除的结点只有左孩子结点
    3.  要删除的结点只有右孩子结点
    4.  要删除的结点有左、右孩子结点

    看起来有待删除节点有4种情况,实际情况1可以与情况2或者3合并起来,因此真正的删除过程
    如下:

    • 情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除
    • 情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除
    • 情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除
    1. bool Erase(const K& key)
    2. {
    3. BSTNode* cur = _root, * parent =nullptr;
    4. while (cur)
    5. {
    6. if (cur->_key < key)
    7. {
    8. parent = cur;
    9. cur = cur->right;
    10. }
    11. else if (cur->_key > key)
    12. {
    13. parent = cur;
    14. cur = cur->left;
    15. }
    16. else
    17. { //没有左孩子节点
    18. if (cur->left == nullptr)
    19. {
    20. if (parent == nullptr)
    21. {
    22. _root = _root->right;
    23. }
    24. else if (parent->left == cur)
    25. {
    26. parent->left = cur->right;
    27. }
    28. else
    29. {
    30. parent->right = cur->right;
    31. }
    32. delete cur;
    33. }
    34. //没有右孩子节点
    35. else if (cur->right == nullptr)
    36. {
    37. if (parent == nullptr)
    38. {
    39. _root = _root->right;
    40. }
    41. else if (parent->left == cur)
    42. {
    43. parent->left = cur->left;
    44. }
    45. else
    46. {
    47. parent->right = cur->left;
    48. }
    49. delete cur;
    50. }
    51. //左右孩子都有的节点
    52. else
    53. {
    54. BSTNode*minparent = cur;
    55. BSTNode* minright = cur->right;
    56. while (minright->left)
    57. {
    58. minparent = minright;
    59. minright = minright->left;
    60. }
    61. swap(minright->_key, cur->_key);
    62. if (minparent->left = minright)
    63. {
    64. minparent->left = minright->right;
    65. }
    66. else
    67. {
    68. minparent->right = minright->right;
    69. }
    70. delete minright;
    71. }
    72. }
    73. return true;
    74. }
    75. return false;
    76. }

    ⭐2.7二叉搜索树的删除(递归)

    1. bool _EraseR(BSTNode*& root, const K& key)//传引用
    2. {
    3. if (!root)return false;
    4. if (root->_key == key)
    5. {
    6. BSTNode* del = root;
    7. // 删除
    8. if (root->left == nullptr)
    9. {
    10. root = root->right;
    11. }
    12. else if (root->right == nullptr)
    13. {
    14. root = root->left;
    15. }
    16. else
    17. {
    18. BSTNode* minRight = root->right;
    19. while (minRight->left)
    20. {
    21. minRight = minRight->left;
    22. }
    23. swap(root->_key, minRight->_key);
    24. //交换完以后继续递归删除
    25. return _EraseR(root->right, key);
    26. }
    27. delete del;
    28. return true;
    29. }
    30. else if (root->_key > key)
    31. return _EraseR(root->left, key);
    32. else
    33. return _EraseR(root->right, key);
    34. }

    ⭐2.8二叉搜索树的遍历

    当创建好二叉搜索树后,我们需要知道自己的相关操作对不对,所以需要遍历二叉搜索树来验证,

    那什么遍历方式好呢?这里选的是中序遍历,因为二叉搜索树左边都是小于根节点的,右边都是大于根节点的,所以使用中序遍历可以得到一个呈升序的序列

    1. void _Inorder(BSTNode* root)
    2. {
    3. if (!root)return;
    4. _Inorder(root->left);
    5. cout << root->_key << ' ';
    6. _Inorder(root->right);
    7. }

    ⭐2.9二叉树的拷贝构造及构造,赋值重载

    1. //C++11支持的编译器强制生成默认构造函数
    2. //BST() = default;
    3. BST()//构造
    4. {}
    5. BSTNode* CopyTree( BSTNode* root)
    6. {
    7. if (root == nullptr)
    8. return nullptr;
    9. BSTNode* copyNode = new BSTNode(root->_key);
    10. copyNode->_left = CopyTree(root->_left);
    11. copyNode->_right = CopyTree(root->_right);
    12. return copyNode;
    13. }
    14. BST(const BST& bst)//拷贝构造
    15. {
    16. _root = CopyTree(bst);
    17. }
    18. BST& operator=(const BST bst)//赋值重载
    19. {
    20. swap(_root, bst._root);
    21. return *this;
    22. }

    ⭐三、二叉搜索树的全部代码

    1. #pragma once
    2. #include
    3. using namespace std;
    4. template <class K>
    5. struct BSTNode
    6. {
    7. BSTNode* left;
    8. BSTNode* right;
    9. K _key;
    10. BSTNode(K key)
    11. :left(nullptr)
    12. , right(nullptr)
    13. , _key(key)
    14. {}
    15. };
    16. template <class K>
    17. class BST
    18. {
    19. public:
    20. //C++11支持的编译器强制生成默认构造函数
    21. //BST() = default;
    22. BST()
    23. {}
    24. BSTNode* CopyTree( BSTNode* root)
    25. {
    26. if (root == nullptr)
    27. return nullptr;
    28. BSTNode* copyNode = new BSTNode(root->_key);
    29. copyNode->_left = CopyTree(root->_left);
    30. copyNode->_right = CopyTree(root->_right);
    31. return copyNode;
    32. }
    33. BST(const BST& bst)
    34. {
    35. _root = CopyTree(bst);
    36. }
    37. BST& operator=(const BST bst)
    38. {
    39. swap(_root, bst._root);
    40. return *this;
    41. }
    42. bool find(const K& key)
    43. {
    44. BSTNode* cur = _root;
    45. while (cur)
    46. {
    47. if (cur->_key == key)
    48. return true;
    49. else if (cur->_key < key)
    50. cur = cur->right;
    51. else
    52. cur = cur->left;
    53. }
    54. return false;
    55. }
    56. bool insert(const K& key)
    57. {
    58. if (_root == nullptr)
    59. {
    60. _root= new BSTNode(key);
    61. return true;
    62. }
    63. BSTNode* cur = _root, *parent=nullptr;
    64. while (cur)
    65. {
    66. if (_root->_key < key)
    67. {
    68. parent = cur;
    69. cur = cur->right;
    70. }
    71. else if (_root->_key > key)
    72. {
    73. parent = cur;
    74. cur = cur->left;
    75. }
    76. else
    77. return false;
    78. }
    79. BSTNode* newnode = new BSTNode(key);
    80. if (parent->_key < key)
    81. {
    82. parent->right = newnode;
    83. }
    84. else
    85. parent->left = newnode;
    86. return true;
    87. }
    88. bool Erase(const K& key)
    89. {
    90. BSTNode* cur = _root, * parent =nullptr;
    91. while (cur)
    92. {
    93. if (cur->_key < key)
    94. {
    95. parent = cur;
    96. cur = cur->right;
    97. }
    98. else if (cur->_key > key)
    99. {
    100. parent = cur;
    101. cur = cur->left;
    102. }
    103. else
    104. {
    105. if (cur->left == nullptr)
    106. {
    107. if (parent == nullptr)
    108. {
    109. _root = _root->right;
    110. }
    111. else if (parent->left == cur)
    112. {
    113. parent->left = cur->right;
    114. }
    115. else
    116. {
    117. parent->right = cur->right;
    118. }
    119. delete cur;
    120. }
    121. else if (cur->right == nullptr)
    122. {
    123. if (parent == nullptr)
    124. {
    125. _root = _root->right;
    126. }
    127. else if (parent->left == cur)
    128. {
    129. parent->left = cur->left;
    130. }
    131. else
    132. {
    133. parent->right = cur->left;
    134. }
    135. delete cur;
    136. }
    137. else
    138. {
    139. BSTNode*minparent = cur;
    140. BSTNode* minright = cur->right;
    141. while (minright->left)
    142. {
    143. minparent = minright;
    144. minright = minright->left;
    145. }
    146. swap(minright->_key, cur->_key);
    147. if (minparent->left = minright)
    148. {
    149. minparent->left = minright->right;
    150. }
    151. else
    152. {
    153. minparent->right = minright->right;
    154. }
    155. delete minright;
    156. }
    157. }
    158. return true;
    159. }
    160. return false;
    161. }
    162. void Inorder()
    163. {
    164. _Inorder(_root);
    165. cout << endl;
    166. }
    167. bool findR(const K& key)
    168. {
    169. return _findR(_root, key);
    170. }
    171. bool InsertR(const K& key)
    172. {
    173. return _InsertR(_root, key);
    174. }
    175. bool EraseR(const K& key)
    176. {
    177. return _EraseR(_root, key);
    178. }
    179. private:
    180. void _Inorder(BSTNode* root)
    181. {
    182. if (!root)return;
    183. _Inorder(root->left);
    184. cout << root->_key << ' ';
    185. _Inorder(root->right);
    186. }
    187. bool _findR(BSTNode* root, const K& key)
    188. {
    189. if (!root)return false;
    190. if (root->_key == key)
    191. return true;
    192. else if (root->_key > key)
    193. return _findR(root->left, key);
    194. else
    195. return _findR(root->right, key);
    196. }
    197. bool _InsertR(BSTNode*& root, const K& key)
    198. {
    199. if (!root)
    200. BSTNode* root = new BSTNode(key);
    201. if (root->_key > key)
    202. {
    203. return _InsertR(root->left, key);
    204. }
    205. else if (root->_key < key)
    206. {
    207. return _InsertR(root->right, key);
    208. }
    209. else
    210. return false;
    211. }
    212. bool _EraseR(BSTNode*& root, const K& key)
    213. {
    214. if (!root)return false;
    215. if (root->_key == key)
    216. {
    217. BSTNode* del = root;
    218. // 删除
    219. if (root->left == nullptr)
    220. {
    221. root = root->right;
    222. }
    223. else if (root->right == nullptr)
    224. {
    225. root = root->left;
    226. }
    227. else
    228. {
    229. BSTNode* minRight = root->right;
    230. while (minRight->left)
    231. {
    232. minRight = minRight->left;
    233. }
    234. swap(root->_key, minRight->_key);
    235. return _EraseR(root->right, key);
    236. }
    237. delete del;
    238. return true;
    239. }
    240. else if (root->_key > key)
    241. return _EraseR(root->left, key);
    242. else
    243. return _EraseR(root->right, key);
    244. }
    245. BSTNode* _root = nullptr;
    246. };

    二叉搜索树的知识就分享到这里了,有什么错误还望指出。

  • 相关阅读:
    水果店圈子:水果店水果都去哪进货,水果店进货怎么找货源
    Docker_基础知识
    c++ 学习 之 继承中静态成员函数和静态成员变量
    基于51单片机交通灯仿真_紧急开关+黄灯倒计时+可调时间(proteus+代码+报告+讲解视频)
    DFS 无向图欧拉路径
    基于stm32单片机的输入捕获测量脉宽Proteus仿真
    【MySQL】 Java的JDBC编程
    【历史上的今天】7 月 30 日:现代电视先驱诞生;以太坊启动;80 年代最畅销的电脑品牌
    CV+Deep Learning——网络架构Pytorch复现系列——classification(三:MobileNet,ShuffleNet)
    【Hello Linux】多路转接之 epoll
  • 原文地址:https://blog.csdn.net/m0_72532428/article/details/130694757