144. Binary Tree Preorder Traversal
Given a binary tree, return the preorder traversal of its nodes’ values.
Example:
Input: [1,null,2,3]
1
\
2
/
3
Output: [1,2,3]
Follow up: Recursive solution is trivial, could you do it iteratively?
思路:
先序遍历的顺序:根节点->左子树->右子树
递归做法比较简单,定义一个递归函数,传入一个TreeNode *
类型的变量root
指向二叉树的根节点。因为需要递归调用该函数,root
需要不断更换为其左子树指针root->left
,或者其右子树指针root->right
所以当root
指向NULL
时访问到了最末端节点的指向NULL
的一侧,直接return即可,此为递归出口。如果root不空
,那么先访问当前节点的值(根)root->val
,然后递归访问其左子树root->left
,和其右子树root->right
C++递归:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> ans;
vector<int> preorderTraversal(TreeNode* root) {
preorder(root);
return ans;
}
void preorder(TreeNode * root){
if(root == NULL)
return;
ans.push_back(root->val);
preorder(root->left);
preorder(root->right);
}
};
结果
非递归做法:假设传入的二叉树的根节点为p
,如果 p!=NULL
说明指针p
指向的节点可以访问,而先序遍历最先访问的就是根节点,所以访问p->val
,将结果保存。因为下一步应该访问p
的左子树,而p
的右子树是最后访问的,所以应该将p
压入栈stk
以便下次访问p
的右子树使用。
这一步可以写成代码段1:
if(p){//p!=NULL
ans.push_back(p->val);//访问根节点
stk.push(p);//将当前节点入栈,方便下次出栈遍历其右子树
p = p->left;
}
如此循环上面代码段1直到p==NULL
,这时是访问到了下面这两种情况,最近保存的是最后入栈的。图片来源
可以看到p==NULL
时,可以看做最后入栈的元素已经访问完其左孩子(NULL),和其根节点(上面代码段看到我们是先访问再入栈),这时需要访问最近入栈元素的右孩子,那么我们让栈顶元素出栈,访问其右孩子,得到以下代码段2:
if(!p){
TreeNode * t;
t = stk.top();//此时p==NULL,说明p的父节点和其左孩子都被访问过了,此时将栈顶元素出栈
stk.pop();//将p的父节点出栈
p = t->right;//访问其右孩子
}
而树是递归定义的,其右孩子也是一颗树,只需要将上面两部重复就可以完成先序遍历,整个代码如下:
C++迭代解:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> ans;
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode *> stk;
TreeNode * p = root;
while(!stk.empty()||p){//注意将队首元素出栈是在访问玩根节点和左孩子,
//所以当栈为空不一定访问完了二叉树,可能访问完了二叉树的根节点的左子树,
//而p此刻正指向根节点的右子树。经过分析可以知道,p最后指向最后访问的一个元素的右孩子(NULL),所以需要综合考虑
if(p){
ans.push_back(p->val);
stk.push(p);
p = p->left;
}
else{//p == NULL
TreeNode * t;
t = stk.top();//p==NULL,说明p的父节点和其左孩子都被访问过了
stk.pop();//将p的父节点出栈
p = t->right;//访问其右孩子
}
}
return ans;
}
};