• 二叉搜索树的实现


    目录

    1.二叉搜索树概念

    2.二叉树插入的实现 

    3. 二叉搜索树的查找

    4.二叉树的删除

     5.二叉搜索树的应用

    5.1 K模型

    5.2 KV模型


    1.二叉搜索树概念

    若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
    若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
    它的左右子树也分别为二叉搜索树
    例如:

    2.二叉树插入的实现 

    如何插入?

    1. 如果树为空,直接插入。
    2. 如果树不为空,则将要插入的值与二叉树中各结点的值比较,最后再插入

    例如:

     代码实现:

    先创建一个结构体存储每个结点的信息:

    1. template<class K>
    2. struct BSTreeNode
    3. {
    4. BSTreeNode* _left;
    5. BSTreeNode* _right;
    6. K _key;
    7. BSTreeNode(const K& key)
    8. :_left(nullptr)
    9. , _right(nullptr)
    10. , _key(key)
    11. {}
    12. };
    1. template<class K>
    2. class BSTree
    3. {
    4. typedef BSTreeNode Node;
    5. public:
    6. bool _InsertR(const K& key)
    7. {
    8. return _InsertR(_root, key);
    9. }
    10. private
    11. bool _InsertR(Node*& root, const K& key)
    12. {
    13. if (root == nullptr)
    14. {
    15. root = new Node(key);
    16. return true;
    17. }
    18. if (key > root->_key)
    19. {
    20. return _InsertR(root->_right, key);
    21. }
    22. else if (key < root->_key)
    23. {
    24. return _InsertR(root->_left, key);
    25. }
    26. else//不允许存在相同的值
    27. return false;
    28. }
    29. }
    root是父亲结点的左右指针的引用,修改root也就是修改父亲结点的左右指针,

    3. 二叉搜索树的查找

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

    4.二叉树的删除

    二叉树的删除可分为两种情况。

    1. 1.要删除的结点只有一个孩子或无孩子。
    2. 2.要删除的结点有两个孩子。

    例如:

    1.  第一种情况:
    2. 1.删除4
    3. 2.删除10
    4. 第二种情况:
    5. 1.删除3;在它的右子树中寻找中序下的第一个结点(关键码最小,也就是最左结点),用它的值填补到被删除
    6. 节点中,再来处理该结点的删除问题--替换法删除
    1. bool _EraseR(Node*& root, const K& key)//root是父亲结点左右指针的引用
    2. {
    3. if (root == nullptr)
    4. return false;
    5. if (root->_key < key)
    6. {
    7. return _EraseR(root->_right, key);
    8. }
    9. else if (root->_key > key)
    10. {
    11. return _EraseR(root->_left, key);
    12. }
    13. else//先找到要删除的结点
    14. {
    15. Node* del = root;
    16. if (root->_left == nullptr)
    17. {
    18. root = root->_right;
    19. }
    20. else if (root->_right == nullptr)
    21. {
    22. root = root->_left;
    23. }
    24. else
    25. {
    26. Node* minRight = root->_right;//找到被删删除结点的右孩子,minRight
    27. while (minRight->_left)//以minRight为根,找到最左的孩子。
    28. {
    29. minRight = minRight->_left;
    30. }
    31. swap(root->_key, minRight->_key);//将被删出的结点与最左孩子值替换。
    32. return _EraseR(root->_right, key);//此时被删除的结点在之前最左孩子的位置,它
    33. 无左孩子,转换成了第一种情况对其删除。
    34. }
    35. delete del;
    36. return true;
    37. }
    38. }

     画图分析:

     完整代码:

    1. template<class K>
    2. struct BSTreeNode
    3. {
    4. BSTreeNode* _left;
    5. BSTreeNode* _right;
    6. K _key;
    7. BSTreeNode(const K& key)
    8. :_left(nullptr)
    9. , _right(nullptr)
    10. , _key(key)
    11. {}
    12. };
    13. template<class K>
    14. class BSTree
    15. {
    16. typedef BSTreeNode Node;
    17. private:
    18. void DestoryTree(Node* root)
    19. {
    20. if (root == nullptr)
    21. return;
    22. DestoryTree(root->_left);
    23. DestoryTree(root->_right);
    24. delete root;
    25. }
    26. Node* CopyTree(Node* root)
    27. {
    28. if (root == nullptr)
    29. return nullptr;
    30. Node* copyNode = new Node(root->_key);
    31. copyNode->_left = CopyTree(root->_left);
    32. copyNode->_right = CopyTree(root->_right);
    33. return copyNode;
    34. }
    35. public:
    36. // 强制编译器自己生成构造,C++11支持
    37. BSTree() = default;
    38. BSTree(const BSTree& t)//写了拷贝构造,不会默认生成构造函数
    39. {
    40. _root = CopyTree(t._root);
    41. }
    42. BSTree& operator=(BSTree t)
    43. {
    44. swap(_root, t._root);
    45. return *this;
    46. }
    47. ~BSTree()
    48. {
    49. DestoryTree(_root);
    50. _root = nullptr;
    51. }
    52. bool _FindR(const K& key)
    53. {
    54. return _FindR(_root, key);
    55. }
    56. bool _InsertR(const K& key)
    57. {
    58. return _InsertR(_root, key);
    59. }
    60. bool _EraseR(const K& key)
    61. {
    62. return _EraseR(_root, key);
    63. }
    64. void InOrder()
    65. {
    66. _InOrder(_root);
    67. }
    68. private:
    69. bool _EraseR(Node*& root, const K& key)
    70. {
    71. if (root == nullptr)
    72. return false;
    73. if (root->_key < key)
    74. {
    75. return _EraseR(root->_right, key);
    76. }
    77. else if (root->_key > key)
    78. {
    79. return _EraseR(root->_left, key);
    80. }
    81. else
    82. {
    83. Node* del = root;
    84. if (root->_left == nullptr)
    85. {
    86. root = root->_right;
    87. }
    88. else if (root->_right == nullptr)
    89. {
    90. root = root->_left;
    91. }
    92. else
    93. {
    94. Node* minRight = root->_right;
    95. while (minRight->_left)
    96. {
    97. minRight = minRight->_left;
    98. }
    99. swap(root->_key, minRight->_key);
    100. return _EraseR(root->_right, key);
    101. }
    102. delete del;
    103. return true;
    104. }
    105. }
    106. bool _InsertR(Node*& root, const K& key)
    107. {
    108. if (root == nullptr)
    109. {
    110. root = new Node(key);
    111. return true;
    112. }
    113. if (key > root->_key)
    114. {
    115. return _InsertR(root->_right, key);
    116. }
    117. else if (key < root->_key)
    118. {
    119. return _InsertR(root->_left, key);
    120. }
    121. else
    122. return false;
    123. }
    124. bool _FindR(Node* root, const K& key)
    125. {
    126. if (root == nullptr)
    127. return false;
    128. if (root->_key < key)
    129. {
    130. return _FindR(root->_right, key);
    131. }
    132. else if (root->_key > key)
    133. {
    134. return _FindR(root->_left, key);
    135. }
    136. else
    137. {
    138. return true;
    139. }
    140. }
    141. void _InOrder(Node* root)
    142. {
    143. if (root == nullptr)
    144. return;
    145. _InOrder(root->_left);
    146. cout << root->_key << " ";
    147. _InOrder(root->_right);
    148. }
    149. private:
    150. Node* _root = nullptr;
    151. };

     5.二叉搜索树的应用

    5.1 K模型

    K 模型即只有 key 作为关键码,结构中只需要存储 Key 即可,关键码即为需要搜索到
    比如: 给一个单词 word ,判断该单词是否拼写正确 ,具体方式如下:
    以词库中所有单词集合中的每个单词作为 key ,构建一棵二叉搜索树
    在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误

    5.2 KV模型

    每一个关键码 key ,都有与之对应的值 Value ,即 的键值对
    比如:
    英汉词典就是英文与中文的对应关系 ,通过英文可以快速找到与其对应的中文,英
    文单词与其对应的中文 就构成一种键值对;
    或者统计单词等的次数,若存在,则把value的值+1;
    对上面代码进行改进,来运用KV模型。
    下面展示需要更改的部分
    1. template<class K, class V>
    2. struct BSTreeNode
    3. {
    4. BSTreeNode* _left;
    5. BSTreeNode* _right;
    6. const K _key;
    7. V _value;
    8. BSTreeNode(const K& key, const V& value)
    9. :_left(nullptr)
    10. , _right(nullptr)
    11. , _key(key)
    12. , _value(value)
    13. {}
    14. };
    1. template<class K, class V>
    2. class BSTree
    3. {
    4. typedef BSTreeNode Node;
    5. public:
    6. void InOrder()
    7. {
    8. _InOrder(_root);
    9. cout << endl;
    10. }
    11. Node* FindR(const K& key)//返回结点的指针,可对结点内容进行修改
    12. {
    13. return _FindR(_root, key);
    14. }
    15. bool InsertR(const K& key, const V& value)
    16. {
    17. return _InsertR(_root, key, value);
    18. }
    19. private:
    20. bool _InsertR(Node*& root, const K& key, const V& value)
    21. {
    22. if (root == nullptr)
    23. {
    24. root = new Node(key, value);
    25. return true;
    26. }
    27. if (root->_key < key)
    28. return _InsertR(root->_right, key, value);
    29. else if (root->_key > key)
    30. return _InsertR(root->_left, key, value);
    31. else
    32. return false;
    33. }
    34. Node* _FindR(Node* root, const K& key)
    35. {
    36. if (root == nullptr)
    37. return nullptr;
    38. if (root->_key < key)
    39. {
    40. return _FindR(root->_right, key);
    41. }
    42. else if (root->_key > key)
    43. {
    44. return _FindR(root->_left, key);
    45. }
    46. else
    47. {
    48. return root;
    49. }
    50. }
    51. void _InOrder(Node* root)
    52. {
    53. if (root == nullptr)
    54. return;
    55. _InOrder(root->_left);
    56. cout << root->_key << ":" << root->_value << endl;
    57. _InOrder(root->_right);
    58. }
    59. private:
    60. Node* _root = nullptr;
    61. };

    例如:

    1. void test2()
    2. {
    3. string arr[] = { "香蕉","苹果","梨","桃子","梨","香蕉","黄瓜" };
    4. BSTree<string, int> p;
    5. for (auto ch : arr)
    6. {
    7. auto ret = p.FindR(ch);
    8. if (ret==nullptr)
    9. {
    10. p.InsertR(ch, 1);
    11. }
    12. else
    13. {
    14. ret->_value++;
    15. }
    16. }
    17. p.InOrder();
    18. }
    19. int main()
    20. {
    21. test2();
    22. return 0;
    23. }

    结果:

    1. 黄瓜:1
    2. 梨:2
    3. 苹果:1
    4. 桃子:1
    5. 香蕉:2

  • 相关阅读:
    学习java第一百一十三天
    实验五 模块、包和库
    从最初的月薪 23K 涨到了年薪65W,真像做梦一样……
    Javaer 面试必背系列!超高频八股之三色标记法
    PTA C 1050 螺旋矩阵(思路与优化)
    卧兔观察:决心有了,就让拼多多飞一会儿吧
    人工智能轨道交通行业周刊-第15期(2022.9.19-9.25)
    golang的切片使用总结一
    【python】py文件全自动打包成spec文件
    安卓APP(1)——安卓工程构建和第一APP运行
  • 原文地址:https://blog.csdn.net/m0_64397669/article/details/126081453