递归遍历
题目链接/文章讲解/视频讲解: 代码随想录
-
确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
-
确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
-
确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
通过这三个步骤即可写出递归方法的遍历,代码如下:
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;
}
};
前序中序后序的区别只在于vec.push_back(cur->val);和遍历左右节点的顺序,改变一下即可变成另外两种遍历方式。
迭代遍历
题目链接/文章讲解/视频讲解: 代码随想录
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
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) st.push(node->right);
if (node->left) st.push(node->left);
}
return result;
}
};
首先是前序算法,核心思想是使用栈来进行迭代,来模拟递归的方法。首先现将根节点压入栈中,因为是前序遍历,所以在循环中首先要将弹出的元素存入result之中,然后先后遍历该节点的右左节点,这样在弹栈的过程中就能让左节点先被遍历右节点再被遍历,符合前序便利的顺序。因为前序遍历访问顺序和处理顺序是一致的,所以可以这样去做,先将要处理的元素处理了再进行压栈操作,而中序遍历则不像这样。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
TreeNode* cur = root;
while (cur != NULL || !st.empty()) {
if (cur != NULL) { // 指针来访问节点,访问到最底层
st.push(cur); // 将访问的节点放进栈
cur = cur->left; // 左
} else {
cur = st.top(); // 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
st.pop();
result.push_back(cur->val); // 中
cur = cur->right; // 右
}
}
return result;
}
};
中序遍历,由于上述原因,中序遍历不能采用和前序遍历相同的方式。中序遍历也使用了栈来模拟遍历的过程,不过是在栈弹出的时候进行元素处理。首先先让cur等于root,在遍历的过程中,先将该节点压入栈中,然后再将其左节点压入栈中,直至没有左节点了,这时候开始处理栈中的节点。首先弹出的是二叉树中最左的节点,在处理完栈弹出的元素后,再将该元素的右节点存入栈中,这样就可以实现左中右的顺序了。
class Solution {
public:
vector<int> postorderTraversal(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->left) st.push(node->left); // 相对于前序遍历,这更改一下入栈顺序 (空节点不入栈)
if (node->right) st.push(node->right); // 空节点不入栈
}
reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
return result;
}
};
后序遍历的顺序是左右中,而前序遍历的顺序是中左右,只需使用前序遍历的方法得到中右左的顺序,然后再将答案反转过来即可得到后序遍历的顺序。
统一迭代
题目链接/文章讲解: 代码随想录
就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记,就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记