C++八股文(数据结构与算法)

1. 如何实现一个链表?

单链表核心实现

struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

class LinkedList {
    ListNode* head;
public:
    LinkedList() : head(nullptr) {}
    
    void insert(int val) {  // 头插
        ListNode* node = new ListNode(val);
        node->next = head;
        head = node;
    }
    
    void remove(int val) {  // 删除节点
        ListNode dummy(0);
        dummy.next = head;
        ListNode* prev = &dummy;
        while (prev->next) {
            if (prev->next->val == val) {
                ListNode* temp = prev->next;
                prev->next = prev->next->next;
                delete temp;
                break;
            }
            prev = prev->next;
        }
        head = dummy.next;
    }
};

  • 关键点:节点结构(数据+指针)、头指针管理、插入删除操作
  • 双向链表:节点增加prev指针,可双向遍历
  • 循环链表:尾节点指向头节点
  • 常见操作:反转链表、查找中间节点、合并有序链表、检测环
  • 优点:动态大小、插入删除O(1)
  • 缺点:随机访问O(n)、额外指针空间

2. 如何实现栈和队列?

栈(数组实现)

class Stack {
    vector<int> data;
public:
    void push(int x) { data.push_back(x); }
    void pop() { if (!empty()) data.pop_back(); }
    int top() { return data.back(); }
    bool empty() { return data.empty(); }
};

队列(链表实现)

class Queue {
    list<int> data;
public:
    void push(int x) { data.push_back(x); }
    void pop() { if (!empty()) data.pop_front(); }
    int front() { return data.front(); }
    bool empty() { return data.empty(); }
};

  • 栈特点:LIFO(后进先出),用于函数调用、表达式求值、DFS
  • 队列特点:FIFO(先进先出),用于BFS、任务调度
  • 循环队列:数组实现,避免空间浪费,需要front、rear指针
  • 双端队列:两端都可插入删除,STL的deque
  • STL容器:stack、queue、priority_queue(堆)

3. 如何实现二叉树的前序、中序、后序遍历?

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

// 前序:根-左-右
void preorder(TreeNode* root) {
    if (!root) return;
    cout << root->val << " ";
    preorder(root->left);
    preorder(root->right);
}

// 中序:左-根-右(二叉搜索树得到有序序列)
void inorder(TreeNode* root) {
    if (!root) return;
    inorder(root->left);
    cout << root->val << " ";
    inorder(root->right);
}

// 后序:左-右-根
void postorder(TreeNode* root) {
    if (!root) return;
    postorder(root->left);
    postorder(root->right);
    cout << root->val << " ";
}

// 层序遍历(BFS)
void levelorder(TreeNode* root) {
    if (!root) return;
    queue<TreeNode*> q;
    q.push(root);
    while (!q.empty()) {
        TreeNode* node = q.front();
        q.pop();
        cout << node->val << " ";
        if (node->left) q.push(node->left);
        if (node->right) q.push(node->right);
    }
}

  • 递归实现:简洁但可能栈溢出
  • 迭代实现:用栈模拟递归,前序和中序较简单,后序稍复杂
  • Morris遍历:O(1)空间,利用线索二叉树
  • 应用:前序用于复制树、中序用于BST排序、后序用于删除树

4. 如何实现哈希表?

class HashTable {
    static const int SIZE = 1000;
    vector<list<pair<int, int>>> table;  // 链地址法
public:
    HashTable() : table(SIZE) {}
    
    int hash(int key) { return key % SIZE; }
    
    void insert(int key, int value) {
        int idx = hash(key);
        for (auto& p : table[idx]) {
            if (p.first == key) {
                p.second = value;  // 更新
                return;
            }
        }
        table[idx].push_back({key, value});
    }
    
    int get(int key) {
        int idx = hash(key);
        for (auto& p : table[idx]) {
            if (p.first == key) return p.second;
        }
        return -1;  // 不存在
    }
    
    void remove(int key) {
        int idx = hash(key);
        table[idx].remove_if([key](auto& p) { return p.first == key; });
    }
};

  • 哈希函数:将key映射到索引,要求分布均匀、计算快速
  • 冲突解决:①链地址法(拉链法)②开放地址法(线性探测、二次探测、双重哈希)
  • 负载因子:元素数/桶数,过高需要rehash扩容
  • 时间复杂度:平均O(1),最坏O(n)
  • STL实现:unordered_map、unordered_set

5. 如何使用 std::map 和 std::unordered_map?


 

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

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

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

全部评论
点赞 回复 分享
发布于 02-03 09:11 上海

相关推荐

评论
1
1
分享

创作者周榜

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