// 二叉树常见面试问题汇总#include <iostream>#include <stack>#include <vector>using namespace std;class TreeNode{public: TreeNode(int val): val(val), left(nullptr),right(nullptr){} int val; TreeNode* left; TreeNode* right;};//前序遍历非递归void preOrder1(TreeNode* root, vector<int> &res){ if (root != nullptr) { res.push_back(root->val); preOrder1(root->left, res); preOrder1(root->right,res); } return;}/* 前序遍历非递归 1、从根节点开始,遍历所有的根节点的左子树的左孩子,将他们都放入到栈中。 2、出栈。 3、逐个取出栈中的元素,该元素的左子树肯定已经遍历过了,要检查是不是有右子节点,有的话,将右子节点按照步骤1走一遍(相当于以该右子节点为新的根节点进行了同样的遍历)*/void preOrder(TreeNode* root, vector<int> &res){ if (root == nullptr) { return; } stack<TreeNode*> s; TreeNode * p = root; while (p != nullptr || !s.empty()) { //从根节点开始,遍历所有的根节点的左子树的左孩子,将他们都放入到栈中 while (p != nullptr) { s.push(p); res.push_back(p->val); //先遍历根节点的元素 p = p->left; } if (!s.empty()) { p = s.top(); //取出栈顶元素,此时元素的左边应该都已经遍历过了,需要遍历其右边的 s.pop(); p = p->right; //下一次循环就会遍历以该节点为根节点的树 } } return;}//递归中序遍历void inOrder1(TreeNode* root, vector<int> &res){ if (root != nullptr) { inOrder1(root->left, res); res.push_back(root->val); inOrder1(root->right, res); }}/* 中序遍历非递归 1、先将根节点入栈,遍历左子树 2、第一遍循环遍历完左子树返回后,此时栈顶元素为左子树的最左边的元素,此节点没有左子树,相当于左子树已经遍历完了,此时打印该节点的值 3、然后以该节点的右子节点作为新的跟节点进行下一轮中序遍历循环*/void inOrder(TreeNode* root, vector<int> &res){ stack<TreeNode*> s; TreeNode* p = root; while (p != nullptr || !s.empty()) { while (p != nullptr) { s.push(p); p = p->left; } //取出栈中的元素,查看其右子节点 if (!s.empty()) { p = s.top(); s.pop(); res.push_back(p->val); p = p->right; } } return;}//后序遍历递归void postOrder1(TreeNode* root, vector<int>& res){ if (root != nullptr) { postOrder1(root->left, res); postOrder1(root->right, res); res.push_back(root->val); } return;}//后序遍历非递归/* 后序遍历要求在遍历完左右子树之后再访问根,需要判断根节点的左右子树是否均遍历过。 采用标记法,节点入栈时,表示第一次入栈,然后遍历左子树,返回后,修改栈顶元素的访问标记为非第一次访问,然后遍历其右边子树,最后访问根节点。*///辅助结构,增加访问次数标记class Node{public: TreeNode* btNode; bool isFirst;};void postOrder(TreeNode* root, vector<int> &res){ stack<Node*> s; TreeNode* p = root; Node* popNode; //栈顶出栈的元素 while (p != nullptr || !s.empty()) { //将左子树压栈 while (p != nullptr) { Node* curNode = new Node(); curNode->btNode = p; curNode->isFirst = true; s.push(curNode); p = p->left; } if (!s.empty()) { popNode = s.top(); //先查看是否第一次出栈,如果是第一次,还需要将右子节点进行遍历 if (popNode->isFirst) { popNode->isFirst = false; p = popNode->btNode->right; //将右子节点作为新的根节点,进行下一轮的遍历。 } else //左右子树都已经遍历过了 { s.pop(); res.push_back(popNode->btNode->val); p = nullptr; } } }}//二叉树层序遍历/* 借助队列: 假如层序遍历为A、B、C、D、E、F、G A B C D E F G 1、A入队 2、A出队,同时A的子节点B、C入队(此时队列有B、C) 3、B出队,同时B的子节点D、E入队(此时队列由C、D、E) 4、C出队,同时C的子节点F、G入队(此时队列有D、E、F、G)*/void LevelOrder(TreeNode* root, vector<int> &res){ queue<TreeNode*> q; TreeNode* p; q.push(root); //根节点入队 while (!q.empty()) { p = q.front(); q.pop(); res.push_back(p->val); if (p->left) //当前节点有左节点,则左节点入队 { q.push(p->left); } if (p->right) //当前节点有右节点,则右节点入队 { q.push(p->right); } } return;}int main(){ //创建二叉树 TreeNode* root = new TreeNode(1); TreeNode* curNode = root; curNode->left = new TreeNode(2); curNode->right = new TreeNode(3); curNode->left->left = new TreeNode(4); curNode->left->right = new TreeNode(5); curNode->right->left = new TreeNode(6); curNode->right->right = new TreeNode(7); vector<int> res; postOrder(root, res); for (int i = 0; i < res.size(); i++) { cout << res[i] << " "; } cout << endl; return 0;}