?声明:本文原题主要来自力扣力扣,记录此博客主要是为自己学习总结,不做任何商业等活动
本文主要讲解二叉树的前序遍历递归法和迭代法。
一、前序遍历递归法
前序遍历递归法主要是先遍历父节点parent,然后遍历左子节点,最后遍历右子节点,具体可以参考博客:二叉树基本知识点图文介绍(全网最简洁)_净无邪博客-CSDN博客。
下面力扣一道二叉树前序遍历题目:
给你二叉树的根节点?root ?,返回它节点值的?前序?遍历。
示例 1:
输入:root = [1,null,2,3]
输出:[1,2,3]
1.1具体解法如下
递归法的要诀是找到递归退出条件和按条件分步进行递归。具体解法比较简单,直接看代码和解释即可理解。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
if(root == nullptr) // 递归退出条件
return datas;
else
datas.push_back(root->val); // 递归遍历父节点,也是当前节点
preorderTraversal(root->left); // 递归遍历左子节点
preorderTraversal(root->right); // 递归遍历右子节点
return datas;
}
private:
vector<int> datas;
};
1.2总结
递归法虽然简洁容易理解,但是当二叉树节点很多时,比如十万个,则十分容易出现栈溢出,所以需要采用更为优化的遍历方法,最常用的是迭代法。
二、前序遍历迭代法
迭代法,也成为非递归法解前序遍历时,需要依靠一个栈数据结构依次遍历每一个节点。实现方法为将每个节点压入栈。注意,栈是先进后出结构,所以需要先压入右节点,再压入左节点,弹出的时候才能先弹出左节点,再弹出右节点进行前序遍历访问。
2.1具体解法步骤
a1 现将父节点压入栈(注意判断异常,如果为空则直接返回)
if (root == nullptr)
return datas;
std::stack<TreeNode*> nodeStack;
TreeNode* cur = nullptr;
nodeStack.push(root);
a2 循环遍历栈,如果为空则退出循环;
while (!nodeStack.empty())
{
cur = nodeStack.top(); // 遍历当前节点
nodeStack.pop();
datas.push_back(cur->val);
// ... 压入左右节点,然后逐个弹出进行访问
}
a3 遍历的时候分别将右节点和左节点依次压入栈
while (!nodeStack.empty())
{
cur = nodeStack.top(); // 遍历当前节点
nodeStack.pop();
datas.push_back(cur->val);
// ... 压入左右节点,然后逐个弹出进行访问
if (cur->right != nullptr)
nodeStack.push(cur->right); // 压入右节点
if (cur->left != nullptr)
nodeStack.push(cur->left); // 压入左节点
}
2.2 二叉树前序遍历迭代法完整代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
if(root == nullptr)
return datas;
std::stack<TreeNode*> nodeStack;
TreeNode *cur = nullptr;
nodeStack.push(root);
while(!nodeStack.empty())
{
cur = nodeStack.top();
nodeStack.pop();
datas.push_back(cur->val);
if(cur->right != nullptr)
nodeStack.push(cur->right);
if(cur->left != nullptr)
nodeStack.push(cur->left);
}
return datas;
}
private:
vector<int> datas;
};
2.3 总结
由于上面的迭代法前序遍历二叉树可知,这种方法优点是避免了二叉树节点多时栈溢出。主要实现思路是模拟程序的栈结构,按照前序遍历的顺序依次遍历每个二叉树节点,保证每个节点有且仅有依次遍历和访问,实现这个保证的数据结构是栈。那么,同时,也可以采用队列数据结构进行保证,具体做法是用依次将每个待遍历节点按照前序遍历顺序压入队列,然后依次弹出每个节点进行访问,直到整个队列为空,则所有节点被访问了一次。通过这个迭代法的解法,可以反推图的每个节点访问要保证有且仅有依次访问,也可以采用这种将待访问节点压队列,访问完后弹出队列,然后将所有关联节点依次压入队列直到整个队列为空即完成整个图所有节点有且仅有一次访问。
|