树的遍历
来源:互联网 发布:西蒙网络面板 有问题 编辑:程序博客网 时间:2024/05/18 10:57
概述
树的遍历分为深度优先遍历和广度优先遍历。深度优先遍历又分为前序遍历、中序遍历、后序遍历。前序遍历的顺序为:父节点、左子节点、右子节点,中序遍历的顺序为:左子节点、父节点、右子节点,后序遍历的顺序为:左子节点、右子节点、父节点。广度优先遍历即从根节点从上往下逐层遍历,每层从左到右遍历。可以通过递归的方式或者使用栈来实现遍历,递归方式和使用栈的方式都需要遍历n个节点,所以时间复杂度为o(n);采用递归方式,需要n次递归调用,所以空间复杂度为o(n),使用栈的方式,栈需要存储空间,栈的大小为n,所以空间复杂度为o(n)
前序遍历
●递归版
思路:按照遍历的顺序进行递归调用即可;退出递归调用的条件:节点为空
#include<iostream>#include<vector>using namespace std;struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};void preorder(TreeNode *root,vector<int>&result) { if (!root) return; result.push_back(root->val); preorder(root->left,result); preorder(root->right,result);}
●非递归版
思路:从根节点开始依次将节点入栈,栈顶节点即为本次需要访问的节点,访问过栈顶节点后,然后将此节点弹出,分别将右子节点入栈、左子节点入栈,然后进行下一次访问,直到栈为空,即访问完所有节点。
#include<iostream>#include<vector>#include<stack>using namespace std;struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};vector<int>preorder(TreeNode *root){ vector<int> result; stack<TreeNode *> sta; TreeNode *p ; if (!root) return result; else sta.push(root); while(!sta.empty()) { p = sta.top(); sta.pop(); result.push_back(p->val); if (p->right) sta.push(p->right); if (p->left) sta.push(p->left); } return result;}
后序遍历
●递归版
思路:按照遍历的顺序进行递归调用即可;退出递归调用的条件:节点为空
#include<iostream>#include<vector>using namespace std;struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};void postorder(TreeNode *root, vector<int>&result) { if (!root) return; postorder(root->left); postorder(root->right); result.push_back(root->val);}
●非递归版
思路:后序遍历的顺序是左字节点、右子节点、父节点。可以先访问父节点,将父节点保存到动态数组中,然后访问右子节点,将右子节点保存到动态数组的第一个元素处,最后访问左子节点,并保存到动态数组的一个元素处,最后动态数组中元素的顺序为左字节点、右子节点、父节点。思路与前序遍历基本相同,只是将正在访问的元素存入动态数组vector.begin()处,而前序遍历是存入vector.end()处
#include<iostream>#include<vector>#include<stack>using namespace std;struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};vector<int> postorder(TreeNode* root) { vector<int> result; stack<TreeNode *> sta; TreeNode *p; if (!root) return result; else sta.push(root); while (!sta.empty()) { p = sta.top(); sta.pop(); result.insert(result.begin(), p->val); if (p->left) sta.push(p->left); if (p->right) sta.push(p->right); } return result;}
中序遍历
●递归版
思路:按照遍历的顺序进行递归调用即可;退出递归调用的条件:节点为空
#include<iostream>#include<vector>using namespace std;struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};void inorder(TreeNode *root,vector<int>&result) { if (root == NULL) return; inorder(root->left); result.push_back(root->val); inorder(root->right);}
●非递归版
思路:与之前前序遍历和后序遍历不同的是,父节点的访问顺序介于左子节点和右子节点之间,需要先访问左子节点,然后再回退访问父节点,最后访问右子节点,另外访问结束的条件与前序和后续遍历也不同,只有当栈为空且节点为空才代表访问完了所有节点,栈为空说明访问完了根节点的左子树,节点为空说明当前节点的父节点不存在左子节点,不用访问左子节点。
#include<iostream>#include<vector>#include<stack>using namespace std;struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};vector<int>inorder(TreeNode *root){ vector<int> result; stack<TreeNode *> sta; TreeNode *p = root; if (root == nullptr) return result; while (p != nullptr||!sta.empty()) { if (p != nullptr) { sta.push(p); p = p->left; } else { p = sta.top(); sta.pop(); result.push_back(p->val); p = p->right; } } return result;}
层序遍历
思路:层序遍历即从根节点所在层从上往下逐层遍历,每一层从左到右进行遍历,可以使用二维数组作为存储结构,将相同层的节点存入同一个数组中。
#include<iostream>#include<vector>#include<stack>using namespace std;struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}};void travel(TreeNode *p, int level, vector<vector<int>>&result){ if (!p) return ; while (level > result.size()) result.push_back(vector<int>()); result[level - 1].push_back(p->val); travel(p->left, level + 1, result); travel(p->right, level + 1, result);}vector<vector<int>>level(TreeNode *root){ vector<vector<int>>result; travel(root, 1, result); return result;}
相关问题
打印出二叉树中和为某一值的所有路径,从树的根节点到叶子节点算作一条路径
思路:直到访问到叶子节点时才能判断路径是否符合要求,因此需要变量存储已访问节点的路径和。在访问到叶子节点之前,需要将之前访问过的节点保存起来,从而在路径满足要求时,可以打印路径。可以通过递归的方式,访问各个节点,先访问父节点,然后访问左字节点和右子节点,访问到叶子节点时,退出递归函数。每访问过一个节点,需要将节点从路径中删除,从而访问由此节点的兄弟节点构成的路径。
#include<iostream>#include<vector>using namespace std;struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int value) :val(value), left(nullptr), right(nullptr){}};void findpath(TreeNode *root, int tar,int cursum, vector<int>&result){ TreeNode *p = root; cursum+=root->val; result.push_back(root->val); if (p->left == nullptr&&p->right == nullptr) { if (cursum == tar) { for (int i = 0; i < result.size(); i++) cout << result[i] << " "; cout << endl; } result.pop_back(); return; } if (p->left) findpath(p->left, tar, cursum, result); if (p->right) findpath(p->right, tar, cursum, result); result.pop_back();}void findpath(TreeNode *root, int tar){ vector<int> result; if (root == nullptr) return ; int cursum = 0; findpath(root, tar,cursum ,result);}
- 二叉树的遍历(层遍历和深度遍历)
- 二叉树的前序中序后序遍历,非递归遍历 层次遍历
- 二叉树的先中后序遍历,递归遍历,非递归遍历
- 二叉树遍历-----前序后序迭代遍历的新思路
- 二叉树的遍历-按层次遍历
- 二叉树的遍历(递归遍历)
- 二叉树的遍历-层次遍历
- 树的遍历
- 六、 树的遍历
- 二叉树的遍历
- haffman树的遍历
- 二叉树的遍历
- 树的各种遍历
- 树的遍历
- 二叉树的遍历
- C++树的遍历
- Java树的遍历
- 树的简单遍历
- 用两个栈实现队列
- 清单文件的具体介绍
- switch
- 收藏的网站
- 嵌入式实时操作系统ucos/ii 原理与应用(五)
- 树的遍历
- File对象的常用方法
- 编写视图函数
- 动态规划问题系列---Unique Paths II
- (转)如何查询Oracle中所有用户信息
- Android中资源文件的使用
- linux C 代码格式化工具indent
- EditPlus取消自动备份文件
- POJ 2377