算法记录第11天 [二叉树]
1.LeetCode 144. 二叉树的前序遍历 94. 二叉树的中序遍历 145. 二叉树的后序遍历
题目描述:
- 给你一棵二叉树的根节点 root ,返回其节点值的 前序、中序、后序遍历 。
递归法核心思想 :
-
递归遍历:
- 利用递归的方式进行树的前序遍历,强调对树结构的深度优先搜索。前序遍历的顺序为:访问根节点 → 遍历左子树 → 遍历右子树。
-
访问节点:
- 在遍历过程中,首先访问当前节点并将其值存储到结果数组中。这确保了每个节点的值都能按照前序的顺序被记录。
/*递 归 法*/
// 前序遍历
void traversal(TreeNode* root,vector<int>& vec){
if (root == NULL) return;
vec.push_back(root->val);
traversal(root->left,vec);
traversal(root->right,vec);
}
// 中序遍历
void traversal(TreeNode* root, vector<int>& vec){
if(root==nullptr) return;
traversal(root->left,vec);
vec.push_back(root->val);
traversal(root->right,vec);
}
// 后序遍历
void traversal(TreeNode* root, vector<int>& vec){
if(root==nullptr) return;
traversal(root->left,vec);
traversal(root->right,vec);
vec.push_back(root->val);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root,result);
return result;
}
遍历法核心思想 :
-
非递归遍历:
- 利用栈(
stack
)模拟递归过程,通过手动管理栈来实现树的遍历,避免了递归调用的开销和可能的栈溢出。
- 利用栈(
-
前序遍历:
- 前序遍历的顺序为:根节点 → 左子树 → 右子树。通过将右子节点先入栈,再将左子节点入栈,确保在处理时左子节点会优先被访问,从而实现正确的遍历顺序。
/*遍 历 法*/
// 前序
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) st.push(node->right); // 右(空节点不入栈)
if (node->left) st.push(node->left); // 左(空节点不入栈)
}
return result;
}
- 中序遍历:
- 中序遍历的顺序为:左子树 → 根节点 → 右子树。通过先遍历左子树、记录根节点值,放入栈中。再遍历右子树,确保正确的遍历顺序。
/*遍 历 法*/
// 中序
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
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;
}
- 后序遍历
- 后序遍历的顺序为:左子树 → 右子树 → 根节点。通过先访问并记录根节点,再入栈左右子树,最终通过反转结果获得正确顺序。
- 在遍历完成后,利用反转操作将记录的节点值顺序调整为后序遍历的标准顺序。
/*遍 历 法*/
// 后序
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;
}
总结
三道题基本一样,只需要确定好一个递归的顺序就可以。而在遍历法中,需要分析清楚如何入栈与出栈。
2.LeetCode 102. 二叉树的层序遍历
题目描述:
- 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
- 示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
题目链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/description/
核心思想 :
-
层序遍历实现:
- 使用队列(
queue
)来实现二叉树的层序遍历,依次访问每一层的节点。
- 使用队列(
-
分层记录结果:
- 每层的节点值存储在一个独立的向量中,方便将不同层的结果汇总到最终结果中。
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> que;
vector<vector<int>> result;
if(root != nullptr) que.push(root);
while(!que.empty()){
// 记录这一层的节点数
int size = que.size();
vector<int> vec;
// 将这一层遍历
for(int i=0;i<size;i++){
TreeNode* tem = que.front();
vec.push_back(tem->val);
que.pop();
if(tem->left!=nullptr) que.push(tem->left);
if(tem->right!=nullptr) que.push(tem->right);
}
result.push_back(vec);
}
return result;
}
总结
每次经过一个for循环就会遍历一层,所以只需要再循环式将所有节点放入队列中即可。