C++算法(树算法)

1. 二叉树的前序、中序、后序遍历

思路解析:

  • 前序遍历(Pre-order):根 -> 左 -> 右
  • 中序遍历(In-order):左 -> 根 -> 右
  • 后序遍历(Post-order):左 -> 右 -> 根
  • 可以用递归或迭代(栈)实现
  • 时间复杂度:O(N),空间复杂度:O(H),H 为树的高度
#include <iostream>
#include <vector>
#include <stack>

using namespace std;

// 二叉树节点定义
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// ========== 递归实现 ==========

// 前序遍历:根 -> 左 -> 右
void preorderRecursive(TreeNode* root, vector<int>& result) {
    if (root == nullptr) return;
    
    result.push_back(root->val);      // 访问根节点
    preorderRecursive(root->left, result);   // 遍历左子树
    preorderRecursive(root->right, result);  // 遍历右子树
}

// 中序遍历:左 -> 根 -> 右
void inorderRecursive(TreeNode* root, vector<int>& result) {
    if (root == nullptr) return;
    
    inorderRecursive(root->left, result);    // 遍历左子树
    result.push_back(root->val);      // 访问根节点
    inorderRecursive(root->right, result);   // 遍历右子树
}

// 后序遍历:左 -> 右 -> 根
void postorderRecursive(TreeNode* root, vector<int>& result) {
    if (root == nullptr) return;
    
    postorderRecursive(root->left, result);  // 遍历左子树
    postorderRecursive(root->right, result); // 遍历右子树
    result.push_back(root->val);      // 访问根节点
}

// ========== 迭代实现(使用栈)==========

// 前序遍历(迭代)
vector<int> preorderIterative(TreeNode* root) {
    vector<int> result;
    if (root == nullptr) return result;
    
    stack<TreeNode*> st;
    st.push(root);
    
    while (!st.empty()) {
        TreeNode* node = st.top();
        st.pop();
        result.push_back(node->val);
        
        // 先压右子树,再压左子树(栈是后进先出)
        if (node->right) st.push(node->right);
        if (node->left) st.push(node->left);
    }
    
    return result;
}

// 中序遍历(迭代)
vector<int> inorderIterative(TreeNode* root) {
    vector<int> result;
    stack<TreeNode*> st;
    TreeNode* curr = root;
    
    while (curr != nullptr || !st.empty()) {
        // 一直往左走,将所有左节点入栈
        while (curr != nullptr) {
            st.push(curr);
            curr = curr->left;
        }
        
        // 访问栈顶节点
        curr = st.top();
        st.pop();
        result.push_back(curr->val);
        
        // 转向右子树
        curr = curr->right;
    }
    
    return result;
}

// 后序遍历(迭代)
vector<int> postorderIterative(TreeNode* root) {
    vector<int> result;
    if (root == nullptr) return result;
    
    stack<TreeNode*> st1, st2;
    st1.push(root);
    
    // 使用两个栈,第一个栈按 根->右->左 的顺序
    // 第二个栈反转后就是 左->右->根
    while (!st1.empty()) {
        TreeNode* node = st1.top();
        st1.pop();
        st2.push(node);
        
        if (node->left) st1.push(node->left);
        if (node->right) st1.push(node->right);
    }
    
    // 从第二个栈中取出结果
    while (!st2.empty()) {
        result.push_back(st2.top()->val);
        st2.pop();
    }
    
    return result;
}

int main() {
    // 构建测试树
    //       1
    //      / \
    //     2   3
    //    / \
    //   4   5
    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);
    
    // 递归遍历
    vector<int> preorder, inorder, postorder;
    preorderRecursive(root, preorder);
    inorderRecursive(root, inorder);
    postorderRecursive(root, postorder);
    
    cout << "前序遍历(递归): ";
    for (int val : preorder) cout << val << " ";
    cout << endl;
    
    cout << "中序遍历(递归): ";
    for (int val : inorder) cout << val << " ";
    cout << endl;
    
    cout << "后序遍历(递归): ";
    for (int val : postorder) cout << val << " ";
    cout << endl;
    
    // 迭代遍历
    cout << "\n前序遍历(迭代): ";
    vector<int> preorderIter = preorderIterative(root);
    for (int val : preorderIter) cout << val << " ";
    cout << endl;
    
    cout << "中序遍历(迭代): ";
    vector<int> inorderIter = inorderIterative(root);
    for (int val : inorderIter) cout << val << " ";
    cout << endl;
    
    cout << "后序遍历(迭代): ";
    vector<int> postorderIter = postorderIterative(root);
    for (int val : postorderIter) cout << val << " ";
    cout << endl;
    
    return 0;
}

