「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战」
二叉树的遍历方式
- 深度优先遍历(使用栈)
- 广度优先遍历(使用队列)
深度优先遍历
- 前序遍历(中左右)
- 中序遍历(左中右)
- 后序遍历(左右中) 注:上面的三种遍历方式可以使用递归法也可以使用迭代法
递归遍历
/*
递归遍历:
递归算法三要素:
1、确定递归函数的参数与返回值
(递归中需要处理的参数 与 每次递归结束需要返回的结果值)
2、确定终止条件
(递归算法最常见的错误就是栈溢出,原因是终止条件没有写正确)
3、确定单层递归的逻辑
(每层递归要处理的逻辑)
二叉树的递归遍历:
1、前序遍历
2、中序遍历
3、后序遍历
*/
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL){};
};
class Traversal
{
public:
// 前序遍历
void preTraversal(TreeNode *node, vector<int> &vec)
{
// 终止条件
if (node == NULL)
{
return;
}
// 递归逻辑
vec.push_back(node->val);
preTraversal(node->left, vec);
preTraversal(node->right, vec);
}
vector<int> preTraversalResult(TreeNode *root)
{
vector<int> vec;
preTraversal(root, vec);
return vec;
}
// 中序遍历
void midTraversal(TreeNode *node, vector<int> &vec)
{
if (node == NULL)
{
return;
}
midTraversal(node->left, vec);
vec.push_back(node->val);
midTraversal(node->right, vec);
}
vector<int> midTraversalResult(TreeNode *root)
{
vector<int> vec;
midTraversal(root, vec);
return vec;
}
// 后续遍历
void postTraversal(TreeNode *node, vector<int> &vec)
{
if (node == NULL)
{
return;
}
postTraversal(node->left, vec);
postTraversal(node->right, vec);
vec.push_back(node->val);
}
vector<int> postTraversalResult(TreeNode *root)
{
vector<int> vec;
postTraversal(root, vec);
return vec;
}
};
迭代遍历
class Traversal
{
public:
// 根据栈的特性
// 前序遍历
// 遍历过程:中 左 右
// 根节点入栈
// 遍历子树的过程中先将右子树入栈,在将左子树入栈
// 这样出栈的时候就是 : 根节点出栈 -- 左子树出栈 -- 右子树出栈
vector<int> preorderTraversal(TreeNode *root)
{
stack<TreeNode *> st;
vector<int> result;
if (root == NULL)
{
return result;
}
// 先将根节点入栈
st.push(root);
while (!st.empty())
{
// 指针指向栈顶节点
TreeNode *cur = st.top();
// 栈顶节点出栈(即每棵树的根节点)
st.pop();
result.push_back(cur->val);
// 先将右子树入栈
if (cur->right != NULL)
{
st.push(cur->right);
}
// 左子树入栈
if (cur->left != NULL)
{
st.push(cur->left);
}
}
return result;
}
// 后序遍历
// 后续遍历的过程为 左右中,所以可以由前序遍历变化得到
// 变化过程: 中左右 -> 中右左 ->(反转)左右中
// 所以对于前序遍历的入栈过程:从 中右左 -> 中左右 即可
vector<int> postorderTraversal(TreeNode *root)
{
stack<TreeNode *> st;
vector<int> result;
if (root == NULL)
{
return result;
}
// 根节点入栈
st.push(root);
while (!st.empty())
{
// 获取栈顶节点,并出栈
TreeNode *cur = st.top();
st.pop();
result.push_back(cur->val);
// 左子树入栈
if (cur->left)
{
st.push(cur->left);
}
// 右子树入栈
if (cur->right)
{
st.push(cur->right);
}
}
reverse(result.begin(), result.end());
return result;
}
// 中序遍历
// 遍历过程:左 中 右
// 先将最左侧子树的左子树... 入栈
vector<int> midorderTraversal(TreeNode *root)
{
stack<TreeNode *> st;
vector<int> result;
TreeNode *cur = root;
// 当前节点的左子树非空或者栈非空
while (cur != NULL || !st.empty())
{
if (cur != NULL)
{
st.push(cur);
cur = cur->left;
}
else
{
// 左子树出栈
TreeNode *node = st.top();
st.pop();
result.push_back(node->val); // 中
if (node->right)
{
st.push(node->right); // 右
}
}
}
return result;
}
};
广度优先遍历
- 层次遍历(迭代法)
代码
class Traversal
{
public:
vector<vector<int>> levelOrder(TreeNode *root)
{
queue<TreeNode *> que;
if (root != NULL)
{
que.push(root);
}
vector<vector<int>> result;
while (!que.empty())
{
int size = que.size();
vector<int> vec;
// 这里一定要使用固定大小的size,不要使用que.size()
// 因为que.size()是不断变化的
for (int i = 0; i < size; i++)
{
TreeNode *node = que.front();
que.pop();
vec.push_back(node->val);
if (node->left)
{
que.push(node->left);
}
if (node->right)
{
que.push(node->right);
}
}
result.push_back(vec);
}
return result;
}
// 反转数组元素
void reverseVector(vector<vector<int>> &result)
{
int left = 0, right = result.size() - 1;
while (left < right)
{
vector<int> tmp = result[left];
result[left] = result[right];
result[right] = tmp;
}
}
};