解题思路
1.题目描述
”n叉树定义
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
1.1 前序遍历-589
给定一个 n 叉树的根节点 root ,返回 其节点值的前序遍历 。
n 叉树 在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。
示例1:
输入:root = [1,null,3,2,4,null,5,6]
输出:[1,3,5,6,2,4]
示例2:
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:[1,2,3,6,7,11,14,4,8,12,5,9,13,10]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal
1.2 后序遍历590
给定一个 n 叉树的根节点 root ,返回 其节点值的 后序遍历 。
n 叉树 在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。
示例1:
输入:root = [1,null,3,2,4,null,5,6]
输出:[5,6,3,2,4,1]
示例2:
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:[2,6,14,11,7,3,12,8,4,13,9,10,5,1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal
2.题目分析
模拟二叉树的递归与迭代方式实现,原理基本相同,细节部分见代码注释。
3.题目解答
3.1 前序遍历
3.1.1 前序递归
class Solution {
public:
void preorderTraverse(Node* root,vector<int>& ivec){
if(root == nullptr) return;
ivec.push_back(root->val);
for(Node *cur : root->children){
preorderTraverse(cur,ivec);
}
}
vector<int> preorder(Node* root) {
vector<int> ivec;
preorderTraverse(root,ivec);
return ivec;
}
};
3.1.2前序迭代
class Solution {
public:
vector<int> preorder(Node* root) {
vector<int> ivec;
stack<Node*> st;
if(root == nullptr) return ivec;
// 保存当前节点的子节点访问记录
unordered_map<Node*,int> mni;
Node* node = root;
while(!st.empty() || node){
while(node){
ivec.emplace_back(node->val);
st.push(node);
// 只有当前节点有着子节点才能进行访问
if(node->children.size()>0){
mni[node]=0;
node = node->children[0];
}
else node = nullptr;
}
// 读取栈顶元素并操作
node = st.top();
// 获取上次访问此节点的子节点下标
int index = mni.count(node)>0 ?mni[node]:-1;
index+=1;
// 如果子节点未访问完
if(index < node->children.size()){
mni[node]=index;
node = node->children[index];
}else{
//若节点的子节点已经访问完,弹出此节点
st.pop();
mni.erase(node);
node = nullptr;
}
}
return ivec;
}
};
3.2 前序遍历
3.2.1 后序递归
void postTraverse(Node* root,vector<int> &iv){
if(root == nullptr) return;
// 先遍历子节点,再遍历父节点
for(int i=0;i<root->children.size();i++){
postTraverse(root->children[i],iv);
}
iv.emplace_back(root->val);
}
vector<int> postorder(Node* root) {
vector<int>ivec;
postTraverse(root,ivec);
return ivec;
}
3.2.2 后序迭代
vector<int> postorder(Node* root) {
vector<int>ivec;
stack<Node*>st;
if(root == nullptr) return ivec;
Node *node = root;
// 子节点访问记录标记
unordered_map<Node*,int> mni;
while(!st.empty() || node){
//最左边下沉
while(node){
st.emplace(node);
//若当前节点有子节点
if(node->children.size() > 0){
mni[node] = 0;
node = node->children[0];
}else{
node = nullptr;
}
}
node = st.top();
int index = mni.count(node)>0 ? mni[node]:-1;
index+=1;
if(index<node->children.size()){
mni[node] = index;
node = node->children[index];
}else{
// 元素出栈之前才能压入数组,
// 出栈说明其子节点刚刚都访问完
ivec.emplace_back(node->val);
st.pop();
mni.erase(node);
node = nullptr;
}
}
return ivec;
}
总结:树的算法实现与其遍历密不可分,可以参考本文学习二叉树的遍历