2. 判断一个二叉树是否是平衡二叉树

思路解析:

  • 平衡二叉树:每个节点的左右子树高度差不超过 1
  • 递归判断:对于每个节点,检查左右子树是否平衡,且高度差 ≤ 1
  • 优化:在计算高度的同时判断是否平衡,避免重复计算
  • 时间复杂度:O(N)
#include <iostream>
#include <algorithm>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 辅助函数:计算高度并判断是否平衡
// 返回 -1 表示不平衡,否则返回高度
int checkHeight(TreeNode* root) {
    if (root == nullptr) return 0;  // 空树高度为 0
    
    // 递归检查左子树
    int leftHeight = checkHeight(root->left);
    if (leftHeight == -1) return -1;  // 左子树不平衡
    
    // 递归检查右子树
    int rightHeight = checkHeight(root->right);
    if (rightHeight == -1) return -1;  // 右子树不平衡
    
    // 检查当前节点的左右子树高度差
    if (abs(leftHeight - rightHeight) > 1) {
        return -1;  // 高度差超过 1,不平衡
    }
    
    // 返回当前节点的高度
    return max(leftHeight, rightHeight) + 1;
}

// 判断是否为平衡二叉树
bool isBalanced(TreeNode* root) {
    return checkHeight(root) != -1;
}

int main() {
    // 测试 1:平衡二叉树
    //       1
    //      / \
    //     2   3
    //    / \
    //   4   5
    TreeNode* root1 = new TreeNode(1);
    root1->left = new TreeNode(2);
    root1->right = new TreeNode(3);
    root1->left->left = new TreeNode(4);
    root1->left->right = new TreeNode(5);
    
    cout << "测试 1: " << (isBalanced(root1) ? "是平衡二叉树" : "不是平衡二叉树") << endl;
    
    // 测试 2:不平衡二叉树
    //       1
    //      /
    //     2
    //    /
    //   3
    TreeNode* root2 = new TreeNode(1);
    root2->left = new TreeNode(2);
    root2->left->left = new TreeNode(3);
    
    cout << "测试 2: " << (isBalanced(root2) ? "是平衡二叉树" : "不是平衡二叉树") << endl;
    
    return 0;
}

3. 二叉树的最大深度

思路解析:

  • 最大深度:从根节点到最远叶子节点的最长路径上的节点数
  • 递归:最大深度 = max(左子树深度, 右子树深度) + 1
  • 时间复杂度:O(N)
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// ========== 递归实现 ==========
int maxDepthRecursive(TreeNode* root) {
    if (root == nullptr) return 0;  // 空树深度为 0
    
    // 递归计算左右子树的最大深度
    int leftDepth = maxDepthRecursive(root->left);
    int rightDepth = maxDepthRecursive(root->right);
    
    // 返回较大的深度 + 1(当前节点)
    return max(leftDepth, rightDepth) + 1;
}

// ========== 迭代实现(层次遍历)==========
int maxDepthIterative(TreeNode* root) {
    if (root == nullptr) return 0;
    
    queue<TreeNode*> q;
    q.push(root);
    int depth = 0;
    
    while (!q.empty()) {
        int levelSize = q.size();  // 当前层的节点数
        depth++;  // 深度加 1
        
        // 遍历当前层的所有节点
        for (int i = 0; i < levelSize; i++) {
            TreeNode* node = q.front();
            q.pop();
            
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        }
    }
    
    return depth;
}

int main() {
    // 构建测试树
    //       3
    //      / \
    //     9  20
    //       /  \
    //      15   7
    TreeNode* root = new TreeNode(3);
    root->left = new TreeNode(9);
    root->right = new TreeNode(20);
    root->right->left = new TreeNode(15);
    root->right->right = new TreeNode(7);
    
    cout << "最大深度(递归): " << maxDepthRecursive(root) << endl;
    cout << "最大深度(迭代): " << maxDepthIterative(root) << endl;
    
    return 0;
}

