二叉树-DFS-BFS-递归-非递归
BFS
BFS一般使用非递归的模式访问相对简单,其递归的模式相当于是非递归模式,按每一层打标签访问的结果。使用list保存每一层的需要访问的节点,可以将代码写成递归形式。
非递归形式
主要思想:从根节点以此访问左右子树,然后将访问到的节点按访问顺序依次存储在队列之中,在队列非空的情况下,一直按照这种方案进行即可完成BFS的非递归访问。
#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <string>
#include <list>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int vall){
val = vall;
left = NULL;
right = NULL;
}
};
vector<int> BFSNoRecursive(TreeNode *root){
vector<int> ans;
list<TreeNode *> llist;
if(root == NULL){
return ans;
}
else{
llist.push_back(root);
}
while(!llist.empty()){
TreeNode *temp = llist.front();
ans.push_back(temp->val);
if(temp->left){
llist.push_back(temp->left);
}
if(temp->right){
llist.push_back(temp->right);
}
llist.pop_front();
}
return ans;
}
int main(int argc, const char * argv[]) {
TreeNode *r1 = new TreeNode(1);
TreeNode *r2 = new TreeNode(2);
TreeNode *r3 = new TreeNode(3);
TreeNode *r4 = new TreeNode(4);
TreeNode *r5 = new TreeNode(5);
TreeNode *r6 = new TreeNode(6);
TreeNode *r7 = new TreeNode(7);
r1->left = r2;
r1->right = r3;
r2->left = r4;
r2->right = r5;
r3->left = r6;
r6->right = r7;
vector<int> ans = BFSNoRecursive(r1);
for(int i = 0; i < ans.size(); i++){
cout << ans[i] << " ";
}
return 0;
}
递归形式
主要思想:用一个二维数组记录下每一层的指针,这个过程可以用递归来实现,其实在记录过程中,采用的是dfs的套路。记录完成之后,按层访问每一个节点即可。
#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <string>
#include <list>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int vall){
val = vall;
left = NULL;
right = NULL;
}
};
void bfs(TreeNode *root, int level, vector<vector<TreeNode *> >& llist){
if(root == NULL){
return;
}
if(level >= llist.size()){
vector<TreeNode *> listTemp;
listTemp.push_back(root);
llist.push_back(listTemp);
}
else{
llist[level].push_back(root);
}
bfs(root->left, level+1, llist);
bfs(root->right, level+1, llist);
}
vector<int> BFSRecursive(TreeNode *root){
vector<int> ans;
vector<vector<TreeNode *> > llist;
if(root == NULL){
return ans;
}
else{
bfs(root, 0, llist);
}
for(int i = 0; i < llist.size(); i++){
for(int j = 0; j < llist[i].size(); j++){
ans.push_back(llist[i][j]->val);
}
}
return ans;
}
int main(int argc, const char * argv[]) {
TreeNode *r1 = new TreeNode(1);
TreeNode *r2 = new TreeNode(2);
TreeNode *r3 = new TreeNode(3);
TreeNode *r4 = new TreeNode(4);
TreeNode *r5 = new TreeNode(5);
TreeNode *r6 = new TreeNode(6);
TreeNode *r7 = new TreeNode(7);
r1->left = r2;
r1->right = r3;
r2->left = r4;
r2->right = r5;
r3->left = r6;
r6->right = r7;
vector<int> ans = BFSRecursive(r1);
for(int i = 0; i < ans.size(); i++){
cout << ans[i] << " ";
}
return 0;
}
DFS
DFS的访问模式总共是分为三种,即先序,中序,后序。其中,先中后是相对于根节点而言的。
先序:根,左,右
中序:左,根,右
后序:左,右,根
这三种方式都有递归和非递归两种实现方法,比较简洁理想的是采用递归方式,非递归方式需要借助栈进行实现。
递归形式
只在递归的顺序上有很小的调整!!
先序
#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <string>
#include <list>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int vall){
val = vall;
left = NULL;
right = NULL;
}
};
void DFSRecursive(TreeNode *root, vector<int>& ans){
if(root == NULL){
return;
}
ans.push_back(root->val);
DFSRecursive(root->left, ans);
DFSRecursive(root->right, ans);
}
int main(int argc, const char * argv[]) {
TreeNode *r1 = new TreeNode(1);
TreeNode *r2 = new TreeNode(2);
TreeNode *r3 = new TreeNode(3);
TreeNode *r4 = new TreeNode(4);
TreeNode *r5 = new TreeNode(5);
TreeNode *r6 = new TreeNode(6);
TreeNode *r7 = new TreeNode(7);
r1->left = r2;
r1->right = r3;
r2->left = r4;
r2->right = r5;
r3->left = r6;
r6->right = r7;
vector<int> ans;
DFSRecursive(r1, ans);
for(int i = 0; i < ans.size(); i++){
cout << ans[i] << " ";
}
return 0;
}
中序
#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <string>
#include <list>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int vall){
val = vall;
left = NULL;
right = NULL;
}
};
void DFSRecursive(TreeNode *root, vector<int>& ans){
if(root == NULL){
return;
}
DFSRecursive(root->left, ans);
ans.push_back(root->val);
DFSRecursive(root->right, ans);
}
int main(int argc, const char * argv[]) {
TreeNode *r1 = new TreeNode(1);
TreeNode *r2 = new TreeNode(2);
TreeNode *r3 = new TreeNode(3);
TreeNode *r4 = new TreeNode(4);
TreeNode *r5 = new TreeNode(5);
TreeNode *r6 = new TreeNode(6);
TreeNode *r7 = new TreeNode(7);
r1->left = r2;
r1->right = r3;
r2->left = r4;
r2->right = r5;
r3->left = r6;
r6->right = r7;
vector<int> ans;
DFSRecursive(r1, ans);
for(int i = 0; i < ans.size(); i++){
cout << ans[i] << " ";
}
return 0;
}
后序
#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <string>
#include <list>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int vall){
val = vall;
left = NULL;
right = NULL;
}
};
void DFSRecursive(TreeNode *root, vector<int>& ans){
if(root == NULL){
return;
}
DFSRecursive(root->left, ans);
DFSRecursive(root->right, ans);
ans.push_back(root->val);
}
int main(int argc, const char * argv[]) {
TreeNode *r1 = new TreeNode(1);
TreeNode *r2 = new TreeNode(2);
TreeNode *r3 = new TreeNode(3);
TreeNode *r4 = new TreeNode(4);
TreeNode *r5 = new TreeNode(5);
TreeNode *r6 = new TreeNode(6);
TreeNode *r7 = new TreeNode(7);
r1->left = r2;
r1->right = r3;
r2->left = r4;
r2->right = r5;
r3->left = r6;
r6->right = r7;
vector<int> ans;
DFSRecursive(r1, ans);
for(int i = 0; i < ans.size(); i++){
cout << ans[i] << " ";
}
return 0;
}
非递归形式
需要借助于栈结构,在向下查询的过程中,访问不到的节点先存储在栈中
先序
1、从根节点一路向左访问,并将访问到的每一个节点的指针存储在栈中。
2、由于是先序遍历,则在一路向左访问过程中,首先将每个根节点数据存储在ans中。
3、访问到最左以后,使用栈模拟回溯过程,依次对栈中每一个节点的右子树进行先序遍历。
#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <string>
#include <list>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int vall){
val = vall;
left = NULL;
right = NULL;
}
};
vector<int> DFSNoRecursive(TreeNode *root){
vector<int> ans;
if(root == NULL){
return ans;
}
stack<TreeNode*> s;
TreeNode *temp = root;
while(temp != NULL || !s.empty()){
while(temp != NULL){
ans.push_back(temp->val);
s.push(temp);
temp = temp->left;
}
if(!s.empty()){
temp = s.top();
s.pop();
temp = temp->right;
}
}
return ans;
}
int main(int argc, const char * argv[]) {
TreeNode *r1 = new TreeNode(1);
TreeNode *r2 = new TreeNode(2);
TreeNode *r3 = new TreeNode(3);
TreeNode *r4 = new TreeNode(4);
TreeNode *r5 = new TreeNode(5);
TreeNode *r6 = new TreeNode(6);
TreeNode *r7 = new TreeNode(7);
r1->left = r2;
r1->right = r3;
r2->left = r4;
r2->right = r5;
r3->left = r6;
r6->right = r7;
vector<int> ans = DFSNoRecursive(r1);
for(int i = 0; i < ans.size(); i++){
cout << ans[i] << " ";
}
return 0;
}
中序
基本和先序一致
1、从根节点一路向左访问,并将访问到的每一个节点的指针存储在栈中。
2、由于是中序遍历,则在一路向左访问过程中,不能将每个根节点数据存储在ans中,在回溯时,将根节点数据存储在ans中。
3、访问到最左以后,使用栈模拟回溯过程,依次对栈中每一个节点的右子树进行先序遍历。
#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <string>
#include <list>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int vall){
val = vall;
left = NULL;
right = NULL;
}
};
vector<int> DFSNoRecursive(TreeNode *root){
vector<int> ans;
if(root == NULL){
return ans;
}
stack<TreeNode*> s;
TreeNode *temp = root;
while(temp != NULL || !s.empty()){
while(temp != NULL){
s.push(temp);
temp = temp->left;
}
if(!s.empty()){
temp = s.top();
s.pop();
ans.push_back(temp->val);
temp = temp->right;
}
}
return ans;
}
int main(int argc, const char * argv[]) {
TreeNode *r1 = new TreeNode(1);
TreeNode *r2 = new TreeNode(2);
TreeNode *r3 = new TreeNode(3);
TreeNode *r4 = new TreeNode(4);
TreeNode *r5 = new TreeNode(5);
TreeNode *r6 = new TreeNode(6);
TreeNode *r7 = new TreeNode(7);
r1->left = r2;
r1->right = r3;
r2->left = r4;
r2->right = r5;
r3->left = r6;
r6->right = r7;
vector<int> ans = DFSNoRecursive(r1);
for(int i = 0; i < ans.size(); i++){
cout << ans[i] << " ";
}
return 0;
}
后序
先序和中序基本是一个套路,后序相对复杂一些,需要单独对当前访问树结构的根节点进行记录。相当于记录右子树的访问情况。因为此时,必须确定将左,右子树全部访问完,才访问根节点。
1、从根节点一路向左访问,并将访问到的每一个节点的指针存储在栈中。
2、在回溯过程中,首先将左子树的值记录下来,然后记录当前的根,然后判断右子树是否已经访问,如果未访问,则先访问右子树,最后再记录根节点的值。
#include <iostream>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#include <string>
#include <list>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int vall){
val = vall;
left = NULL;
right = NULL;
}
};
vector<int> DFSNoRecursive(TreeNode *root){
vector<int> ans;
if(root == NULL){
return ans;
}
stack<TreeNode*> s;
TreeNode *temp = root;
TreeNode *last = NULL;
while(temp != NULL || !s.empty()){
while(temp != NULL){
s.push(temp);
temp = temp->left;
}
if(!s.empty()){
temp = s.top();
if(temp->right == NULL || temp->right == last){
ans.push_back(temp->val);
s.pop();
last = temp;
temp = NULL;
}
else{
temp = temp->right;
}
}
}
return ans;
}
int main(int argc, const char * argv[]) {
TreeNode *r1 = new TreeNode(1);
TreeNode *r2 = new TreeNode(2);
TreeNode *r3 = new TreeNode(3);
TreeNode *r4 = new TreeNode(4);
TreeNode *r5 = new TreeNode(5);
TreeNode *r6 = new TreeNode(6);
TreeNode *r7 = new TreeNode(7);
r1->left = r2;
r1->right = r3;
r2->left = r4;
r2->right = r5;
r3->left = r6;
r6->right = r7;
vector<int> ans = DFSNoRecursive(r1);
for(int i = 0; i < ans.size(); i++){
cout << ans[i] << " ";
}
return 0;
}