位置: 文档库 > C/C++ > C++中的算法与数据结构面试常见问题

C++中的算法与数据结构面试常见问题

南柯一梦 上传于 2021-08-16 11:54

《C++中的算法与数据结构面试常见问题》

在C++技术面试中,算法与数据结构是核心考察内容。无论是校招还是社招,面试官常通过这类问题评估候选人的编程思维、问题解决能力以及对底层原理的理解。本文系统梳理了C++面试中高频出现的算法与数据结构问题,涵盖基础概念、经典题目、底层实现及优化技巧,帮助读者构建完整的知识体系。

一、基础数据结构核心问题

1. 数组与字符串

数组是连续内存存储的线性结构,而字符串可视为字符数组。面试中常考察数组操作、字符串处理及边界条件处理。

问题示例:如何反转一个字符串?

#include 
#include 
void reverseString(std::string& s) {
    std::reverse(s.begin(), s.end()); // STL方法
    // 或手动实现双指针
    int left = 0, right = s.size() - 1;
    while (left 

关键点:时间复杂度O(n),空间复杂度O(1)。需注意字符串为空或长度为1时的边界情况。

2. 链表操作

链表通过指针连接节点,面试中常考察反转、环检测、合并等操作。

问题示例:反转单链表(递归与非递归)。

// 非递归实现
struct ListNode {
    int val;
    ListNode *next;
};
ListNode* reverseList(ListNode* head) {
    ListNode *prev = nullptr, *curr = head;
    while (curr) {
        ListNode *next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
}
// 递归实现
ListNode* reverseListRecursive(ListNode* head) {
    if (!head || !head->next) return head;
    ListNode *newHead = reverseListRecursive(head->next);
    head->next->next = head;
    head->next = nullptr;
    return newHead;
}

关键点:理解指针操作顺序,避免断链。递归需明确终止条件与递归关系。

3. 栈与队列

栈(LIFO)与队列(FIFO)是基础容器,常考察其实现及应用场景。

问题示例:用两个栈实现队列。

#include 
class QueueWithStacks {
private:
    std::stack in, out;
public:
    void push(int x) { in.push(x); }
    int pop() {
        if (out.empty()) {
            while (!in.empty()) {
                out.push(in.top());
                in.pop();
            }
        }
        int val = out.top();
        out.pop();
        return val;
    }
    bool empty() { return in.empty() && out.empty(); }
};

关键点:入队操作O(1),出队操作均摊O(1)。需理解栈的顺序反转特性。

二、树与图算法

1. 二叉树遍历

二叉树遍历分为深度优先(前序、中序、后序)与广度优先(层次遍历)。

问题示例:二叉树的中序遍历(递归与非递归)。

// 递归实现
void inorderTraversal(TreeNode* root, std::vector& res) {
    if (!root) return;
    inorderTraversal(root->left, res);
    res.push_back(root->val);
    inorderTraversal(root->right, res);
}
// 非递归实现(使用栈)
std::vector inorderTraversalIterative(TreeNode* root) {
    std::vector res;
    std::stack s;
    TreeNode *curr = root;
    while (curr || !s.empty()) {
        while (curr) {
            s.push(curr);
            curr = curr->left;
        }
        curr = s.top(); s.pop();
        res.push_back(curr->val);
        curr = curr->right;
    }
    return res;
}

关键点:非递归实现需模拟递归调用栈,明确节点访问顺序。

2. 二叉搜索树(BST)

BST满足左子小于根、右子树大于根的特性,常考察插入、删除、验证等操作。

问题示例:验证二叉搜索树。

bool isValidBST(TreeNode* root, long long min = LLONG_MIN, long long max = LLONG_MAX) {
    if (!root) return true;
    if (root->val val >= max) return false;
    return isValidBST(root->left, min, root->val) && 
           isValidBST(root->right, root->val, max);
}

关键点:利用上下界约束递归验证,避免仅比较左右子节点。

3. 图算法

图算法包括深度优先搜索(DFS)、广度优先搜索(BFS)及拓扑排序等。

问题示例:课程表问题(拓扑排序)。

#include 
#include 
bool canFinish(int numCourses, std::vector<:vector>>& prerequisites) {
    std::vector<:vector>> graph(numCourses);
    std::vector inDegree(numCourses, 0);
    for (auto& edge : prerequisites) {
        graph[edge[1]].push_back(edge[0]);
        inDegree[edge[0]]++;
    }
    std::queue q;
    for (int i = 0; i 

关键点:构建有向图并计算入度,通过BFS实现拓扑排序。

三、排序与搜索算法

1. 快速排序与归并排序

快速排序通过分治思想实现,归并排序则依赖递归与合并。

问题示例:快速排序实现。

#include 
#include 
void quickSort(std::vector& nums, int left, int right) {
    if (left >= right) return;
    int pivot = nums[(left + right) / 2];
    int i = left, j = right;
    while (i  pivot) j--;
        if (i 

关键点:选择合适基准值(pivot),避免最坏时间复杂度O(n²)。

2. 二分查找

二分查找要求数组有序,常考察边界条件与变种问题。

问题示例:寻找旋转排序数组中的最小值。

int findMin(std::vector& nums) {
    int left = 0, right = nums.size() - 1;
    while (left  nums[right]) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    return nums[left];
}

关键点:通过比较中间值与右边界确定搜索方向,终止条件为left == right。

四、动态规划与贪心算法

1. 动态规划基础

动态规划通过状态转移方程解决重叠子问题,常考察背包问题、最长子序列等。

问题示例:0-1背包问题。

int knapsack(int W, std::vector& weights, std::vector& values) {
    int n = weights.size();
    std::vector<:vector>> dp(n + 1, std::vector(W + 1, 0));
    for (int i = 1; i 

关键点:定义状态dp[i][w]表示前i个物品在容量w下的最大价值,优化空间复杂度至O(W)。

2. 贪心算法应用

贪心算法通过局部最优解推导全局最优,常考察区间调度、硬币找零等问题。

问题示例:区间调度最大化非重叠区间数。

#include 
#include 
int eraseOverlapIntervals(std::vector<:vector>>& intervals) {
    if (intervals.empty()) return 0;
    std::sort(intervals.begin(), intervals.end(), 
              [](auto& a, auto& b) { return a[1] = end) {
            end = intervals[i][1];
            count++;
        }
    }
    return intervals.size() - count;
}

关键点:按结束时间排序,每次选择结束最早的区间以保留更多空间。

五、STL与底层实现

1. STL容器特性

面试中常考察vector、map、unordered_map等容器的底层实现与时间复杂度。

问题示例:vector扩容机制。

vector在容量不足时按2倍(或1.5倍)扩容,涉及内存重新分配与元素拷贝。例如:

std::vector v;
v.reserve(10); // 预留空间但不改变size
v.push_back(1); // 若容量不足则触发扩容

关键点:理解capacity与size的区别,扩容导致迭代器失效。

2. 智能指针

智能指针(unique_ptr、shared_ptr)用于管理动态内存,常考察引用计数与循环引用问题。

问题示例:shared_ptr循环引用导致内存泄漏。

#include 
struct Node {
    std::shared_ptr next;
    ~Node() { std::cout ();
    auto b = std::make_shared();
    a->next = b; // 循环引用
    b->next = a;
    // 此时引用计数为2,无法释放
    return 0;
}

解决方案:使用weak_ptr打破循环引用。

六、系统设计与优化

1. 大数据量处理

面试中常考察海量数据下的算法优化,如分治、布隆过滤器、哈希分片等。

问题示例:设计一个支持增删改查的亿级数据系统。

解决方案:

  • 分库分表:按哈希或范围分割数据
  • 缓存层:使用Redis缓存热点数据
  • 异步处理:消息队列解耦读写操作

2. 算法空间优化

通过位运算、原地修改等方式减少空间占用。

问题示例:原地删除排序数组中的重复项。

int removeDuplicates(std::vector& nums) {
    if (nums.empty()) return 0;
    int slow = 0;
    for (int fast = 1; fast 

关键点:双指针法,时间复杂度O(n),空间复杂度O(1)。

关键词、简介

关键词:C++面试、算法、数据结构、链表反转、二叉树遍历、动态规划、二分查找、STL容器、智能指针、系统设计

简介:本文系统梳理C++面试中算法与数据结构的高频问题,涵盖数组、链表、树、图等基础数据结构,排序、搜索、动态规划等核心算法,以及STL使用与系统设计优化技巧。通过代码示例与关键点解析,帮助读者掌握面试常见问题的解题思路与实现细节。