4. 二叉树的最小深度

思路解析:

  • 最小深度:从根节点到最近叶子节点的最短路径上的节点数
  • 注意:叶子节点是指没有子节点的节点
  • 递归时需要特别处理只有一个子树的情况
  • 时间复杂度:O(N)
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// ========== 递归实现 ==========
int minDepthRecursive(TreeNode* root) {
    if (root == nullptr) return 0;
    
    // 如果左子树为空,只计算右子树
    if (root->left == nullptr) {
        return minDepthRecursive(root->right) + 1;
    }
    
    // 如果右子树为空,只计算左子树
    if (root->right == nullptr) {
        return minDepthRecursive(root->left) + 1;
    }
    
    // 左右子树都存在,取较小的深度
    int leftDepth = minDepthRecursive(root->left);
    int rightDepth = minDepthRecursive(root->right);
    
    return min(leftDepth, rightDepth) + 1;
}

// ========== 迭代实现(BFS 层次遍历)==========
int minDepthIterative(TreeNode* root) {
    if (root == nullptr) return 0;
    
    queue<TreeNode*> q;
    q.push(root);
    int depth = 1;
    
    while (!q.empty()) {
        int levelSize = q.size();
        
        // 遍历当前层的所有节点
        for (int i = 0; i < levelSize; i++) {
            TreeNode* node = q.front();
            q.pop();
            
            // 如果是叶子节点,直接返回当前深度
            if (node->left == nullptr && node->right == nullptr) {
                return depth;
            }
            
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        }
        
        depth++;
    }
    
    return depth;
}

int main() {
    // 测试树
    //       3
    //      / \
    //     9  20
    //       /  \
    //      15   7
    TreeNode* root = new TreeNode(3);
    root->left = new TreeNode(9);
    root->right = new TreeNode(20);
    root->right->left = new TreeNode(15);
    root->right->right = new TreeNode(7);
    
    cout << "最小深度(递归): " << minDepthRecursive(root) << endl;
    cout << "最小深度(迭代): " << minDepthIterative(root) << endl;
    
    return 0;
}

5. 二叉树的层次遍历

思路解析:

  • 层次遍历(Level Order Traversal):按层从上到下、从左到右访问节点
  • 使用队列(BFS)实现
  • 可以返回每一层的节点值
  • 时间复杂度:O(N)
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 层次遍历,返回每一层的节点值
vector<vector<int>> levelOrder(TreeNode* root) {
    vector<vector<int>> result;
    if (root == nullptr) return result;
    
    queue<TreeNode*> q;
    q.push(root);
    
    while (!q.empty()) {
        int levelSize = q.size();  // 当前层的节点数
        vector<int> currentLevel;  // 存储当前层的节点值
        
        // 遍历当前层的所有节点
        for (int i = 0; i < levelSize; i++) {
            TreeNode* node = q.front();
            q.pop();
            currentLevel.push_back(node->val);
            
            // 将下一层的节点加入队列
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        }
        
        result.push_back(currentLevel);
    }
    
    return result;
}

// 之字形层次遍历(Zigzag Level Order)
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
    vector<vector<int>> result;
    if (root == nullptr) return result;
    
    queue<TreeNode*> q;
    q.push(root);
    bool leftToRight = true;  // 标记遍历方向
    
    while (!q.empty()) {
        int levelSize = q.size();
        vector<int> currentLevel(levelSize);
        
        for (int i = 0; i < levelSize; i++) {
            TreeNode* node = q.front();
            q.pop();
            
            // 根据方向决定插入位置
            int index = leftToRight ? i : (levelSize - 1 - i);
            currentLevel[index] = node->val;
            
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        }
        
        result.push_back(currentLevel);
        leftToRight = !leftToRight;  // 切换方向
    }
    
    return result;
}

