1. 二叉树遍历基础概念
二叉树是一种非常重要的非线性数据结构,在计算机科学中有着广泛的应用。理解二叉树的遍历方式是掌握树结构操作的基础。二叉树的遍历指的是按照某种顺序访问树中的所有节点,确保每个节点都被访问且仅被访问一次。
1.1 为什么需要多种遍历方式
不同的遍历顺序会产生不同的节点访问序列,这些序列在不同场景下各有优势:
- 先序遍历:适合需要优先处理父节点再处理子节点的场景,如复制整个树结构
- 中序遍历:对二叉搜索树会得到有序序列,常用于排序和搜索操作
- 后序遍历:适用于需要先处理子节点再处理父节点的场景,如计算子树特征值
1.2 二叉树节点定义
在C++中,我们通常这样定义二叉树节点:
cpp复制struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
这个简单的结构体包含:
val:存储节点的值left:指向左子节点的指针right:指向右子节点的指针
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先序遍历(Preorder Traversal)
2.1 递归实现
递归实现是最直观的方式,完美体现了"分而治之"的思想:
cpp复制void preorderRecursive(TreeNode* root) {
if (root == nullptr) return;
// 访问根节点
cout << root->val << " ";
// 遍历左子树
preorderRecursive(root->left);
// 遍历右子树
preorderRecursive(root->right);
}
注意事项:递归实现虽然简洁,但当树的高度很大时可能导致栈溢出。对于极端不平衡的树(如退化成链表),递归深度可能达到O(n)。
2.2 迭代实现
使用栈来模拟递归调用栈:
cpp复制void preorderIterative(TreeNode* root) {
if (root == nullptr) return;
stack<TreeNode*> st;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
st.pop();
cout << node->val << " ";
// 注意:先右后左,因为栈是LIFO
if (node->right) st.push(node->right);
if (node->left) st.push(node->left);
}
}
这种实现的时间复杂度为O(n),空间复杂度在最坏情况下也是O(n)(当树退化成链表时)。
2.3 莫里斯遍历
莫里斯遍历的巧妙之处在于它利用了树中的空指针来存储临时信息,实现了O(1)的额外空间:
cpp复制void preorderMorris(TreeNode* root) {
TreeNode* curr = root;
while (curr != nullptr) {
if (curr->left == nullptr) {
cout <
