1. 多叉树遍历
1.1 深度优先遍历
深度优先遍历:从根节点开始先沿着树的一个枝遍历到叶子节点,再遍历其他的枝。深度优先遍历又分为先序遍历和后序遍历
先序遍历
上图树的先序遍历结果:A → B → D → G → H → I → C → E → J → F
递归深度优先遍历:先序遍历
以 力扣589题:叉树的前序遍历 为例
/*
// 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;
}
};
*/
class Solution {
public:
vector<int> preorder(Node* root) {
if(nullptr == root) return {
}; // 空节点返回空
vector<int> res;
res.push_back(root->val); // 访问当前根节点
for(auto child:root->children){
vector ans = preorder(child); // 每一个子节点都做一次遍历
res.insert(res.end(),ans.begin(),ans.end()); // 把返回值的一串数加到res的后面
}
return res;
}
};
非递归深度优先遍历:先序遍历
以 上图树 为例,使用栈可以实现
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
class Node{
public:
char val;
vector<Node*> children;
Node(int val):val(val){
} // 构造函数
void AppendChild(Node* child){
// 放入children里
children.push_back(child);
}
};
// 前序
void preorder(const Node* root){
if(nullptr == root) return;
/* // 递归写法
cout << root->val << endl;
for(auto child:root->children){
// cout << root->val << "--" << child->val << endl;
preorder(child);
}
*/
// 非递归写法
vector<const Node*> s;
s.push_back(root); // 入栈
while(!s.empty()){
cout << "栈内节点有:";
for(auto p:s) cout << p->val << " "; // 看看栈内数据
cout << endl;
const Node* cur = s.back();
s.pop_back(); // 出栈
cout << "出栈:" << cur->val << endl; // 看看出栈的是哪个节点
auto& children = cur->children;
for(auto it=children.rbegin();it!=children.rend();++it){
// 出栈后要把它的所有子节点放入栈
s.push_back(*it);
}
}
}
int main(){
Node a('A');
Node b('B');
Node c('C');
Node d('D');
Node e('E');
Node f('F');
Node g('G');
Node h('H');
Node i('I');
Node j('J');
a.AppendChild(&b);
a.AppendChild(&c);
b.AppendChild(&d);
d.AppendChild(&g);
d.AppendChild(&h);
d.AppendChild(&i);
c.AppendChild(&e);
c.AppendChild(&f);
e.AppendChild(&j);
preorder(&a);
}
结果为:
栈内节点有:A
出栈:A
栈内节点有:C B
出栈:B
栈内节点有:C D
出栈:D
栈内节点有:C I H G
出栈:G
栈内节点有:C I H
出栈:H
栈内节点有:C I
出栈:I
栈内节点有:C
出栈:C
栈内节点有:F E
出栈:E
栈内节点有:F J
出栈:J
栈内节点有:F
出栈:F
在一个节点出栈后把这个节点的子节点(反着)全部放入栈内,然后再出栈,以此类推,把出栈的顺序即为前序遍历的顺序
后序遍历
上图树的后序遍历结果:G → H → I → D → B → J → E → F → C → A
递归深度优先遍历:后序遍历
以 力扣590题:叉树的后序遍历 为例
/*
// 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;
}
};
*/
class Solution {
public:
vector<int> postorder(Node* root) {
if(nullptr == root) return {
};
vector<int> res;
for(auto child:root->children){
vector ans = postorder(child);
res.insert(res.end(),ans.begin(),ans.end());
}
res.push_back(root->val); // 子节点都访问完了,最后访问当前根
return res;
}
};
非递归深度优先遍历:后序遍历
以 上图树 为例,对照先序遍历,使用两个栈可以实现
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
class Node{
public:
char val;
vector<Node*> children;
Node(int val):val(val){
} // 构造函数
void AppendChild(Node* child){
// 放入children里
children.push_back(child);
}
};
// 后序
void postorder(const Node* root){
if(nullptr == root) return;
vector<const Node*> s;
vector<const Node*> t; // 再创建一个栈
s.push_back(root);
while(!s.empty()){
cout << "栈内节点有:";
for(auto p:s) cout <&