欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 资讯 > c/c++蓝桥杯经典编程题100道(17)二叉树遍历

c/c++蓝桥杯经典编程题100道(17)二叉树遍历

2025/2/10 11:39:01 来源:https://blog.csdn.net/wumingkun319/article/details/145524498  浏览:    关键词:c/c++蓝桥杯经典编程题100道(17)二叉树遍历

二叉树遍历

->返回c/c++蓝桥杯经典编程题100道-目录


目录

二叉树遍历

一、题型解释

二、例题问题描述

三、C语言实现

解法1:递归前序遍历(难度★)

解法2:迭代中序遍历(难度★★)

解法3:层次遍历(BFS,难度★★)

四、C++实现

解法1:递归后序遍历(难度★)

解法2:迭代前序遍历(难度★★)

解法3:锯齿形层次遍历(难度★★★)

五、总结对比表

六、特殊方法与内置函数补充

1. C++ STL容器

2. Morris遍历算法(C语言示例)


一、题型解释

二叉树遍历是按照特定顺序访问树中所有节点的操作。常见题型:

  1. 基础遍历:前序、中序、后序遍历(递归或迭代实现)。

  2. 层次遍历(BFS):按层从上到下访问节点。

  3. 变种遍历

    • 锯齿形层次遍历(Zigzag遍历)。

    • 垂序遍历(按列访问节点)。

  4. Morris遍历:使用线索二叉树实现O(1)空间复杂度的遍历。


二、例题问题描述

例题1:输入二叉树:

    1  / \  2   3  / \  
4   5

前序遍历输出 1 2 4 5 3,中序遍历输出 4 2 5 1 3,后序遍历输出 4 5 2 3 1

例题2:输入同上二叉树,层次遍历输出 1 2 3 4 5
例题3:锯齿形层次遍历输出 1 3 2 4 5(第二层反向)。


三、C语言实现

解法1:递归前序遍历(难度★)

通俗解释

  • 像“根→左→右”的顺序探访每个房间,先访问根节点,再递归访问左右子树。

c

#include <stdio.h>
#include <stdlib.h>typedef struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
} TreeNode;void preorderTraversal(TreeNode *root) {if (root == NULL) return;printf("%d ", root->val);  // 先访问根节点preorderTraversal(root->left);  // 递归左子树preorderTraversal(root->right); // 递归右子树
}int main() {// 构建例题1的二叉树TreeNode n4 = {4, NULL, NULL};TreeNode n5 = {5, NULL, NULL};TreeNode n2 = {2, &n4, &n5};TreeNode n3 = {3, NULL, NULL};TreeNode n1 = {1, &n2, &n3};printf("前序遍历:");preorderTraversal(&n1); // 输出 1 2 4 5 3return 0;
}

代码逻辑

  1. 递归终止条件:当前节点为NULL时返回。

  2. 访问顺序:根节点→左子树→右子树。

  3. 时间复杂度:O(n),每个节点访问一次。


解法2:迭代中序遍历(难度★★)

通俗解释

  • 用栈模拟递归过程,像“先深入左子树到底,再回溯访问根节点,最后处理右子树”。

c

#include <stdbool.h>
#define MAX_SIZE 100typedef struct Stack {TreeNode* data[MAX_SIZE];int top;
} Stack;void push(Stack *s, TreeNode *node) {s->data[++s->top] = node;
}TreeNode* pop(Stack *s) {return s->data[s->top--];
}bool isEmpty(Stack *s) {return s->top == -1;
}void inorderTraversal(TreeNode *root) {Stack s = { .top = -1 };TreeNode *curr = root;while (curr != NULL || !isEmpty(&s)) {while (curr != NULL) { // 深入左子树push(&s, curr);curr = curr->left;}curr = pop(&s);        // 回溯到父节点printf("%d ", curr->val);curr = curr->right;    // 处理右子树}
}int main() {printf("\n中序遍历:");inorderTraversal(&n1); // 输出 4 2 5 1 3return 0;
}

代码逻辑

  1. 栈辅助:用栈保存未处理的节点。

  2. 左链入栈:不断将左子节点压栈,直到最左端。

  3. 回溯访问:弹出栈顶节点访问,转向右子树。


解法3:层次遍历(BFS,难度★★)

通俗解释

  • 像逐层扫描,用队列记录每层节点,先访问上层再下层。

c

#include <stdbool.h>
#define MAX_SIZE 100typedef struct Queue {TreeNode* data[MAX_SIZE];int front, rear;
} Queue;void enqueue(Queue *q, TreeNode *node) {q->data[q->rear++] = node;
}TreeNode* dequeue(Queue *q) {return q->data[q->front++];
}bool isEmpty(Queue *q) {return q->front == q->rear;
}void levelOrderTraversal(TreeNode *root) {if (root == NULL) return;Queue q = { .front = 0, .rear = 0 };enqueue(&q, root);while (!isEmpty(&q)) {TreeNode *node = dequeue(&q);printf("%d ", node->val);if (node->left) enqueue(&q, node->left);if (node->right) enqueue(&q, node->right);}
}int main() {printf("\n层次遍历:");levelOrderTraversal(&n1); // 输出 1 2 3 4 5return 0;
}

代码逻辑

  1. 队列初始化:根节点入队。

  2. 循环处理:出队节点并访问,将其子节点入队。

  3. 逐层遍历:队列先进先出特性保证按层访问。


四、C++实现

解法1:递归后序遍历(难度★)

通俗解释

  • 按“左→右→根”顺序访问,先处理左右子树,最后访问根节点。

cpp

#include <iostream>
using namespace std;struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};void postorderTraversal(TreeNode *root) {if (!root) return;postorderTraversal(root->left);  // 先左子树postorderTraversal(root->right); // 再右子树cout << root->val << " ";        // 最后根节点
}int main() {TreeNode *root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);cout << "后序遍历:";postorderTraversal(root); // 输出 4 5 2 3 1return 0;
}