int main() {
    // 构建测试树
    //       3
    //      / \
    //     9  20
    //       /  \
    //      15   7
    TreeNode* root = new TreeNode(3);
    root->left = new TreeNode(9);
    root->right = new TreeNode(20);
    root->right->left = new TreeNode(15);
    root->right->right = new TreeNode(7);
    
    // 普通层次遍历
    cout << "层次遍历:" << endl;
    vector<vector<int>> levels = levelOrder(root);
    for (auto& level : levels) {
        for (int val : level) {
            cout << val << " ";
        }
        cout << endl;
    }
    
    // 之字形层次遍历
    cout << "\n之字形层次遍历:" << endl;
    vector<vector<int>> zigzag = zigzagLevelOrder(root);
    for (auto& level : zigzag) {
        for (int val : level) {
            cout << val << " ";
        }
        cout << endl;
    }
    
    return 0;
}

6. 将二叉树转换为链表(Flatten Binary Tree to Linked List)

思路解析:

  • 将二叉树展开为单链表,按前序遍历的顺序
  • 要求原地修改,使用 O(1) 额外空间
  • 方法:递归处理右子树和左子树,将左子树插入到根节点和右子树之间
  • 时间复杂度:O(N)
#include <iostream>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// ========== 方法 1:递归实现 ==========
void flatten(TreeNode* root) {
    if (root == nullptr) return;
    
    // 递归展开左右子树
    flatten(root->left);
    flatten(root->right);
    
    // 保存右子树
    TreeNode* rightSubtree = root->right;
    
    // 将左子树移到右边
    root->right = root->left;
    root->left = nullptr;
    
    // 找到当前右子树的末尾
    TreeNode* curr = root;
    while (curr->right != nullptr) {
        curr = curr->right;
    }
    
    // 将原来的右子树接到末尾
    curr->right = rightSubtree;
}

// ========== 方法 2:迭代实现(Morris 遍历思想)==========
void flattenIterative(TreeNode* root) {
    TreeNode* curr = root;
    
    while (curr != nullptr) {
        if (curr->left != nullptr) {
            // 找到左子树的最右节点
            TreeNode* rightmost = curr->left;
            while (rightmost->right != nullptr) {
                rightmost = rightmost->right;
            }
            
            // 将右子树接到左子树的最右节点
            rightmost->right = curr->right;
            
            // 将左子树移到右边
            curr->right = curr->left;
            curr->left = nullptr;
        }
        
        // 移动到下一个节点
        curr = curr->right;
    }
}

// 辅助函数:打印链表
void printList(TreeNode* root) {
    while (root != nullptr) {
        cout << root->val << " -> ";
        root = root->right;
    }
    cout << "NULL" << endl;
}

int main() {
    // 构建测试树
    //       1
    //      / \
    //     2   5
    //    / \   \
    //   3   4   6
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(5);
    root->left->left = new TreeNode(3);
    root->left->right = new TreeNode(4);
    root->right->right = new TreeNode(6);
    
    flatten(root);
    
    cout << "展开后的链表: ";
    printList(root);
    
    return 0;
}

7. 判断一个二叉树是否为二叉搜索树(BST)

思路解析:

  • 二叉搜索树(BST):左子树所有节点 < 根节点 < 右子树所有节点
  • 递归判断:对于每个节点,检查其值是否在合法范围内
  • 使用上下界限制节点值的范围
  • 时间复杂度:O(N)
#include <iostream>
#include <climits>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// ========== 方法 1:递归 + 范围检查 ==========
bool isValidBSTHelper(TreeNode* root, long long minVal, long long maxVal) {
    if (root == nullptr) return true;
    
    // 检查当前节点的值是否在合法范围内
    if (root->val <= minVal || root->val >= maxVal) {
        return false;
    }
    
    // 递归检查左右子树
    // 左子树的值必须在 (minVal, root->val) 范围内
    // 右子树的值必须在 (root->val, maxVal) 范围内
    return isValidBSTHelper(root->left, minVal, root->val) &&
           isValidBSTHelper(root->right, root->val, maxVal);
}

bool isValidBST(TreeNode* root) {
    return isValidBSTHelper(root, LLONG_MIN, LLONG_MAX);
}

