leetcode144 二叉树的前序遍历 递归法、迭代法
递归算法的三个要素
确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
(1) 找出重复的子问题。
这个很好找,前序遍历的顺序是:根、左子树、右子树。
对于左子树或者右子树来说,也是同样的遍历顺序。
所以这个重复的子问题就出来了,先取根节点,再遍历左子树,最后遍历右子树。
(2) 确定终止条件。
对于二叉树的遍历来说,想终止,即没东西遍历了,没东西遍历自然就停下来了。
那就是当前的节点是空的,既然是空的那就没啥好遍历。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void Traversal(TreeNode* cur, vector<int>& vec){
if(cur == NULL) return;
vec.push_back(cur->val);
Traversal(cur->left, vec);
Traversal(cur->right, vec);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
Traversal(root, result);
return result;
}
};
-
构造函数:
-
TreeNode()
:默认构造函数,初始化节点值为0
,左右子节点为nullptr
。 -
TreeNode(int x)
:初始化节点值为x
,左右子节点为nullptr
。 -
TreeNode(int x, TreeNode* left, TreeNode* right)
:初始化节点值为x
,并指定左右子节点。
-
-
你在
while (cur != NULL)
中递归调用了Traversal
函数。 -
这个
while
循环会导致无限递归,因为cur
的值在递归调用中不会改变,while
循环的条件始终为真(除非cur
一开始就是nullptr
)。 -
正确的递归实现应该用
if
判断,而不是while
循环。
迭代法:用栈,不断地将旧的变量值,递推计算新的变量值。
-
初始化维护一个栈,将根节点入栈。
-
当栈不为空时
-
弹出栈顶元素 node,将节点值加入结果数组中。
-
若 node 的右子树不为空,右子树入栈。
-
若 node 的左子树不为空,左子树入栈。
-
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if(root == NULL) return result;
st.push(root);
while(!st.empty()){
TreeNode* node = st.top();
st.pop();
result.push_back(node->val);
if(node->right != NULL) st.push(node->right);
if(node->left != NULL) st.push(node->left);
}
return result;
}
};
TreeNode* node
的作用是 临时存储当前正在处理的二叉树节点。它是栈顶节点的副本,用于访问当前节点的值以及将其子节点压入栈中。