1. // 二叉树常见面试问题汇总
    2. #include <iostream>
    3. #include <stack>
    4. #include <vector>
    5. using namespace std;
    6. class TreeNode
    7. {
    8. public:
    9. TreeNode(int val): val(val), left(nullptr),right(nullptr){}
    10. int val;
    11. TreeNode* left;
    12. TreeNode* right;
    13. };
    14. //前序遍历非递归
    15. void preOrder1(TreeNode* root, vector<int> &res)
    16. {
    17. if (root != nullptr)
    18. {
    19. res.push_back(root->val);
    20. preOrder1(root->left, res);
    21. preOrder1(root->right,res);
    22. }
    23. return;
    24. }
    25. /*
    26. 前序遍历非递归
    27. 1、从根节点开始,遍历所有的根节点的左子树的左孩子,将他们都放入到栈中。
    28. 2、出栈。
    29. 3、逐个取出栈中的元素,该元素的左子树肯定已经遍历过了,要检查是不是有右子节点,有的话,将右子节点按照步骤1走一遍(相当于以该右子节点为新的根节点进行了同样的遍历)
    30. */
    31. void preOrder(TreeNode* root, vector<int> &res)
    32. {
    33. if (root == nullptr)
    34. {
    35. return;
    36. }
    37. stack<TreeNode*> s;
    38. TreeNode * p = root;
    39. while (p != nullptr || !s.empty())
    40. {
    41. //从根节点开始,遍历所有的根节点的左子树的左孩子,将他们都放入到栈中
    42. while (p != nullptr)
    43. {
    44. s.push(p);
    45. res.push_back(p->val); //先遍历根节点的元素
    46. p = p->left;
    47. }
    48. if (!s.empty())
    49. {
    50. p = s.top(); //取出栈顶元素,此时元素的左边应该都已经遍历过了,需要遍历其右边的
    51. s.pop();
    52. p = p->right; //下一次循环就会遍历以该节点为根节点的树
    53. }
    54. }
    55. return;
    56. }
    57. //递归中序遍历
    58. void inOrder1(TreeNode* root, vector<int> &res)
    59. {
    60. if (root != nullptr)
    61. {
    62. inOrder1(root->left, res);
    63. res.push_back(root->val);
    64. inOrder1(root->right, res);
    65. }
    66. }
    67. /*
    68. 中序遍历非递归
    69. 1、先将根节点入栈,遍历左子树
    70. 2、第一遍循环遍历完左子树返回后,此时栈顶元素为左子树的最左边的元素,此节点没有左子树,相当于左子树已经遍历完了,此时打印该节点的值
    71. 3、然后以该节点的右子节点作为新的跟节点进行下一轮中序遍历循环
    72. */
    73. void inOrder(TreeNode* root, vector<int> &res)
    74. {
    75. stack<TreeNode*> s;
    76. TreeNode* p = root;
    77. while (p != nullptr || !s.empty())
    78. {
    79. while (p != nullptr)
    80. {
    81. s.push(p);
    82. p = p->left;
    83. }
    84. //取出栈中的元素,查看其右子节点
    85. if (!s.empty())
    86. {
    87. p = s.top();
    88. s.pop();
    89. res.push_back(p->val);
    90. p = p->right;
    91. }
    92. }
    93. return;
    94. }
    95. //后序遍历递归
    96. void postOrder1(TreeNode* root, vector<int>& res)
    97. {
    98. if (root != nullptr)
    99. {
    100. postOrder1(root->left, res);
    101. postOrder1(root->right, res);
    102. res.push_back(root->val);
    103. }
    104. return;
    105. }
    106. //后序遍历非递归
    107. /*
    108. 后序遍历要求在遍历完左右子树之后再访问根,需要判断根节点的左右子树是否均遍历过。
    109. 采用标记法,节点入栈时,表示第一次入栈,然后遍历左子树,返回后,修改栈顶元素的访问标记为非第一次访问,然后遍历其右边子树,最后访问根节点。
    110. */
    111. //辅助结构,增加访问次数标记
    112. class Node
    113. {
    114. public:
    115. TreeNode* btNode;
    116. bool isFirst;
    117. };
    118. void postOrder(TreeNode* root, vector<int> &res)
    119. {
    120. stack<Node*> s;
    121. TreeNode* p = root;
    122. Node* popNode; //栈顶出栈的元素
    123. while (p != nullptr || !s.empty())
    124. {
    125. //将左子树压栈
    126. while (p != nullptr)
    127. {
    128. Node* curNode = new Node();
    129. curNode->btNode = p;
    130. curNode->isFirst = true;
    131. s.push(curNode);
    132. p = p->left;
    133. }
    134. if (!s.empty())
    135. {
    136. popNode = s.top();
    137. //先查看是否第一次出栈,如果是第一次,还需要将右子节点进行遍历
    138. if (popNode->isFirst)
    139. {
    140. popNode->isFirst = false;
    141. p = popNode->btNode->right; //将右子节点作为新的根节点,进行下一轮的遍历。
    142. }
    143. else //左右子树都已经遍历过了
    144. {
    145. s.pop();
    146. res.push_back(popNode->btNode->val);
    147. p = nullptr;
    148. }
    149. }
    150. }
    151. }
    152. //二叉树层序遍历
    153. /*
    154. 借助队列:
    155. 假如层序遍历为A、B、C、D、E、F、G
    156. A
    157. B C
    158. D E F G
    159. 1、A入队
    160. 2、A出队,同时A的子节点B、C入队(此时队列有B、C)
    161. 3、B出队,同时B的子节点D、E入队(此时队列由C、D、E)
    162. 4、C出队,同时C的子节点F、G入队(此时队列有D、E、F、G)
    163. */
    164. void LevelOrder(TreeNode* root, vector<int> &res)
    165. {
    166. queue<TreeNode*> q;
    167. TreeNode* p;
    168. q.push(root); //根节点入队
    169. while (!q.empty())
    170. {
    171. p = q.front();
    172. q.pop();
    173. res.push_back(p->val);
    174. if (p->left) //当前节点有左节点,则左节点入队
    175. {
    176. q.push(p->left);
    177. }
    178. if (p->right) //当前节点有右节点,则右节点入队
    179. {
    180. q.push(p->right);
    181. }
    182. }
    183. return;
    184. }
    185. int main()
    186. {
    187. //创建二叉树
    188. TreeNode* root = new TreeNode(1);
    189. TreeNode* curNode = root;
    190. curNode->left = new TreeNode(2);
    191. curNode->right = new TreeNode(3);
    192. curNode->left->left = new TreeNode(4);
    193. curNode->left->right = new TreeNode(5);
    194. curNode->right->left = new TreeNode(6);
    195. curNode->right->right = new TreeNode(7);
    196. vector<int> res;
    197. postOrder(root, res);
    198. for (int i = 0; i < res.size(); i++)
    199. {
    200. cout << res[i] << " ";
    201. }
    202. cout << endl;
    203. return 0;
    204. }