// ========== 方法 2:中序遍历检查 ==========
// BST 的中序遍历结果应该是严格递增的
bool isValidBSTInorder(TreeNode* root) {
    TreeNode* prev = nullptr;  // 记录前一个访问的节点
    
    // 辅助函数:中序遍历
    function<bool(TreeNode*)> inorder = [&](TreeNode* node) -> bool {
        if (node == nullptr) return true;
        
        // 遍历左子树
        if (!inorder(node->left)) return false;
        
        // 检查当前节点
        if (prev != nullptr && node->val <= prev->val) {
            return false;  // 不是严格递增
        }
        prev = node;
        
        // 遍历右子树
        return inorder(node->right);
    };
    
    return inorder(root);
}

int main() {
    // 测试 1:有效的 BST
    //       2
    //      / \
    //     1   3
    TreeNode* root1 = new TreeNode(2);
    root1->left = new TreeNode(1);
    root1->right = new TreeNode(3);
    
    cout << "测试 1: " << (isValidBST(root1) ? "是 BST" : "不是 BST") << endl;
    
    // 测试 2:无效的 BST
    //       5
    //      / \
    //     1   4
    //        / \
    //       3   6
    TreeNode* root2 = new TreeNode(5);
    root2->left = new TreeNode(1);
    root2->right = new TreeNode(4);
    root2->right->left = new TreeNode(3);
    root2->right->right = new TreeNode(6);
    
    cout << "测试 2: " << (isValidBST(root2) ? "是 BST" : "不是 BST") << endl;
    
    return 0;
}

8. 二叉搜索树的第 k 大元素

思路解析:

  • BST 的中序遍历是升序序列
  • 第 k 大元素 = 中序遍历的倒数第 k 个元素
  • 可以反向中序遍历(右 -> 根 -> 左),得到降序序列
  • 时间复杂度:O(N),最坏情况;O(H + k),平均情况
#include <iostream>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// ========== 方法 1:反向中序遍历(右 -> 根 -> 左)==========
int kthLargest(TreeNode* root, int k) {
    int count = 0;  // 计数器
    int result = -1;
    
    // 辅助函数:反向中序遍历
    function<void(TreeNode*)> reverseInorder = [&](TreeNode* node) {
        if (node == nullptr || count >= k) return;
        
        // 先遍历右子树(较大的值)
        reverseInorder(node->right);
        
        // 访问当前节点
        count++;
        if (count == k) {
            result = node->val;
            return;
        }
        
        // 再遍历左子树(较小的值)
        reverseInorder(node->left);
    };
    
    reverseInorder(root);
    return result;
}

// ========== 方法 2:正向中序遍历,找第 n-k+1 小的元素 ==========
int kthLargestAlternative(TreeNode* root, int k) {
    // 先计算节点总数
    function<int(TreeNode*)> countNodes = [&](TreeNode* node) -> int {
        if (node == nullptr) return 0;
        return 1 + countNodes(node->left) + countNodes(node->right);
    };
    
    int n = countNodes(root);
    int target = n - k + 1;  // 第 k 大 = 第 n-k+1 小
    
    int count = 0;
    int result = -1;
    
    // 正向中序遍历
    function<void(TreeNode*)> inorder = [&](TreeNode* node) {
        if (node == nullptr || count >= target) return;
        
        inorder(node->left);
        
        count++;
        if (count == target) {
            result = node->val;
            return;
        }
        
        inorder(node->right);
    };
    
    inorder(root);
    return result;
}

int main() {
    // 构建 BST
    //       5
    //      / \
    //     3   6
    //    / \
    //   2   4
    //  /
    // 1
    TreeNode* root = new TreeNode(5);
    root->left = new TreeNode(3);
    root->right = new TreeNode(6);
    root->left->left = new TreeNode(2);
    root->left->right = new TreeNode(4);
    root->left->left->left = new TreeNode(1);
    
    // 中序遍历:1, 2, 3, 4, 5, 6
    // 第 1 大:6,第 2 大:5,第 3 大:4
    
    cout << "第 1 大元素: " << kthLargest(root, 1) << endl;
    cout << "第 2 大元素: " << kthLargest(root, 2) << endl;
    cout << "第 3 大元素: " << kthLargest(root, 3) << endl;
    
    return 0;
}

9. 从前序和中序遍历构造二叉树

