函数递归调用图

函数递归调用图.png

二叉树

  1. // 二叉树.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //
  3. #include "pch.h"
  4. #include <stdio.h>
  5. struct Node {
  6. int nData; // 节点的数据域
  7. Node* pLeft; // 左子树指针
  8. Node* pRight; // 右子树指针
  9. Node() :pLeft(), pRight() {}
  10. Node(int nData)
  11. :nData(nData),pLeft(), pRight()
  12. {}
  13. };
  14. // 二叉查找树
  15. class BSTree {
  16. int m_nCount = 0; // 树中节点个数
  17. Node* m_pRoot = 0;// 根节点指针:记录树中的根节点地址.
  18. protected:
  19. // 参数1是指针的引用, 为的是能够在
  20. // 函数内部修改函数外部的实参(可以参考交换两个变量的函数)
  21. /*!
  22. * 函数名 : insert
  23. * 功 能 : 将数据nData插入到pTree作为根节点的树居中
  24. * 参 数 : Node * & pTree 树的根节点.
  25. * 参 数 : int nData 插入的数据
  26. * 返回值 : void
  27. */
  28. void insert( Node*& pTree, int nData) {
  29. // 1. 判断树的根节点是否为NULL,如果为NULL
  30. // 直接插入到根节点
  31. if (pTree == nullptr) {
  32. pTree = new Node(nData);
  33. // 递增节点个数
  34. ++m_nCount;
  35. return;
  36. }
  37. // 2. 如果不为空,则判断插入的数据和根节点
  38. // 所保存的数据的大小关系
  39. if (nData < pTree->nData) {
  40. // 3. 如果插入数据小于根节点数据,那么就将
  41. // 根节点的左子树作为新的根节点,让后将
  42. // 数据插入到左子树中.
  43. insert(pTree->pLeft, nData);
  44. }
  45. else {
  46. // 否则就插入到右子树中.
  47. insert(pTree->pRight, nData);
  48. }
  49. }
  50. Node*& find(Node*& pTree, int nData) {
  51. if (pTree == nullptr) {
  52. return pTree;
  53. }
  54. // 1. 判断当前节点保存的数据是否
  55. // 就是要查找的数据
  56. if (pTree->nData == nData) {
  57. // 如果是, 就返回节点本身
  58. return pTree;
  59. }
  60. // 如果不是, 则判断这个数据是在节点的左子树中
  61. // 还是在右子树中.
  62. // 因为二叉树是左小右大的.
  63. // 因此, 比较要删除的数据和当前节点的大小关系
  64. // 就能知道是在左子树还是在右子树中
  65. else if (nData < pTree->nData) {
  66. return find(pTree->pLeft,nData);
  67. }
  68. else {
  69. return find(pTree->pRight,nData);
  70. }
  71. }
  72. void remove(Node*& pTree, int nData) {
  73. if (pTree == nullptr) {
  74. return;
  75. }
  76. printf("-------- 删除:%d----- \n", nData);
  77. printTree();
  78. // 1. 在树中查找到要删除的节点.
  79. Node*& pFindNode = find(pTree, nData);
  80. // 是否能够找到节点.
  81. if (pFindNode == nullptr) {
  82. return;
  83. }
  84. // 2. 找到节点的就是被删除的节点
  85. // 删除时要判断节点是否是一个叶子节点
  86. // 如果是叶子节点可以直接删除
  87. if (pFindNode->pLeft == nullptr && pFindNode->pRight == nullptr) {
  88. // 直接删除
  89. delete pFindNode;
  90. // 将指针设置为空,由于pFindNode是一个指针
  91. // 的引用, 因此它修改的是哪里????(实际上修改的是
  92. // 父节点的右子树指针或左子树指针)
  93. pFindNode = nullptr;
  94. // 递减节点个数
  95. --m_nCount;
  96. return;
  97. }
  98. // 3. 如果不是叶子节点. 就需要在被删除节点的
  99. // 子树中找到一个叶子节点, 然后两者的值
  100. // 互换, 再删除掉叶子节点
  101. // 3.1 再找叶子节点的时候, 需要考虑子树高度差
  102. // 因此会在树高比较高的子树中找叶子节点.
  103. int nLeftHeight = getHeight(pFindNode->pLeft);
  104. int nRightHeight = getHeight(pFindNode->pRight);
  105. // 3.2 树中左小右大的关系, 因此, 需要左子树中
  106. // 找最大值, 在右子树中找最小值.
  107. if (nLeftHeight >= nRightHeight) {
  108. // 左子树比较高,需要找最大值
  109. Node*& pNode = getMax(pFindNode->pLeft);
  110. // 将当前被找到的节点和叶子节点的数据域
  111. // 进行调换
  112. int t = pFindNode->nData;
  113. pFindNode->nData = pNode->nData;
  114. pNode->nData = t;
  115. // 删除叶子节点
  116. // 递归删除.
  117. remove(pFindNode->pLeft, pNode->nData);
  118. }
  119. else {
  120. // 右子树比较高,需要找最小值
  121. Node*& pNode = getMin(pFindNode->pRight);
  122. int t = pFindNode->nData;
  123. pFindNode->nData = pNode->nData;
  124. pNode->nData = t;
  125. // 删除叶子节点
  126. // 递归删除.
  127. remove(pFindNode->pRight, pNode->nData);
  128. }
  129. }
  130. /*!
  131. * 函数名 : getHeight
  132. * 功 能 : 求一个树的高度
  133. * 参 数 : Node * pTree
  134. * 返回值 : int
  135. */
  136. int getHeight(Node* pTree) {
  137. if (pTree == nullptr) {
  138. return 0;
  139. }
  140. // 求出左子树的高度
  141. int nLeftHeight =
  142. getHeight(pTree->pLeft);
  143. // 求出右子树的高度
  144. int nRightHeight =
  145. getHeight(pTree->pRight);
  146. // 取左右子树高度的最大值作为子树的高度
  147. int nHeight = nLeftHeight > nRightHeight ? nLeftHeight : nRightHeight;
  148. // 本节点的高度 = 自身高度 + 子树的高度
  149. return 1 + nHeight;
  150. }
  151. Node*& getMin(Node*& pTree) {
  152. if (pTree == nullptr) {
  153. return pTree;
  154. }
  155. // 二叉树是左小右大的.
  156. // 一个树的最小值就在树的最左边
  157. if (pTree->pLeft == nullptr) {
  158. // 如果本节点的左子节点已经为空了
  159. // 说明了本节点就是树中最左边的节点
  160. // 就返回节点自身.
  161. return pTree;
  162. }
  163. return getMin(pTree->pLeft);
  164. }
  165. Node*& getMax(Node*& pTree) {
  166. if (pTree == nullptr) {
  167. return pTree;
  168. }
  169. // 二叉树是左小右大的.
  170. // 一个树的最大值就在树的最右边
  171. if (pTree->pRight == nullptr) {
  172. // 如果本节点的右子节点已经为空了
  173. // 说明了本节点就是树中最右边的节点
  174. // 就返回节点自身.
  175. return pTree;
  176. }
  177. return getMax(pTree->pRight);
  178. }
  179. // 清空整颗树(后序遍历
  180. void clear(Node*& pTree) {
  181. clear(pTree->pLeft);
  182. clear(pTree->pRight);
  183. delete pTree;
  184. }
  185. // 前序方式遍历树
  186. void printTreeByPreOrder(Node*& pTree) {
  187. if (pTree == nullptr) {
  188. return;
  189. }
  190. printf("%d,", pTree->nData);
  191. printTreeByPreOrder(pTree->pLeft);
  192. printTreeByPreOrder(pTree->pRight);
  193. }
  194. // 中序方式遍历树
  195. void printTreeByInOrder(Node*& pTree) {
  196. if (pTree == nullptr) {
  197. return;
  198. }
  199. printTreeByInOrder(pTree->pLeft);
  200. printf("%d,", pTree->nData);
  201. printTreeByInOrder(pTree->pRight);
  202. }
  203. // 后序方式遍历树
  204. void printTreeByPostOrder(Node*& pTree) {
  205. if (pTree == nullptr) {
  206. return;
  207. }
  208. printTreeByPostOrder(pTree->pLeft);
  209. printTreeByPostOrder(pTree->pRight);
  210. printf("%d,", pTree->nData);
  211. }
  212. void printTree(Node*& pTree, int nWidth, char ch) {
  213. if (pTree == nullptr) {
  214. return;
  215. }
  216. printTree(pTree->pLeft, nWidth + 2, '/');
  217. printf("%*c%d\n", nWidth, ch , pTree->nData);
  218. printTree(pTree->pRight, nWidth + 2, '\\');
  219. }
  220. void sort(Node*& pTree) {
  221. // 1. 判断树的形状:
  222. int nLeftHeight = getHeight(pTree->pLeft);
  223. int nRightHeight = getHeight(pTree->pRight);
  224. if (nLeftHeight - nRightHeight > 1) {
  225. // 1.1 左斜
  226. nLeftHeight = getHeight(pTree->pLeft->pLeft);
  227. nRightHeight = getHeight(pTree->pLeft->pRight);
  228. if (nLeftHeight > nRightHeight) {
  229. // 1.1.1 左单斜
  230. }
  231. else {
  232. // 1.1.2 左歪斜
  233. }
  234. }
  235. else if (nLeftHeight - nRightHeight < -1) {
  236. // 1.2 右斜
  237. nLeftHeight = getHeight(pTree->pRight->pLeft);
  238. nRightHeight = getHeight(pTree->pRight->pRight);
  239. if (nRightHeight > nLeftHeight) {
  240. // 1.2.1 右单斜
  241. }
  242. else {
  243. // 1.2.2 右歪斜
  244. }
  245. }
  246. }
  247. public:
  248. void insert(int nData) {
  249. insert(m_pRoot, nData);
  250. }
  251. void remove(int nData) {
  252. remove(m_pRoot, nData);
  253. }
  254. void printTree() {
  255. printTree(m_pRoot, 2, '*');
  256. printf("\n");
  257. }
  258. };
  259. struct MyStruct {
  260. int nNum = 0;
  261. const char* pStr;
  262. };
  263. const char*& fun(const char*& p) {
  264. return p;
  265. }
  266. int main(){
  267. MyStruct stc = {0, "hello" };
  268. const char*& p = fun(stc.pStr);
  269. p = "呵呵";
  270. BSTree tree;
  271. tree.insert(10);
  272. tree.insert(5);
  273. tree.insert(20);
  274. tree.insert(7);
  275. tree.insert(6);
  276. tree.printTree();
  277. tree.remove(10);
  278. tree.printTree();
  279. }