[关闭]
@Lin-- 2020-02-15T10:18:30.000000Z 字数 10813 阅读 235

二叉搜索树

DataStruct


零、定义:

每个节点至多有两个孩子,且左孩子的值小于自己,右孩子的值大于自己。

  1. struct BST{
  2. int value;
  3. struct BST * right;
  4. struct BST * left;
  5. };

一、创建结点

  1. //build a binary tree (root)
  2. struct BST* BuildBSTNode(int v)
  3. {
  4. struct BST* node=(struct BST *)malloc(sizeof(struct BST));
  5. node->value=v;
  6. node->left=NULL;
  7. node->right=NULL;
  8. return node;
  9. }

二、在树中插入已有结点

  1. //insert BSTNode
  2. void InsertBSTNode(struct BST * root,struct BST * node)
  3. {
  4. if(node->value<root->value&&root->left==NULL)
  5. {root->left=node;}
  6. if(node->value>root->value&&root->right==NULL)
  7. {root->right=node;}
  8. if(node->value<root->value&&root->left!=NULL)
  9. {InsertBSTNode(root->left,node);}
  10. if(node->value>root->value&&root->right!=NULL)
  11. {InsertBSTNode(root->right,node);}
  12. }

三、寻找结点

  1. //Find a Node whether in a tree
  2. bool FindNode(struct BST *root,int v)
  3. {
  4. if(root==NULL){return false;}
  5. if(v==root->value)
  6. {return true;}
  7. else if(v<root->value)
  8. {return FindNode(root->left,v);}
  9. else
  10. {return FindNode(root->right,v);}
  11. }

四、寻找父节点

  1. //Find a node's parent in a tree
  2. struct BST * FindParent(struct BST * root,int v)
  3. {
  4. if(root->value==v){return NULL;}
  5. if(v<root->value)
  6. {
  7. if(v==root->left->value){return root;}
  8. else{return FindParent(root->left,v);}
  9. }
  10. else
  11. {
  12. if(v==root->right->value){return root;}
  13. else{return FindParent(root->right,v);}
  14. }
  15. }

五、删除结点

结点有三种情况:

1.没有孩子

直接删除

  1. //结点为叶子结点,左右子树为空。直接删除
  2. if(pre->left==NULL&&pre->right==NULL)
  3. {
  4. if(parent->left!=NULL&&parent->left->value==v)
  5. {
  6. free(parent->left);parent->left=NULL;
  7. free(pre);
  8. pre=NULL;
  9. }
  10. else
  11. {
  12. free(parent->right);parent->right=NULL;
  13. free(pre);
  14. pre=NULL;
  15. }
  16. }

2.有单子结点

将其父节点指向待删结点的指针,指向待删结点的单子

  1. //左子树为空,右子树不空。将该节点的父节点连接其右子树
  2. else if(pre->left==NULL&&pre->right!=NULL)
  3. {
  4. //该节点是父亲节点的左子树
  5. if(parent->left->value==v)
  6. {
  7. parent->left=pre->right;
  8. free(pre);pre=NULL;
  9. }
  10. //该节点是父节点的右子树
  11. else
  12. {
  13. parent->right=pre->right;
  14. free(pre);pre=NULL;
  15. }
  16. }
  17. //右子树为空,左子树不空。将该节点的父节点连接其左子树
  18. else if(pre->left!=NULL&&pre->right==NULL)
  19. {
  20. //该节点是父亲节点的左子树
  21. if(parent->left->value==v)
  22. {
  23. parent->left=pre->left;
  24. free(pre);pre=NULL;
  25. }
  26. //该节点是父节点的右子树
  27. else
  28. {
  29. parent->right=pre->left;
  30. free(pre);pre=NULL;
  31. }
  32. }

3.有双子结点

自己的值替换成右子树中,最小的值(最左边那个结点),然后将那个被替代的结点删除。

  1. //左右子树都不空,取右子树中最左的结点代替后删除
  2. else
  3. {
  4. struct BST * temp=&(*pre->right),* tempparent=&(*pre);
  5. //找到最左的结点
  6. while(temp->left!=NULL)
  7. {tempparent=temp;temp=temp->left;}
  8. //最左结点是叶子结点
  9. if(temp->right==NULL)
  10. {
  11. pre->value=temp->value;//替换到待删结点
  12. free(pre->right);pre->right=NULL;
  13. free(temp);temp=NULL;
  14. }
  15. //若最左结点还有右子树
  16. else
  17. {
  18. pre->value=temp->value;
  19. if(tempparent->value==pre->value)
  20. {pre->right=temp->right;free(temp);temp=NULL;}
  21. else
  22. {
  23. tempparent->left=temp->right;
  24. free(temp);temp=NULL;
  25. }
  26. }
  27. }