思路解析:

  • 前序遍历:根 -> 左 -> 右,第一个元素是根节点
  • 中序遍历:左 -> 根 -> 右,根节点将序列分为左右子树
  • 递归构造: 从前序遍历找到根节点在中序遍历中找到根节点位置,划分左右子树递归构造左右子树
  • 使用哈希表优化中序遍历中根节点的查找
  • 时间复杂度:O(N)
#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 从前序和中序遍历构造二叉树
TreeNode* buildTreeHelper(vector<int>& preorder, int preStart, int preEnd,
                          vector<int>& inorder, int inStart, int inEnd,
                          unordered_map<int, int>& inorderMap) {
    if (preStart > preEnd || inStart > inEnd) {
        return nullptr;
    }
    
    // 前序遍历的第一个元素是根节点
    int rootVal = preorder[preStart];
    TreeNode* root = new TreeNode(rootVal);
    
    // 在中序遍历中找到根节点的位置
    int rootIndex = inorderMap[rootVal];
    
    // 计算左子树的节点数量
    int leftSize = rootIndex - inStart;
    
    // 递归构造左子树
    // 前序:[preStart+1, preStart+leftSize]
    // 中序:[inStart, rootIndex-1]
    root->left = buildTreeHelper(preorder, preStart + 1, preStart + leftSize,
                                  inorder, inStart, rootIndex - 1, inorderMap);
    
    // 递归构造右子树
    // 前序:[preStart+leftSize+1, preEnd]
    // 中序:[rootIndex+1, inEnd]
    root->right = buildTreeHelper(preorder, preStart + leftSize + 1, preEnd,
                                   inorder, rootIndex + 1, inEnd, inorderMap);
    
    return root;
}

TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    // 构建中序遍历的值到索引的映射,便于快速查找
    unordered_map<int, int> inorderMap;
    for (int i = 0; i < inorder.size(); i++) {
        inorderMap[inorder[i]] = i;
    }
    
    return buildTreeHelper(preorder, 0, preorder.size() - 1,
                          inorder, 0, inorder.size() - 1, inorderMap);
}

// 辅助函数:打印中序遍历(验证结果)
void printInorder(TreeNode* root) {
    if (root == nullptr) return;
    printInorder(root->left);
    cout << root->val << " ";
    printInorder(root->right);
}

int main() {
    // 示例:
    // 前序遍历:[3, 9, 20, 15, 7]
    // 中序遍历:[9, 3, 15, 20, 7]
    // 构造的树:
    //       3
    //      / \
    //     9  20
    //       /  \
    //      15   7
    
    vector<int> preorder = {3, 9, 20, 15, 7};
    vector<int> inorder = {9, 3, 15, 20, 7};
    
    TreeNode* root = buildTree(preorder, inorder);
    
    cout << "构造的树的中序遍历: ";
    printInorder(root);
    cout << endl;
    
    return 0;
}

10. 从后序和中序遍历构造二叉树

思路解析:

  • 后序遍历:左 -> 右 -> 根,最后一个元素是根节点
  • 中序遍历:左 -> 根 -> 右,根节点将序列分为左右子树
  • 递归构造: 从后序遍历找到根节点(最后一个元素)在中序遍历中找到根节点位置,划分左右子树递归构造左右子树
  • 时间复杂度:O(N)
#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 从后序和中序遍历构造二叉树
TreeNode* buildTreeHelper(vector<int>& postorder, int postStart, int postEnd,
                          vector<int>& inorder, int inStart, int inEnd,
                          unordered_map<int, int>& inorderMap) {
    if (postStart > postEnd || inStart > inEnd) {
        return nullptr;
    }
    
    // 后序遍历的最后一个元素是根节点
    int rootVal = postorder[postEnd];
    TreeNode* root = new TreeNode(rootVal);
    
    // 在中序遍历中找到根节点的位置
    int rootIndex = inorderMap[rootVal];
    
    // 计算左子树的节点数量
    int leftSize = rootIndex - inStart;
    
    // 递归构造左子树
    // 后序:[postStart, postStart+leftSize-1]
    // 中序:[inStart, rootIndex-1]
    root->left = buildTreeHelper(postorder, postStart, postStart + leftSize - 1,
                                  inorder, inStart, rootIndex - 1, inorderMap);
    
    // 递归构造右子树
    // 后序:[postStart+leftSize, postEnd-1]
    // 中序:[rootIndex+1, inEnd]
    root->right = buildTreeHelper(postorder, postStart + leftSize, postEnd - 1,
                                   inorder, rootIndex + 1, inEnd, inorderMap);
    
    return root;
}

