前言
二叉树的遍历方法分为深度优先遍历与宽度优先遍历,其中深度优先遍历又以根节点的访问时机分为前序遍历、中序遍历与后序遍历,而宽度优先遍历(层序遍历)则是一层一层往下遍历。
正文
前序遍历
前序遍历有递归和迭代两种实现方式
递归实现:
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {} //构造函数初始化
};
void preorderTraversal(TreeNode* root, vector<int>& result) {
if (root == NULL) {
return;
}
result.push_back(root->val); // 将当前节点的值加入结果列表
preorderTraversal(root->left, result); // 递归访问左子树
preorderTraversal(root->right, result); // 递归访问右子树
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
preorderTraversal(root, result); // 调用重载函数
return result;
}
迭代实现:
void preorderTraversal(TreeNode* root) {
if (root == nullptr) {
return;
}
std::stack<TreeNode*> stack;
stack.push(root);
while (!stack.empty()) {
TreeNode* current = stack.top();
stack.pop();
std::cout << current->value << " "; // 访问节点
if (current->right != nullptr) {
stack.push(current->right);
}//右孩子先进后出
if (current->left != nullptr) {
stack.push(current->left);
}//左孩子后进先出
}
}
中序遍历
中序遍历的递归实现与前序遍历的区别仅仅是:中序遍历在递归访问左子树和递归访问右子树之间将节点加入结果列表。
void preorderTraversal(TreeNode* root, vector<int>& result) {
if (root == NULL) {
return;
}
preorderTraversal(root->left, result); // 递归访问左子树
result.push_back(root->val); // 将当前节点的值加入结果列表
preorderTraversal(root->right, result); // 递归访问右子树
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
preorderTraversal(root, result); // 调用重载函数
return result;
}
同理,后序遍历则是在递归访问左子树和右子树之后将节点加入结果列表,代码不在赘述。
中序遍历的迭代实现也是通过栈来实现:
我们使用了一个栈来保存经过的节点。我们从根节点开始,将当前节点以及其左子树中的节点都入栈,直到遇到叶子节点。然后,弹出栈顶节点,将其值加入结果列表,并将当前节点指向其右子树。然后,重复上述步骤,直到栈为空且当前节点为空。最终,返回得到的结果列表,即为中序遍历的结果。代码如下:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
TreeNode* curr = root;
while (curr != nullptr || !stk.empty()) {
while (curr != nullptr) {
stk.push(curr);
curr = curr->left;
}
curr = stk.top();
stk.pop();
res.push_back(curr->val);
curr = curr->right;
}
return res;
}
后序遍历
后序遍历的迭代实现:
我们从根节点开始,将每个节点以及其左子树中的节点都入栈,直到遇到叶子节点。然后,检查栈顶节点的右子树是否为空,或者是否已经访问过。如果是,则将栈顶节点的值加入结果列表,并将其弹出栈。然后,将prev
指针指向当前弹出的节点,继续处理下一个节点。如果栈顶节点的右子树不为空且未被访问过,则将当前节点指向其右子树,继续迭代处理右子树。最终,返回得到的结果列表,即为后序遍历的结果。
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
TreeNode* prev = nullptr;
while (root != nullptr || !stk.empty()) {
while (root != nullptr) {
stk.push(root);
root = root->left;
}
root = stk.top();
if (root->right == nullptr || root->right == prev) {
res.push_back(root->val);
stk.pop();
prev = root;
root = nullptr;
} else {
root = root->right;
}
}
return res;
}
宽度优先遍历(层次遍历)
宽度优先遍历通过队列来实现,代码如下:
vector<int> bfs(TreeNode* root) {
vector<int> res;
if (root == nullptr) return res;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* curr = q.front();
q.pop();
res.push_back(curr->val);
if (curr->left != nullptr) {
q.push(curr->left);
}
if (curr->right != nullptr) {
q.push(curr->right);
}
}
return res;
}