二叉树的遍历方式
前序遍历
递归:
递归函数最重要的三个部分:
1 :递归函数的传参
2:递归函数的出口 什么时候结束
3:递归函数的内层逻辑是啥
void pre(TreeNode *root,vector<int>&vec){
if(root==NULL)return ; // 递归函数的出口 如果此时节点指针为空 则返回
vec.push_back(root->val); // 把当前节点的值放进结果数组中
pre(root->left,vec); // 递归节点的左孩子
pre(root->right,vec); // 递归节点的右孩子
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int>result; //定义结果数组 用来存放遍历的结果
pre(root,result);
return result;
迭代 用到栈,利用栈的先进后出的性质
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*>st; // 定义用来遍历的栈 因为存放的是指针变量所以定义时候也是指针变量形式
vector<int>res; // 定义用来存放遍历结果的数组
st.push(root); // 把树的根节点入栈
while(!st.empty()){
//当栈不为空的时候 就继续入栈
TreeNode *node = st.top(); // 此时的栈顶元素的
st.pop(); // 将元素出栈
if(node!=NULL)res.push_back(node->val); //如果此时元素不是空 题目没说是满二叉树
else continue; // 因此有可能存在左右子树有空的情况
if(node->right)st.push(node->right); // 把左右子树入栈
if(node->left)st.push(node->left);
}
return res;
中序遍历
递归方式
void mid(TreeNode *root,vector<int>&vec){
if(root == NULL)return;
mid(root->left,vec);
vec.push_back(root->val);
mid(root->right,vec);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int>result;
mid(root,result);
return result;
}
迭代
二叉树的中序遍历迭代方法跟前序有点不一样,前序每次将栈顶元素出栈然后将右子树和左子树入栈就行了,但中序遍历因为是要一直访问到左子树的最左边,所以需要一个指针变量帮助找到二叉树的最左边的节点。
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*>st; // 定义用来遍历的栈
vector<int>res; // 定义结果数组
TreeNode *cur = root; // 初始化指针为根节点
while(cur!=NULL || !st.empty()){
// 如果此时的栈不为空或者指针不为空
if(cur!=NULL){
// 如果此时的指针不为空 则说明还未找到树的左子树的左叶子节点
st.push(cur); // 将左孩子节点都放到栈中去
cur=cur->left; // 一直往左下角找
}
else{
cur = st.top(); // 如果此时的指针为空 则要进行出栈操作
st.pop();
res.push_back(cur->val);
cur = cur->right; // 将指针指向该节点的右孩子
}
}
return res;
}
后序遍历
递归 (套路都是一样的,不过是放到数组的顺序不一样而已)
void lat(TreeNode *root,vector<int>&vec){
if(root == NULL)return ;
lat(root->left,vec);
lat(root->right,vec);
vec.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int>result;
lat(root,result);
return result;
}
迭代
也是用栈来解决,但比较麻烦的是后续遍历顺序是***“左右根”***,如果按照前序遍历那样的话,一个元素如果要出栈肯定得是第二次遇见或者左右子树都没了才可以,比较麻烦。
因为前序遍历顺序是***“根左右”***,而后续遍历的顺序是***“左右根”***,因此可以在前序遍历的基础上改一下,将前序遍历的代码该为***“根右左”***,然后再将结果数组反转即可。
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*>st; // 定义栈
vector<int>res; //定义结果数组
st.push(root); // 将根节点入栈
while(!st.empty()){
TreeNode *node = st.top(); // 此时的栈顶元素为要出栈的元素
st.pop();
if(node!=NULL)res.push_back(node->val); //先判断是否为空 可能不是满二叉树
else continue;
if(node->left)st.push(node->left); //将左子树先进栈 则后访问左子树
if(node->right)st.push(node->right);
}
reverse(res.begin(),res.end()); //将结果数组反转一下
return res;
}
总结
树的三种遍历很重要,面试时候只会写递归在面试时候估计容易听到 “回家等通知吧”!