TreeNode* buildTreeFromPostIn(vector<int>& postorder, vector<int>& inorder) {
    // 构建中序遍历的值到索引的映射
    unordered_map<int, int> inorderMap;
    for (int i = 0; i < inorder.size(); i++) {
        inorderMap[inorder[i]] = i;
    }
    
    return buildTreeHelper(postorder, 0, postorder.size() - 1,
                          inorder, 0, inorder.size() - 1, inorderMap);
}

// 辅助函数:打印后序遍历(验证结果)
void printPostorder(TreeNode* root) {
    if (root == nullptr) return;
    printPostorder(root->left);
    printPostorder(root->right);
    cout << root->val << " ";
}

int main() {
    // 示例:
    // 后序遍历:[9, 15, 7, 20, 3]
    // 中序遍历:[9, 3, 15, 20, 7]
    // 构造的树:
    //       3
    //      / \
    //     9  20
    //       /  \
    //      15   7
    
    vector<int> postorder = {9, 15, 7, 20, 3};
    vector<int> inorder = {9, 3, 15, 20, 7};
    
    TreeNode* root = buildTreeFromPostIn(postorder, inorder);
    
    cout << "构造的树的后序遍历: ";
    printPostorder(root);
    cout << endl;
    
    return 0;
}

11. 二叉树的最大路径和

思路解析:

  • 路径:从任意节点到任意节点的序列(不一定经过根节点)
  • 路径和:路径上所有节点值的总和
  • 递归思路: 对于每个节点,计算经过该节点的最大路径和最大路径和 = 左子树最大贡献 + 右子树最大贡献 + 当前节点值返回给父节点的贡献 = max(左子树贡献, 右子树贡献) + 当前节点值
  • 需要处理负数节点(可以选择不包含某个子树)
  • 时间复杂度:O(N)
#include <iostream>
#include <algorithm>
#include <climits>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
private:
    int maxSum;  // 记录全局最大路径和
    
    // 计算以当前节点为起点的最大路径贡献
    int maxGain(TreeNode* node) {
        if (node == nullptr) return 0;
        
        // 递归计算左右子树的最大贡献
        // 如果贡献为负,则不选择该子树(取 0)
        int leftGain = max(maxGain(node->left), 0);
        int rightGain = max(maxGain(node->right), 0);
        
        // 计算经过当前节点的最大路径和
        int currentPathSum = node->val + leftGain + rightGain;
        
        // 更新全局最大路径和
        maxSum = max(maxSum, currentPathSum);
        
        // 返回当前节点能提供给父节点的最大贡献
        // 只能选择左或右其中一条路径
        return node->val + max(leftGain, rightGain);
    }
    
public:
    int maxPathSum(TreeNode* root) {
        maxSum = INT_MIN;  // 初始化为最小值
        maxGain(root);
        return maxSum;
    }
};

int main() {
    // 测试 1:
    //      1
    //     / \
    //    2   3
    // 最大路径和:2 + 1 + 3 = 6
    TreeNode* root1 = new TreeNode(1);
    root1->left = new TreeNode(2);
    root1->right = new TreeNode(3);
    
    Solution sol1;
    cout << "测试 1 最大路径和: " << sol1.maxPathSum(root1) << endl;
    
    // 测试 2:
    //      -10
    //      /  \
    //     9   20
    //        /  \
    //       15   7
    // 最大路径和:15 + 20 + 7 = 42
    TreeNode* root2 = new TreeNode(-10);
    root2->left = new TreeNode(9);
    root2->right = new TreeNode(20);
    root2->right->left = new TreeNode(15);
    root2->right->right = new TreeNode(7);
    
    Solution sol2;
    cout << "测试 2 最大路径和: " << sol2.maxPathSum(root2) << endl;
    
    // 测试 3:包含负数
    //      -3
    TreeNode* root3 = new TreeNode(-3);
    
    Solution sol3;
    cout << "测试 3 最大路径和: " << sol3.maxPathSum(root3) << endl;
    
    return 0;
}