删除操作完整函数

  1. //delete a node in a tree
  2. bool DeleteNode(struct BST *parent,struct BST *pre,int v)
  3. {
  4. //找不到被删结点
  5. if(pre==NULL){return false;}
  6. //找得到或还没找到
  7. else
  8. {
  9. //待删结点小于当前节点,树往左走
  10. if(v<pre->value)
  11. {
  12. return DeleteNode(&(*pre),(&*pre)->left,v);
  13. }
  14. //待删结点大于当前节点,树往右走
  15. else if(v>pre->value)
  16. {
  17. return DeleteNode(&(*pre),(&*pre)->right,v);
  18. }
  19. //找到待删结点
  20. else
  21. {
  22. //结点为叶子结点,左右子树为空。直接删除
  23. if(pre->left==NULL&&pre->right==NULL)
  24. {
  25. if(parent->left!=NULL&&parent->left->value==v)
  26. {
  27. free(parent->left);parent->left=NULL;
  28. free(pre);
  29. pre=NULL;
  30. }
  31. else
  32. {
  33. free(parent->right);parent->right=NULL;
  34. free(pre);
  35. pre=NULL;
  36. }
  37. }
  38. //左子树为空,右子树不空。将该节点的父节点连接其右子树
  39. else if(pre->left==NULL&&pre->right!=NULL)
  40. {
  41. //该节点是父亲节点的左子树
  42. if(parent->left->value==v)
  43. {
  44. parent->left=pre->right;
  45. free(pre);pre=NULL;
  46. }
  47. //该节点是父节点的右子树
  48. else
  49. {
  50. parent->right=pre->right;
  51. free(pre);pre=NULL;
  52. }
  53. }
  54. //右子树为空,左子树不空。将该节点的父节点连接其左子树
  55. else if(pre->left!=NULL&&pre->right==NULL)
  56. {
  57. //该节点是父亲节点的左子树
  58. if(parent->left->value==v)
  59. {
  60. parent->left=pre->left;
  61. free(pre);pre=NULL;
  62. }
  63. //该节点是父节点的右子树
  64. else
  65. {
  66. parent->right=pre->left;
  67. free(pre);pre=NULL;
  68. }
  69. }
  70. //左右子树都不空,取右子树中最左的结点代替后删除
  71. else
  72. {
  73. struct BST * temp=&(*pre->right),* tempparent=&(*pre);
  74. //找到最左的结点
  75. while(temp->left!=NULL)
  76. {tempparent=temp;temp=temp->left;}
  77. //最左结点是叶子结点
  78. if(temp->right==NULL)
  79. {
  80. pre->value=temp->value;//替换到待删结点
  81. free(pre->right);pre->right=NULL;
  82. free(temp);temp=NULL;
  83. }
  84. //若最左结点还有右子树
  85. else
  86. {
  87. pre->value=temp->value;
  88. if(tempparent->value==pre->value)
  89. {pre->right=temp->right;free(temp);temp=NULL;}
  90. else
  91. {
  92. tempparent->left=temp->right;
  93. free(temp);temp=NULL;
  94. }
  95. }
  96. }
  97. return true;
  98. }
  99. }
  100. }

六、层次遍历

  1. 用一个队列,初始化将根节点push进去
  2. 打印队头的结点并pop出
  3. 依次将当前节点的左右结点(顺序不能倒)push进去
  4. 步骤2和3循环直至队列为空
  1. //visit a tree LevelOrder
  2. void LevelOrder(struct BST *root)
  3. {
  4. queue<struct BST*> Q;
  5. Q.push(root);
  6. while(Q.empty()!=true)
  7. {
  8. printf("%d ",Q.front()->value);
  9. if(Q.front()->left!=NULL)
  10. {
  11. Q.push(Q.front()->left);
  12. }
  13. if(Q.front()->right!=NULL)
  14. {
  15. Q.push(Q.front()->right);
  16. }
  17. Q.pop();
  18. }
  19. }

七、先序遍历

先访问(打印),后进入子树

递归版本

  1. //visit a tree PreOrder
  2. void PreOrderBST(struct BST * root)
  3. {
  4. if(root!=NULL)
  5. {
  6. printf("%d ",root->value);
  7. PreOrderBST(root->left);
  8. PreOrderBST(root->right);
  9. }
  10. }

