一、前言
参考文献:代码随想录
今天的内容比较简单,主要考察的是二叉树的前序、中序、后序遍历的三种形式的遍历,分别有递归遍历,迭代遍历,统一迭代,三种方式。
二、递归遍历:
1、思路:
使用递归就要想好
(1)返回的是什么
(2)传输什么参数?
(3)终止条件是什么?
(4)主体是什么?
想好这三个基本就可以把递归写出来了,在二叉树的遍历当中,我们传入的当然是根节点了,终止条件便是节点为空了,这样我们就很轻而易举地得到了如下代码。
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 {
private:
void traversal(TreeNode *root, vector<int> &result) {
// 递归终止条件
if (root != NULL) {
result.push_back(root->val);
traversal(root->left, result);
traversal(root->right, result);
}
}
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root, result);
return result;
}
};
3、中序遍历代码:
中序遍历只需要将存数的步骤变化位置就可以了,遍历的顺序是左中右
/**
* 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 {
private:
void traversal(TreeNode *root, vector<int> &result) {
// 递归终止条件
if (root != NULL) {
// 左子树
traversal(root->left, result);
// 取值
result.push_back(root->val);
// 右子树
traversal(root->right, result);
}
}
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root, result);
return result;
}
};
4、后序遍历代码:
后序遍历就不必多说了吧,也是只需要改变一下存数的位置就ok了
/**
* 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 {
private:
void traversal(TreeNode *root, vector<int> &result) {
// 递归终止条件
if (root != NULL) {
// 左子树
traversal(root->left, result);
// 右子树
traversal(root->right, result);
// 取值
result.push_back(root->val);
}
}
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root, result);
return result;
}
};
三、迭代遍历
1、思路:
迭代遍历根据我的理解就是把递归换成了一个while循环再加上栈的辅助就是一个迭代了,用while和栈完成递归需要做的事情。
2、前序遍历代码:
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> my_stack;
if (root == NULL) return result;
// 先存入root
my_stack.push(root);
while (!my_stack.empty()) {
// 存数操作,出栈操作
TreeNode* temp = my_stack.top();
my_stack.pop();
result.push_back(temp->val);
// 这里必须先存如right才可以,因为栈先进后出。
if (temp->right) my_stack.push(temp->right); // 空节点不如栈
if (temp->left) my_stack.push(temp->left); // 空节点不如栈
}
return result;
}
};
细节都在代码中,请各位录友友看看咯,首先是先存节点,再存数,然后存右指针,再存左指针。
3、中序遍历代码:
我自己已经忘记了怎么去遍历中序了,看完卡哥的题解后恍然大悟,我总结了以下几点:
1、先设置一个cur遍历到二叉树的最左边(存到stack里面)。
2、到cur==NULL时,就从栈中弹出元素。
3、记录元素,看右子树是否存在。
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> my_stack;
if (root == NULL) return result;
TreeNode* cur = root;
while (cur != NULL || !my_stack.empty()) {
// 一直往左边找,边记录,找到最后的叶子节点
if (cur != NULL) {
my_stack.push(cur);
cur = cur->left;
} else {
// cur == NULL 就从栈中弹出元素,记录
cur = my_stack.top();
my_stack.pop();
// 记录
result.push_back(cur->val);
// 看右指针是否存在,在if上判断,存在right就继续往下遍历了。
cur = cur->right;
}
}
return result;
}
4、后序遍历代码:
后续迭代遍历与先序迭代遍历大差不差,只需要把从循环遍历出来的元素顺序变为中右左,然后在反转一下,就OK了。
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> my_stack;
if (root == NULL) return result;
my_stack.push(root);
while (!my_stack.empty()) {
TreeNode* node = my_stack.top();
my_stack.pop();
// 存数
result.push_back(node->val);
// 先插入左元素,因为先进后出
if (node->left) my_stack.push(node->left);
// 同理
if (node->right) my_stack.push(node->right);
}
// 先出来的是右元素,所以最终的元素排序就是中右左,所以只要反转一下就OK了
reverse(result.begin(), result.end());
return result;
}
四、统一迭代
今天比较累了,还是放过他吧。。
今日学习时间1个半小时。很有收获,初步了解了递归以及其迭代