代码逻辑

  • 与C语言递归类似,但使用C++的类和指针语法。


解法2:迭代前序遍历(难度★★)

通俗解释

  • 用栈模拟递归,显式控制访问顺序(根→左→右)。

cpp

#include <stack>
void preorderIterative(TreeNode *root) {if (!root) return;stack<TreeNode*> s;s.push(root);while (!s.empty()) {TreeNode *node = s.top();s.pop();cout << node->val << " ";if (node->right) s.push(node->right); // 右子先入栈(后处理)if (node->left) s.push(node->left);   // 左子后入栈(先处理)}
}int main() {cout << "\n迭代前序遍历:";preorderIterative(root); // 输出 1 2 4 5 3return 0;
}

代码逻辑

  1. 根节点入栈:栈顶为当前访问的根节点。

  2. 右子先入栈:利用栈的LIFO特性,确保左子先被处理。


解法3:锯齿形层次遍历(难度★★★)

通俗解释

  • 层次遍历的变种,偶数层反向输出(用双端队列控制方向)。

cpp

#include <queue>
#include <vector>
void zigzagLevelOrder(TreeNode *root) {if (!root) return;queue<TreeNode*> q;q.push(root);bool leftToRight = true;while (!q.empty()) {int size = q.size();vector<int> level(size);for (int i = 0; i < size; i++) {TreeNode *node = q.front();q.pop();int index = leftToRight ? i : size - 1 - i;level[index] = node->val;if (node->left) q.push(node->left);if (node->right) q.push(node->right);}leftToRight = !leftToRight;for (int num : level) cout << num << " ";}
}int main() {cout << "\n锯齿形遍历:";zigzagLevelOrder(root); // 输出 1 3 2 4 5return 0;
}

代码逻辑

  1. 队列记录当前层:每次处理一层节点。

  2. 方向控制:根据层数奇偶性决定填充顺序。


五、总结对比表

方法时间复杂度空间复杂度优点缺点
递归遍历O(n)O(n)代码简洁栈溢出风险
迭代遍历O(n)O(n)无栈溢出风险需手动管理栈/队列
层次遍历(BFS)O(n)O(n)直观,适合按层处理空间占用较大
Morris遍历O(n)O(1)无需额外空间修改树结构,逻辑复杂

六、特殊方法与内置函数补充

1. C++ STL容器

  • stack<TreeNode*>:用于迭代遍历,支持 push()pop()top()

  • queue<TreeNode*>:用于层次遍历,支持 push()front()pop()

2. Morris遍历算法(C语言示例)

通俗解释

  • 通过修改树的指针,将空间复杂度降为O(1)。

c

void morrisInorder(TreeNode *root) {TreeNode *curr = root, *pre;while (curr != NULL) {if (curr->left == NULL) { // 无左子树,直接访问printf("%d ", curr->val);curr = curr->right;} else {pre = curr->left;while (pre->right != NULL && pre->right != curr) {pre = pre->right; // 找到左子树的最右节点}if (pre->right == NULL) { // 建立线索pre->right = curr;curr = curr->left;} else { // 删除线索并访问pre->right = NULL;printf("%d ", curr->val);curr = curr->right;}}}
}

代码逻辑

  1. 线索化:将当前节点的前驱节点的右指针指向自己,实现回溯。

  2. 遍历与恢复:访问后删除线索,恢复树结构。

c/c++蓝桥杯经典编程题100道-目录-CSDN博客

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com