非递归版本

  1. 迭代必须用栈,初始化将根结点push进去
  2. 将结点pop出来并打印
  3. 依次push该节点的右左孩子(栈是先进后出,顺序要相反)
  4. 循环步骤2和3直至栈空
  1. //visit a tree PreOrder without recursion
  2. void PreOrderBSTStack(struct BST * root)
  3. {
  4. if(root==NULL){return;}
  5. stack<struct BST*> S;
  6. S.push(root);
  7. while(S.empty()!=true)
  8. {
  9. struct BST *temp=&(*S.top());
  10. printf("%d ",temp->value);
  11. S.pop();
  12. if(temp->right!=NULL)
  13. {
  14. S.push(temp->right);
  15. }
  16. if(temp->left!=NULL)
  17. {
  18. S.push(temp->left);
  19. }
  20. free(temp);
  21. }
  22. }

八、中序遍历

递归版本

  1. //visit a tree InOrder
  2. void InOrderBST(struct BST * root)
  3. {
  4. if(root!=NULL)
  5. {
  6. InOrderBST(root->left);
  7. printf("%d ",root->value);
  8. InOrderBST(root->right);
  9. }
  10. }

非递归版本

中序遍历的顺序是:左->中/根->右。
具体做法是:用一个栈,将左子树一压到底,直到没有左子树,即遇到最左结点,此时便pop出来同时打印,pop出来时,看看其有没有右子树,有的话再push它的右子树。以此循环,直到栈空。


那么对于栈中的结点有两种情况:一是左子树还没压进来,二是左子树已经pop出去了,而这两种情况栈中都没有左子树,所以需要用字典标记当前节点的左子树是否已经是pop出的。

  1. //visit a tree InOrder without recursion
  2. void InOrderBSTStack(struct BST *root)
  3. {
  4. stack<struct BST*> S;
  5. map<struct BST*,bool> dict;
  6. S.push(root);dict[root]=false;
  7. while(S.empty()!=true)
  8. {
  9. struct BST *temp=&(*S.top());
  10. if(temp->left!=NULL&&dict[temp]!=true)
  11. {
  12. S.push(temp->left);
  13. dict[temp]=true;
  14. continue;
  15. }
  16. printf("%d ",temp->value);
  17. S.pop();
  18. if(temp->right!=NULL)
  19. {
  20. S.push(temp->right);
  21. continue;
  22. }
  23. free(temp);
  24. }
  25. }

九、后续遍历

递归版本

  1. //visit a tree PostOrder
  2. void PostOrderBST(struct BST * root)
  3. {
  4. if(root!=NULL)
  5. {
  6. PostOrderBST(root->left);
  7. PostOrderBST(root->right);
  8. printf("%d ",root->value);
  9. }
  10. }

非递归版本

后续遍历的打印顺序是左->右->根。
而且结点要输出会有两种情况:
一是该节点是一个叶子结点,二是该节点的孩子结点都已经输出了。
也就是说,对于一个有子节点的的结点来说,它的子节点要么还没进栈,要么已经输出,而这两种情况栈中都没有它的子节点的存在,所以需要有一个标记来区分一个结点它的子节点是否已经输出。所以,出了一个栈外,还需要有一个字典来存储结点与输出与否之间的映射关系。

  1. //visit a tree PostOrder without recursion
  2. void PostOrderBSTStack(struct BST * root)
  3. {
  4. if(root==NULL){return ;}
  5. map<struct BST *,bool> dict;
  6. stack<struct BST *> S;
  7. S.push(root);dict[root]=false;
  8. while(S.empty()!=true)
  9. {
  10. struct BST *temp=&(*S.top());
  11. if((temp->left==NULL&&temp->right==NULL)||dict[temp]==true)
  12. {
  13. printf("%d ",temp->value);
  14. S.pop();
  15. free(temp);
  16. continue;
  17. }
  18. if(temp->right!=NULL&&dict[temp]!=true)
  19. {
  20. S.push(temp->right);
  21. }
  22. if(temp->left!=NULL&&dict[temp]!=true)
  23. {
  24. S.push(temp->left);
  25. }
  26. dict[temp]=true;
  27. }
  28. }

