• 高阶数据结构:二叉搜索树


    本篇主要是在初级数据结构中介绍的二叉树的提升,了解二叉搜索树的特性。


    文章目录

    • 一、二叉搜索树的概念
    • 二、二叉搜索树操作
      • 1、二叉搜索树的查找
      • 2、二叉搜索树的插入
      • 3、二叉搜索树的删除
    • 三、二叉搜索树的实现
    • 四、二叉搜索树的应用
    • 五、关于二叉树进阶面试题


    一、二叉搜索树概念

    概念:二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下特征:

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

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

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

    如果所示:


    二、二叉搜索树的操作

    1.二叉搜索树的查找

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

    2.二叉树的插入

    1. bool Insert(const K& key)
    2. {
    3. //如果此时根结点不存在需要创建根结点
    4. if (_root == nullptr)
    5. {
    6. _root = new Node(key);
    7. return true;
    8. }
    9. //插入新结点的时候需要将父类的节点进行连接
    10. Node* parent = nullptr;
    11. Node* cur = _root;
    12. while (cur)
    13. {
    14. if (cur->_key < key)
    15. {
    16. parent = cur;
    17. cur = cur->_right;
    18. }
    19. else if (cur->_key > key)
    20. {
    21. parent = cur;
    22. cur = cur->_left;
    23. }
    24. else
    25. {
    26. return false;
    27. }
    28. }
    29. cur = new Node(key);
    30. if (parent->key < key)
    31. parent->_right = cur;
    32. else
    33. parent->_left = cur;
    34. return true;
    35. }

     3.二叉树的删除

    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. //左为空
    21. //右为空
    22. //左右都不为空
    23. //这里需要考虑根节点的情况
    24. if (cur->left == nullptr)
    25. {
    26. if (cur->_left == nullptr)
    27. {
    28. if (cur == _root)
    29. {
    30. _root = cur->_right;
    31. }
    32. else
    33. {
    34. if (cur == parent->_left)
    35. parent->left = cur->_right;
    36. else
    37. parent->_right = cur->right;
    38. }
    39. }
    40. delete cur;
    41. cur = nullptr;
    42. }
    43. else if (cur->_right == nullptr)
    44. {
    45. if (_root == cur)
    46. _root = cur->_left;
    47. else
    48. {
    49. if (cur == parent->_left)
    50. parent->_left = cur->_left;
    51. else
    52. parent->_right = cur->_left;
    53. }
    54. delete cur;
    55. cur = nullptr;
    56. }
    57. else
    58. {
    59. //找到右子树最小节点进行替换
    60. Node* minParent = cur;
    61. Node* min = cur->_right;
    62. while (min->_left)
    63. {
    64. minParent = min;
    65. min = min->_left;
    66. }
    67. swap(cur->_key, min->_key);
    68. if (minParent->_left == min)
    69. minParent->_left = min->_right;
    70. else
    71. minParent->_right = min->_right;
    72. delete min;
    73. }
    74. return true;
    75. }
    76. return false;
    77. }
    78. }

     三、二叉搜索树的实现

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

    四、二叉搜索树的应用

    1.K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到

    的值

    2.KV模型:每一个关键码key,都有与之对应的值Value,即的键值对

     五、关于二叉树进阶面试题

    1.根据二叉树创建字符串OJ链接


    1. /**
    2. * Definition for a binary tree node.
    3. * struct TreeNode {
    4. * int val;
    5. * TreeNode *left;
    6. * TreeNode *right;
    7. * TreeNode() : val(0), left(nullptr), right(nullptr) {}
    8. * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    9. * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
    10. * };
    11. */
    12. class Solution {
    13. public:
    14. string tree2str(TreeNode* root) {
    15. if(root==nullptr)
    16. return string();
    17. string str;
    18. str+=to_string(root->val);
    19. //如果左子树不为空或者左右子树都不为空,左边需要加括号
    20. if(root->left||root->right)
    21. {
    22. str+='(';
    23. str+=tree2str(root->left);
    24. str+=')';
    25. }
    26. //右边如果不为空,右边需要加括号
    27. if(root->right)
    28. {
    29. str+='(';
    30. str+=tree2str(root->right);
    31. str+=')';
    32. }
    33. return str;
    34. }
    35. };

     2.二叉树的层序遍历OJ链接

     

    1. /**
    2. * Definition for a binary tree node.
    3. * struct TreeNode {
    4. * int val;
    5. * TreeNode *left;
    6. * TreeNode *right;
    7. * TreeNode() : val(0), left(nullptr), right(nullptr) {}
    8. * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    9. * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
    10. * };
    11. */
    12. class Solution {
    13. public:
    14. vectorint>> levelOrder(TreeNode* root) {
    15. //如果此时二叉树为空,则返回vector>的匿名对象
    16. if(root==nullptr)
    17. return vectorint>>();
    18. //利用队列先进先出的特性进行判断
    19. queue q;
    20. //利用二维数组来保存当前没一层的节点
    21. vectorint>> vv;
    22. int levelSize=1;//每一行的节点数
    23. q.push(root);//将此时的根节点如队
    24. while(!q.empty())//如果队列不为空就继续
    25. {
    26. vector<int> v;
    27. for(int i=0;i
    28. {
    29. TreeNode*front=q.front();//将队列的第一个数据保存然后出队
    30. q.pop();
    31. v.push_back(front->val);
    32. if(front->left)
    33. q.push(front->left);
    34. if(front->right)
    35. q.push(front->right);
    36. }
    37. levelSize=q.size();//将此时队列中的个数求出来
    38. vv.push_back(v);
    39. }
    40. return vv;
    41. }
    42. };

    3.二叉树的层序遍历IIOJ链接

     

    1. /**
    2. * Definition for a binary tree node.
    3. * struct TreeNode {
    4. * int val;
    5. * TreeNode *left;
    6. * TreeNode *right;
    7. * TreeNode() : val(0), left(nullptr), right(nullptr) {}
    8. * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    9. * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
    10. * };
    11. */
    12. class Solution {
    13. public:
    14. vectorint>> levelOrderBottom(TreeNode* root) {
    15. //如果此时二叉树为空,则返回vector>的匿名对象
    16. if(root==nullptr)
    17. return vectorint>>();
    18. //利用队列先进先出的特性进行判断
    19. queue q;
    20. //利用二维数组来保存当前没一层的节点
    21. vectorint>> vv;
    22. int levelSize=1;//每一行的节点数
    23. q.push(root);//将此时的根节点如队
    24. while(!q.empty())//如果队列不为空就继续
    25. {
    26. vector<int> v;
    27. for(int i=0;i
    28. {
    29. TreeNode*front=q.front();//将队列的第一个数据保存然后出队
    30. q.pop();
    31. v.push_back(front->val);
    32. if(front->left)
    33. q.push(front->left);
    34. if(front->right)
    35. q.push(front->right);
    36. }
    37. levelSize=q.size();//将此时队列中的个数求出来
    38. vv.push_back(v);
    39. }
    40. reverse(vv.begin(),vv.end());
    41. return vv;
    42. }
    43. };

    4.二叉树的最近公共祖先 OJ链接

     

    1. /**
    2. * Definition for a binary tree node.
    3. * struct TreeNode {
    4. * int val;
    5. * TreeNode *left;
    6. * TreeNode *right;
    7. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    8. * };
    9. */
    10. class Solution {
    11. public:
    12. bool Find(TreeNode*root,TreeNode*x,stack&path)
    13. {
    14. if(root==nullptr) return false;
    15. path.push(root);
    16. if(root==x) return true;
    17. //如果没有找到从左子树开始找,如果没找到去右子树中找,如果都没有找到此时需要将所有的当前节点需要进行出栈的操作
    18. if(Find(root->left,x,path)) return true;
    19. if(Find(root->right,x,path)) return true;
    20. path.pop();
    21. return false;
    22. }
    23. TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    24. if(root==nullptr) return nullptr;
    25. //利用DFS来保存每一次搜索的路径
    26. stack pPath,qPath;
    27. Find(root,p,pPath);
    28. Find(root,q,qPath);
    29. //根据求两个链表公共节点的策略来求出二叉树中两个节点的最近的公共祖先的问题
    30. while(pPath.size()!=qPath.size())
    31. {
    32. if(pPath.size()>qPath.size()) pPath.pop();
    33. else qPath.pop();
    34. }
    35. while(pPath.top()!=qPath.top())
    36. {
    37. pPath.pop();
    38. qPath.pop();
    39. }
    40. return pPath.top();
    41. }
    42. };

    5.二叉搜索树与双向链表 OJ链接

     

    1. /*
    2. struct TreeNode {
    3. int val;
    4. struct TreeNode *left;
    5. struct TreeNode *right;
    6. TreeNode(int x) :
    7. val(x), left(NULL), right(NULL) {
    8. }
    9. };*/
    10. class Solution {
    11. public:
    12. void InOrderConvert(TreeNode*cur,TreeNode*&prev)
    13. {
    14. if(cur==nullptr) return;
    15. //先找出左子树
    16. InOrderConvert(cur->left,prev);
    17. cur->left=prev;
    18. if(prev)
    19. prev->right=cur;
    20. prev=cur;
    21. InOrderConvert(cur->right,prev);
    22. }
    23. TreeNode* Convert(TreeNode* pRootOfTree) {
    24. TreeNode*prev=nullptr;
    25. InOrderConvert(pRootOfTree,prev);
    26. while(pRootOfTree&&pRootOfTree->left)
    27. pRootOfTree=pRootOfTree->left;
    28. return pRootOfTree;
    29. }
    30. };

     6.从前序与中序遍历序列构造二叉树OJ链接

    1. /**
    2. * Definition for a binary tree node.
    3. * struct TreeNode {
    4. * int val;
    5. * TreeNode *left;
    6. * TreeNode *right;
    7. * TreeNode() : val(0), left(nullptr), right(nullptr) {}
    8. * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    9. * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
    10. * };
    11. */
    12. class Solution {
    13. public:
    14. //利用前序来创建树,中序来分割区间
    15. TreeNode*buildTreeHelper(vector<int>&preorder,vector<int>&inorder,int& prei,int inbegin,int inend)//这里previ需要利用引用,因为下一次递归prei会发生改变
    16. {
    17. if(inbegin>inend) return nullptr;
    18. TreeNode*root=new TreeNode(preorder[prei++]);
    19. //将中序的区间进行划分
    20. int ini=inbegin;
    21. while(ini<=inend)
    22. {
    23. if(inorder[ini]==root->val) break;
    24. else ++ini;
    25. }
    26. //利用分治法的思想继续分割左右区间
    27. root->left=buildTreeHelper(preorder,inorder,prei,inbegin,ini-1);
    28. root->right=buildTreeHelper(preorder,inorder,prei,ini+1,inend);
    29. return root;
    30. }
    31. TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    32. int i=0;
    33. return buildTreeHelper(preorder,inorder,i,0,inorder.size()-1);
    34. }
    35. };

     

    7.二叉树的前序遍历OJ链接

     

     

    1. /**
    2. * Definition for a binary tree node.
    3. * struct TreeNode {
    4. * int val;
    5. * TreeNode *left;
    6. * TreeNode *right;
    7. * TreeNode() : val(0), left(nullptr), right(nullptr) {}
    8. * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    9. * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
    10. * };
    11. */
    12. class Solution {
    13. public:
    14. vector<int> preorderTraversal(TreeNode* root) {
    15. if(root==nullptr)
    16. return vector<int>();
    17. vector<int> v;
    18. stack st;
    19. TreeNode*cur=root;
    20. while(cur||!st.empty())
    21. {
    22. //左路节点入栈
    23. while(cur)
    24. {
    25. v.push_back(cur->val);
    26. st.push(cur);
    27. cur=cur->left;
    28. }
    29. //右路节点的右子树
    30. TreeNode*top=st.top();
    31. st.pop();
    32. cur=top->right;
    33. }
    34. return v;
    35. }
    36. };

    8.二叉树的中序遍历OJ链接

     

    1. /**
    2. * Definition for a binary tree node.
    3. * struct TreeNode {
    4. * int val;
    5. * TreeNode *left;
    6. * TreeNode *right;
    7. * TreeNode() : val(0), left(nullptr), right(nullptr) {}
    8. * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    9. * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
    10. * };
    11. */
    12. class Solution {
    13. public:
    14. vector<int> inorderTraversal(TreeNode* root) {
    15. if(root==nullptr) return vector<int>();
    16. TreeNode*cur=root;
    17. stack st;
    18. vector<int> v;
    19. while(cur||!st.empty())
    20. {
    21. while(cur)
    22. {
    23. st.push(cur);
    24. cur=cur->left;
    25. }
    26. TreeNode*top=st.top();
    27. v.push_back(top->val);
    28. st.pop();
    29. cur=top->right;
    30. }
    31. return v;
    32. }
    33. };

    9.二叉树的后序遍历OJ链接

     

    1. /**
    2. * Definition for a binary tree node.
    3. * struct TreeNode {
    4. * int val;
    5. * TreeNode *left;
    6. * TreeNode *right;
    7. * TreeNode() : val(0), left(nullptr), right(nullptr) {}
    8. * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    9. * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
    10. * };
    11. */
    12. class Solution {
    13. public:
    14. vector<int> postorderTraversal(TreeNode* root) {
    15. if(root==nullptr) return vector<int>();
    16. TreeNode*cur=root;
    17. TreeNode*prev=nullptr;
    18. vector<int> v;
    19. stack st;
    20. //一个节点不为空的情况下:
    21. //右子树没有访问,访问右子树
    22. //右子树已经访问过了,访问根节点
    23. while(cur||!st.empty())
    24. {
    25. //左路节点入栈
    26. while(cur)
    27. {
    28. st.push(cur);
    29. cur=cur->left;
    30. }
    31. TreeNode*top=st.top();
    32. //右路节点
    33. //如果右为空或者没有访问过
    34. if(top->right==nullptr||top->right==prev)
    35. {
    36. v.push_back(top->val);
    37. prev=top;
    38. st.pop();
    39. }
    40. else
    41. {
    42. cur=top->right;
    43. }
    44. }
    45. return v;
    46. }
    47. };

  • 相关阅读:
    用于语义线检测的深度霍夫变换
    java计算机毕业设计考勤管理系统源码+mysql数据库+系统+lw文档+部署
    Zabbix 5.0部署(centos7+server+MySQL+Apache)
    【开源】JAVA+Vue.js实现大学计算机课程管理平台
    熹微~~~基于Vue开发的昏暗风格的响应式网页!
    【人体骨骼点】算法综述
    第二部分—C语言提高篇_11. 预处理
    【SQL屠夫系列】- 高频面试之SQL计算用户留存率
    数据库innodb使用redo log数据恢复原理
    FFmpeg命令行工具-实用命令
  • 原文地址:https://blog.csdn.net/qq_67458830/article/details/126860284