12. 二叉树的镜像

思路解析:

  • 镜像二叉树:将二叉树的左右子树交换
  • 递归实现:交换当前节点的左右子树,然后递归处理左右子树
  • 迭代实现:使用队列或栈,逐层交换节点的左右子树
  • 时间复杂度:O(N)
#include <iostream>
#include <queue>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// ========== 方法 1:递归实现 ==========
TreeNode* mirrorTree(TreeNode* root) {
    if (root == nullptr) return nullptr;
    
    // 交换左右子树
    TreeNode* temp = root->left;
    root->left = root->right;
    root->right = temp;
    
    // 递归处理左右子树
    mirrorTree(root->left);
    mirrorTree(root->right);
    
    return root;
}

// ========== 方法 2:迭代实现(使用队列)==========
TreeNode* mirrorTreeIterative(TreeNode* root) {
    if (root == nullptr) return nullptr;
    
    queue<TreeNode*> q;
    q.push(root);
    
    while (!q.empty()) {
        TreeNode* node = q.front();
        q.pop();
        
        // 交换当前节点的左右子树
        TreeNode* temp = node->left;
        node->left = node->right;
        node->right = temp;
        
        // 将左右子节点加入队列
        if (node->left) q.push(node->left);
        if (node->right) q.push(node->right);
    }
    
    return root;
}

// ========== 判断两棵树是否互为镜像 ==========
bool isSymmetric(TreeNode* left, TreeNode* right) {
    // 两个节点都为空,是镜像
    if (left == nullptr && right == nullptr) return true;
    
    // 只有一个为空,不是镜像
    if (left == nullptr || right == nullptr) return false;
    
    // 值不相等,不是镜像
    if (left->val != right->val) return false;
    
    // 递归检查:左的左子树和右的右子树,左的右子树和右的左子树
    return isSymmetric(left->left, right->right) && 
           isSymmetric(left->right, right->left);
}

// 判断一棵树是否对称(镜像对称)
bool isSymmetricTree(TreeNode* root) {
    if (root == nullptr) return true;
    return isSymmetric(root->left, root->right);
}

// 辅助函数:层次遍历打印树
void printLevelOrder(TreeNode* root) {
    if (root == nullptr) return;
    
    queue<TreeNode*> q;
    q.push(root);
    
    while (!q.empty()) {
        int levelSize = q.size();
        for (int i = 0; i < levelSize; i++) {
            TreeNode* node = q.front();
            q.pop();
            
            if (node) {
                cout << node->val << " ";
                q.push(node->left);
                q.push(node->right);
            } else {
                cout << "null ";
            }
        }
        cout << endl;
    }
}

int main() {
    // 构建测试树
    //       4
    //      / \
    //     2   7
    //    / \ / \
    //   1  3 6  9
    TreeNode* root = new TreeNode(4);
    root->left = new TreeNode(2);
    root->right = new TreeNode(7);
    root->left->left = new TreeNode(1);
    root->left->right = new TreeNode(3);
    root->right->left = new TreeNode(6);
    root->right->right = new TreeNode(9);
    
    cout << "原始树的层次遍历:" << endl;
    printLevelOrder(root);
    
    // 镜像翻转
    mirrorTree(root);
    
    cout << "\n镜像后的层次遍历:" << endl;
    printLevelOrder(root);
    // 镜像后:
    //       4
    //      / \
    //     7   2
    //    / \ / \
    //   9  6 3  1
    
    // 测试对称树
    cout << "\n测试对称树:" << endl;
    TreeNode* symRoot = new TreeNode(1);
    symRoot->left = new TreeNode(2);
    symRoot->right = new TreeNode(2);
    symRoot->left->left = new TreeNode(3);
    symRoot->left->right = new TreeNode(4);
    symRoot->right->left = new TreeNode(4);
    symRoot->right->right = new TreeNode(3);
    
    cout << "是否对称: " << (isSymmetricTree(symRoot) ? "是" : "否") << endl;
    
    return 0;
}

C++八股文全集 文章被收录于专栏

本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务