十、完整代码

  1. #include<iostream>
  2. #include<queue>
  3. #include<stack>
  4. #include<map>
  5. using namespace std;
  6. struct BST{
  7. int value;
  8. struct BST * right;
  9. struct BST * left;
  10. };
  11. //build a binary tree (root)
  12. struct BST* BuildBSTNode(int v)
  13. {
  14. struct BST* node=(struct BST *)malloc(sizeof(struct BST));
  15. node->value=v;
  16. node->left=NULL;
  17. node->right=NULL;
  18. return node;
  19. }
  20. //visit a tree PreOrder
  21. void PreOrderBST(struct BST * root)
  22. {
  23. if(root!=NULL)
  24. {
  25. printf("%d ",root->value);
  26. PreOrderBST(root->left);
  27. PreOrderBST(root->right);
  28. }
  29. }
  30. //visit a tree PreOrder without recursion
  31. void PreOrderBSTStack(struct BST * root)
  32. {
  33. if(root==NULL){return;}
  34. stack<struct BST*> S;
  35. S.push(root);
  36. while(S.empty()!=true)
  37. {
  38. struct BST *temp=&(*S.top());
  39. printf("%d ",temp->value);
  40. S.pop();
  41. if(temp->right!=NULL)
  42. {
  43. S.push(temp->right);
  44. }
  45. if(temp->left!=NULL)
  46. {
  47. S.push(temp->left);
  48. }
  49. free(temp);
  50. }
  51. }
  52. //visit a tree InOrder
  53. void InOrderBST(struct BST * root)
  54. {
  55. if(root!=NULL)
  56. {
  57. InOrderBST(root->left);
  58. printf("%d ",root->value);
  59. InOrderBST(root->right);
  60. }
  61. }
  62. //visit a tree InOrder without recursion
  63. void InOrderBSTStack(struct BST *root)
  64. {
  65. stack<struct BST*> S;
  66. map<struct BST*,bool> dict;
  67. S.push(root);dict[root]=false;
  68. while(S.empty()!=true)
  69. {
  70. struct BST *temp=&(*S.top());
  71. if(temp->left!=NULL&&dict[temp]!=true)
  72. {
  73. S.push(temp->left);
  74. dict[temp]=true;
  75. continue;
  76. }
  77. printf("%d ",temp->value);
  78. S.pop();
  79. if(temp->right!=NULL)
  80. {
  81. S.push(temp->right);
  82. continue;
  83. }
  84. free(temp);
  85. }
  86. }
  87. //visit a tree PostOrder
  88. void PostOrderBST(struct BST * root)
  89. {
  90. if(root!=NULL)
  91. {
  92. PostOrderBST(root->left);
  93. PostOrderBST(root->right);
  94. printf("%d ",root->value);
  95. }
  96. }
  97. //visit a tree PostOrder without recursion
  98. void PostOrderBSTStack(struct BST * root)
  99. {
  100. if(root==NULL){return ;}
  101. map<struct BST *,bool> dict;
  102. stack<struct BST *> S;
  103. S.push(root);dict[root]=false;
  104. while(S.empty()!=true)
  105. {
  106. struct BST *temp=&(*S.top());
  107. if((temp->left==NULL&&temp->right==NULL)||dict[temp]==true)
  108. {
  109. printf("%d ",temp->value);
  110. S.pop();
  111. free(temp);
  112. continue;
  113. }
  114. if(temp->right!=NULL&&dict[temp]!=true)
  115. {
  116. S.push(temp->right);
  117. }
  118. if(temp->left!=NULL&&dict[temp]!=true)
  119. {
  120. S.push(temp->left);
  121. }
  122. dict[temp]=true;
  123. }
  124. }
  125. //insert BSTNode
  126. void InsertBSTNode(struct BST * root,struct BST * node)
  127. {
  128. if(node->value<root->value&&root->left==NULL)
  129. {root->left=node;}
  130. if(node->value>root->value&&root->right==NULL)
  131. {root->right=node;}
  132. if(node->value<root->value&&root->left!=NULL)
  133. {InsertBSTNode(root->left,node);}
  134. if(node->value>root->value&&root->right!=NULL)
  135. {InsertBSTNode(root->right,node);}
  136. }
  137. //Find a Node whether in a tree
  138. bool FindNode(struct BST *root,int v)
  139. {
  140. if(root==NULL){return false;}
  141. if(v==root->value)
  142. {return true;}
  143. else if(v<root->value)
  144. {return FindNode(root->left,v);}
  145. else
  146. {return FindNode(root->right,v);}
  147. }
  148. //Find a node's parent in a tree
  149. struct BST * FindParent(struct BST * root,int v)
  150. {
  151. if(root->value==v){return NULL;}
  152. if(v<root->value)
  153. {
  154. if(v==root->left->value){return root;}
  155. else{return FindParent(root->left,v);}
  156. }
  157. else
  158. {
  159. if(v==root->right->value){return root;}
  160. else{return FindParent(root->right,v);}
  161. }
  162. }
  163. //delete a node in a tree
  164. bool DeleteNode(struct BST *parent,struct BST *pre,int v)
  165. {
  166. //找不到被删结点
  167. if(pre==NULL){return false;}
  168. //找得到或还没找到
  169. else
  170. {
  171. //待删结点小于当前节点,树往左走
  172. if(v<pre->value)
  173. {
  174. return DeleteNode(&(*pre),(&*pre)->left,v);
  175. }
  176. //待删结点大于当前节点,树往右走
  177. else if(v>pre->value)
  178. {
  179. return DeleteNode(&(*pre),(&*pre)->right,v);
  180. }
  181. //找到待删结点
  182. else
  183. {
  184. //结点为叶子结点,左右子树为空。直接删除
  185. if(pre->left==NULL&&pre->right==NULL)
  186. {
  187. if(parent->left!=NULL&&parent->left->value==v)
  188. {
  189. free(parent->left);parent->left=NULL;
  190. free(pre);
  191. pre=NULL;
  192. }
  193. else
  194. {
  195. free(parent->right);parent->right=NULL;
  196. free(pre);
  197. pre=NULL;
  198. }
  199. }
  200. //左子树为空,右子树不空。将该节点的父节点连接其右子树
  201. else if(pre->left==NULL&&pre->right!=NULL)
  202. {
  203. //该节点是父亲节点的左子树
  204. if(parent->left->value==v)
  205. {
  206. parent->left=pre->right;
  207. free(pre);pre=NULL;
  208. }
  209. //该节点是父节点的右子树
  210. else
  211. {
  212. parent->right=pre->right;
  213. free(pre);pre=NULL;
  214. }
  215. }
  216. //右子树为空,左子树不空。将该节点的父节点连接其左子树
  217. else if(pre->left!=NULL&&pre->right==NULL)
  218. {
  219. //该节点是父亲节点的左子树
  220. if(parent->left->value==v)
  221. {
  222. parent->left=pre->left;
  223. free(pre);pre=NULL;
  224. }
  225. //该节点是父节点的右子树
  226. else
  227. {
  228. parent->right=pre->left;
  229. free(pre);pre=NULL;
  230. }
  231. }
  232. //左右子树都不空,取右子树中最左的结点代替后删除
  233. else
  234. {
  235. struct BST * temp=&(*pre->right),* tempparent=&(*pre);
  236. //找到最左的结点
  237. while(temp->left!=NULL)
  238. {tempparent=temp;temp=temp->left;}
  239. //最左结点是叶子结点
  240. if(temp->right==NULL)
  241. {
  242. pre->value=temp->value;//替换到待删结点
  243. free(pre->right);pre->right=NULL;
  244. free(temp);temp=NULL;
  245. }
  246. //若最左结点还有右子树
  247. else
  248. {
  249. pre->value=temp->value;
  250. if(tempparent->value==pre->value)
  251. {pre->right=temp->right;free(temp);temp=NULL;}
  252. else
  253. {
  254. tempparent->left=temp->right;
  255. free(temp);temp=NULL;
  256. }
  257. }
  258. }
  259. return true;
  260. }
  261. }
  262. }
  263. //visit a tree LevelOrder
  264. void LevelOrder(struct BST *root)
  265. {
  266. queue<struct BST*> Q;
  267. Q.push(root);
  268. while(Q.empty()!=true)
  269. {
  270. printf("%d ",Q.front()->value);
  271. if(Q.front()->left!=NULL)
  272. {
  273. Q.push(Q.front()->left);
  274. }
  275. if(Q.front()->right!=NULL)
  276. {
  277. Q.push(Q.front()->right);
  278. }
  279. Q.pop();
  280. }
  281. }
  282. int main ()
  283. {
  284. int a[16]={15,8,30,6,9,17,40,4,7,16,35,49,33,38,34,39};
  285. struct BST * root=BuildBSTNode(a[0]);
  286. for(int i=1;i<16;++i)
  287. {
  288. struct BST * node=BuildBSTNode(a[i]);
  289. InsertBSTNode(root,node);
  290. }
  291. PostOrderBST(root);printf("\n");
  292. PostOrderBSTStack(root);
  293. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注