南京大学 CPP 2025Fall 第五次机试 题解和思路分享

题目1:集合操作(MySet)

题目描述

实现一个简化的整数集合类MySet,该类持有一个unordered_set来存储元素,为了更方便地进行集合运算,要求通过操作符重载提供直观的集合运算接口。

具体要求

1. 操作符重载

(1)交集
  • 交(*):A * B 返回集合A与集合B的交集
  • 交赋值(*=):A *= BA = A * B
(2)并集与差集
  • 并(+):A + B 返回集合A与集合B的并集
  • 并赋值(+=):A += BA = A + B
  • 差(-):A - B 返回集合A与集合B的差集
  • 差赋值(-=):A -= BA = A - B
  • 操作数类型支持MySetint(表示单个整数构成的集合),示例:
    • A + 11 + A → 集合A与{1}的并集
    • A - 1 → 集合A与{1}的差集
    • 1 - A → 集合{1}与A的差集(结果为{1}{}

2. 类型转换

  • bool():空集合返回false,非空集合返回true
  • int():返回集合的元素个数
  • std::vector<int>():转换为向量,元素按升序排列

3. 输出流重载

  • 友元函数:friend std::ostream& operator<<(std::ostream& os, const MySet& s)
  • 输出格式:{a0, a1, a2, ...}(元素按升序排列)

调用示例

#include "MySet.h"
int main() {
    MySet A = {1, 2, 3, 4};
    MySet B = {4, 5, 6, 7, 8};
    std::cout << (A + 5) * B << std::endl;
    B -= 8;
    std::cout << A + (8 - B) << std::endl;
    if (A * B) {
        std::cout << "A size: " << static_cast<int>(A) << std::endl;
        std::vector<int> a = static_cast<std::vector<int>>(A);
        for (int i : a) {
            std::cout << i << " ";
        }
        std::cout << std::endl;
    }
}

输出结果

{4, 5}
{1, 2, 3, 4, 8}
A size: 4
1 2 3 4

提示

  • 部分操作符可复用已实现的操作符简化代码
  • 并集操作参考声明(其他操作可仿照):
MySet operator+(const MySet& other) const;
MySet operator+(int value) const;
friend MySet operator+(int value, const MySet& set);
MySet& operator+=(const MySet& other);
MySet& operator+=(int value);
  • 需创建MySet.h文件实现操作符重载,Main.cpp输入随意内容即可

代码模板(MySet.h)

#include <algorithm>
#include <iostream>
#include <unordered_set>
#include <vector>

class MySet {
private:
    std::unordered_set<int> data;
public:
    MySet() = default;
    MySet(std::initializer_list<int> init) : data(init) {}

    // ========== 基础方法 ==========
    size_t size() const {
        return data.size();
    }

    bool empty() const {
        return data.empty();
    }

    bool contains(int value) const {
        return data.find(value) != data.end();
    }

    void add(int value) {
        data.insert(value);
    }

    void remove(int value) {
        data.erase(value);
    }

    void clear() {
        data.clear();
    }

    // ========== 操作符重载(待实现) ==========
    // 交集
    MySet operator*(const MySet& other) const;
    MySet& operator*=(const MySet& other);

    // 并集
    MySet operator+(const MySet& other) const;
    MySet operator+(int value) const;
    friend MySet operator+(int value, const MySet& set);
    MySet& operator+=(const MySet& other);
    MySet& operator+=(int value);

    // 差集
    MySet operator-(const MySet& other) const;
    MySet operator-(int value) const;
    friend MySet operator-(int value, const MySet& set);
    MySet& operator-=(const MySet& other);
    MySet& operator-=(int value);

    // 类型转换
    operator bool() const {
        return !empty();
    }

    operator int() const {
        return static_cast<int>(size());
    }

    operator std::vector<int>() const {
        std::vector<int> vec(data.begin(), data.end());
        std::sort(vec.begin(), vec.end());
        return vec;
    }

    // 输出流重载(友元)
    friend std::ostream& operator<<(std::ostream& os, const MySet& s);
};

// ========== 操作符实现(待补充) ==========
MySet MySet::operator*(const MySet& other) const {
    MySet res;
    for (int val : data) {
        if (other.contains(val)) {
            res.add(val);
        }
    }
    return res;
}

MySet& MySet::operator*=(const MySet& other) {
    *this = *this * other;
    return *this;
}

MySet MySet::operator+(const MySet& other) const {
    MySet res;
    for (int val : data) res.add(val);
    for (int val : other.data) res.add(val);
    return res;
}

MySet MySet::operator+(int value) const {
    MySet res = *this;
    res.add(value);
    return res;
}

MySet operator+(int value, const MySet& set) {
    return set + value;
}

MySet& MySet::operator+=(const MySet& other) {
    *this = *this + other;
    return *this;
}

MySet& MySet::operator+=(int value) {
    *this = *this + value;
    return *this;
}

MySet MySet::operator-(const MySet& other) const {
    MySet res;
    for (int val : data) {
        if (!other.contains(val)) {
            res.add(val);
        }
    }
    return res;
}

MySet MySet::operator-(int value) const {
    MySet res = *this;
    res.remove(value);
    return res;
}

MySet operator-(int value, const MySet& set) {
    MySet res;
    if (!set.contains(value)) {
        res.add(value);
    }
    return res;
}

MySet& MySet::operator-=(const MySet& other) {
    *this = *this - other;
    return *this;
}

MySet& MySet::operator-=(int value) {
    *this = *this - value;
    return *this;
}

std::ostream& operator<<(std::ostream& os, const MySet& s) {
    std::vector<int> vec = static_cast<std::vector<int>>(s);
    os << "{";
    for (size_t i = 0; i < vec.size(); ++i) {
        if (i > 0) os << ", ";
        os << vec[i];
    }
    os << "}";
    return os;
}

题目2:通用环形缓冲区(RingBuffer)

题目描述

实现一个名为RingBuffer的C++类模板,代表固定大小的环形缓冲区(Circular Buffer)。环形缓冲区是高效的数据结构,用于在固定大小的存储空间中管理数据流。与普通队列不同,当缓冲区满时,新数据将自动覆盖最早的数据(First-In, Overwrite-Oldest)。

支持任意类型T的元素存储,需正确管理内部内存。

核心概念:环形覆盖

假设缓冲区容量为3:

  1. push(1) → buffer: [1, _, _]
  2. push(2) → buffer: [1, 2, _]
  3. push(3) → buffer: [1, 2, 3](满)
  4. push(4) → buffer: [4, 2, 3](1被4覆盖,最早元素变为2)

功能要求

实现以下成员函数:

  1. RingBuffer(size_t capacity):构造函数,分配存储capacityT类型元素的空间
  2. ~RingBuffer():析构函数,释放所有动态分配的内存
  3. void push(const T& value):添加元素
    • 缓冲区未满:添加到队尾
    • 缓冲区已满:覆盖队头元素,更新队头和队尾位置
  1. void pop():移除队头元素(空缓冲区不执行操作)
  2. T& front():返回队头元素(最早加入)的引用
  3. T& back():返回队尾元素(最近加入)的引用
  4. size_t getSize() const:返回当前元素数量
  5. size_t getCapacity() const:返回总容量
  6. bool isFull() const:检查是否已满
  7. bool isEmpty() const:检查是否为空
  8. void print() const:按从旧到新顺序打印所有元素(空格分隔,末尾换行)

输入格式

每行一条操作指令,格式如下:

  • create <capacity>:创建容量为capacityRingBuffer<int>对象
  • push <value>:添加一个整数
  • pop:移除最早元素
  • front:打印队头元素
  • back:打印队尾元素
  • print:按顺序打印所有元素(队头到队尾)
  • info:打印当前大小(Size)和容量(Capacity)

数据范围

  • 缓冲区容量capacity0 <= capacity
  • 元素valueint范围内

输出格式

  • front/back指令:输出对应数值;空缓冲区输出Empty
  • print指令:一行输出所有元素(空格分隔);空缓冲区输出Empty
  • info指令:输出Size: <size>, Capacity: <capacity>

样例输入

create 3
push 10
push 20
info
push 30
info
print
push 40
info
print
front
back
pop
print

样例输出

Size: 2, Capacity: 3
Size: 3, Capacity: 3
10 20 30
Size: 3, Capacity: 3
20 30 40
20
40
30 40

样例解释

  1. create 3:创建容量为3的缓冲区
  2. push 10push 20:缓冲区为[10, 20],大小2
  3. push 30:缓冲区为[10, 20, 30],已满
  4. push 40:覆盖最早的10,逻辑缓冲区变为[20, 30, 40]
  5. pop:移除最早的20,缓冲区变为[30, 40]

代码模板

#include <iostream>
#include <vector>
#include <string>

template <typename T>
class RingBuffer {
private:
    std::vector<T> data;    // 底层存储
    size_t head;            // 队头索引(最早元素)
    size_t tail;            // 队尾索引(下一个插入位置)
    size_t capacity;        // 总容量
    size_t currentSize;     // 当前元素数量

public:
    // 构造函数
    RingBuffer(size_t cap) : capacity(cap), head(0), tail(0), currentSize(0) {
        if (cap > 0) {
            data.resize(cap);
        }
    }

    // 析构函数
    ~RingBuffer() {
        // vector自动管理内存,无需额外释放
    }

    // 添加元素(如果满则覆盖)
    void push(const T& value) {
        if (capacity == 0) {
            return;
        }
        if (isFull()) {
            // 覆盖队头,更新head
            data[tail] = value;
            head = (head + 1) % capacity;
        } else {
            // 插入队尾,增加大小
            data[tail] = value;
            currentSize++;
        }
        // 更新tail(循环索引)
        tail = (tail + 1) % capacity;
    }

    // 移除队头元素
    void pop() {
        if (isEmpty()) {
            return;
        }
        head = (head + 1) % capacity;
        currentSize--;
    }

    // 获取队头引用
    T& front() {
        static T dummy;
        return isEmpty() ? dummy : data[head];
    }

    // 获取队尾引用
    T& back() {
        static T dummy;
        if (isEmpty()) {
            return dummy;
        }
        // tail指向 next 插入位置,实际队尾是 tail-1(处理环绕)
        size_t backIdx = (tail == 0) ? capacity - 1 : tail - 1;
        return data[backIdx];
    }

    // 获取当前大小
    size_t getSize() const {
        return currentSize;
    }

    // 获取容量
    size_t getCapacity() const {
        return capacity;
    }

    // 检查是否已满
    bool isFull() const {
        return currentSize == capacity;
    }

    // 检查是否为空
    bool isEmpty() const {
        return currentSize == 0;
    }

    // 按从旧到新顺序打印元素
    void print() const {
        if (isEmpty()) {
            std::cout << "Empty" << std::endl;
            return;
        }
        size_t idx = head;
        for (size_t i = 0; i < currentSize; ++i) {
            if (i > 0) {
                std::cout << " ";
            }
            std::cout << data[idx];
            idx = (idx + 1) % capacity;
        }
        std::cout << std::endl;
    }
};

int main() {
    std::string command;
    int capacity;
    RingBuffer<int>* buffer = nullptr;

    while (std::cin >> command) {
        if (command == "create") {
            std::cin >> capacity;
            if (buffer) {
                delete buffer;
            }
            buffer = new RingBuffer<int>(capacity);
        } else if (command == "push") {
            int value;
            std::cin >> value;
            if (buffer) {
                buffer->push(value);
            }
        } else if (command == "pop") {
            if (buffer) {
                buffer->pop();
            }
        } else if (command == "front") {
            if (buffer) {
                if (buffer->isEmpty()) {
                    std::cout << "Empty" << std::endl;
                } else {
                    std::cout << buffer->front() << std::endl;
                }
            }
        } else if (command == "back") {
            if (buffer) {
                if (buffer->isEmpty()) {
                    std::cout << "Empty" << std::endl;
                } else {
                    std::cout << buffer->back() << std::endl;
                }
            }
        } else if (command == "print") {
            if (buffer) {
                buffer->print();
            }
        } else if (command == "info") {
            if (buffer) {
                std::cout << "Size: " << buffer->getSize()
                          << ", Capacity: " << buffer->getCapacity() << std::endl;
            }
        }
    }

    if (buffer) {
        delete buffer;
    }
    return 0;
}

解题思路与参考实现

题目1:RingBuffer

思路梳理

  • 底层存储使用定长数组 T* data(容量为 capacity)。
  • 维护三个指标:head 指向队头(最旧元素),tail 指向下一次写入位置,count 为当前元素个数。
  • push:写入 data[tail],若已满则先移动 head 覆盖最旧元素,否则递增 count,最后 tail = (tail + 1) % capacity
  • pop:空则无操作;否则 head = (head + 1) % capacitycount--
  • front/backfrontdata[head]back(tail + capacity - 1) % capacity
  • 判空判满:count == 0 / count == capacity;容量为 0 时所有操作直接返回以防越界。

参考代码

#include <iostream>
#include <vector>
#include <string>
#include <bits/stdc++.h>

// TODO: 将 RingBuffer 定义为模板类 template <typename T>
template <typename T>
class RingBuffer {
private:
    // TODO: 添加私有成员变量
    T* data;
    size_t capacity;
    size_t head;
    size_t tail;
    size_t count;
    // 建议使用 T* data 或 std::vector<T> 作为底层存储
    // 需要记录 head (队头), tail (队尾) 或 count (当前数量)

public:
    // 构造函数
    RingBuffer(size_t cap) : capacity(cap),head(0),tail(0),count(0){
        // TODO
        if (capacity>0) {
            data = new T[capacity];
        }else {
            data = nullptr;
        }
    }

    // 析构函数
    ~RingBuffer() {
        // TODO
        delete[] data;
        data = nullptr;
    }

    // 添加元素 (如果满则覆盖)
    void push(const T& value) {
        // TODO
        if (capacity == 0) {
            return;
        }

        data[tail] = value;

        if (isFull()) {
            head = (head + 1) % capacity;
        } else {
            count++;
        }

        tail = (tail + 1) % capacity;
    }

    // 移除元素
    void pop() {
        // TODO
        if (isEmpty()) {
            return;
        }

        head = (head + 1) % capacity;
        count--;
    }

    // 获取队头引用
    T& front() {
        // TODO
        // 注意:实际项目中应处理空的情况,这里为了简单可假设调用前非空或返回默认值
        return data[head];
    }

    // 获取队尾引用
    T& back() {
        // TODO
        size_t tailReturn = (tail - 1 + capacity) % capacity;
        return data[tailReturn];
    }

    size_t getSize() const {
        // TODO
        return count;
    }

    size_t getCapacity() const {
        // TODO
        return capacity;
    }

    bool isFull() const {
        // TODO
        if (count == capacity) {
            return true;
        }else {
            return false;
        }
    }

    bool isEmpty() const {
        // TODO
        if (count == 0) {
            return true;
        }else {
            return false;
        }
    }

    // 打印当前缓冲区的所有元素(从旧到新)
    void print() const {
        // TODO
        if (isEmpty()) {
            std::cout << "Empty" << std::endl;
            return;
        }

        for (size_t i = 0; i < count; ++i) {
            size_t idx = (head + i) % capacity;
            if (i > 0) {
                std::cout << " ";
            }
            std::cout << data[idx];
        }
        std::cout << std::endl;
    }
};

int main() {
    std::string command;
    int capacity;
    RingBuffer<int>* buffer = nullptr;

    while (std::cin >> command) {
        if (command == "create") {
            std::cin >> capacity;
            if (buffer) delete buffer;
            buffer = new RingBuffer<int>(capacity);
        } else if (command == "push") {
            int value;
            std::cin >> value;
            if (buffer) buffer->push(value);
        } else if (command == "pop") {
            if (buffer) buffer->pop();
        } else if (command == "front") {
            if (buffer) {
                if (buffer->isEmpty()) std::cout << "Empty" << std::endl;
                else std::cout << buffer->front() << std::endl;
            }
        } else if (command == "back") {
            if (buffer) {
                if (buffer->isEmpty()) std::cout << "Empty" << std::endl;
                else std::cout << buffer->back() << std::endl;
            }
        } else if (command == "print") {
            if (buffer) {
                if (buffer->isEmpty()) {
                    std::cout << "Empty" << std::endl;
                } else {
                    buffer->print();
                }
            }
        } else if (command == "info") {
            if (buffer) {
                std::cout << "Size: " << buffer->getSize()
                          << ", Capacity: " << buffer->getCapacity() << std::endl;
            }
        }
    }

    if (buffer) delete buffer;
    return 0;
}

代码解析

  • 覆盖策略:push 时若满先前移 head,保证最旧元素被替换;tail 永远指向下一写位置。
  • 取尾元素:(tail + capacity - 1) % capacity 处理循环减一。
  • 安全性:容量为 0 时直接返回,避免除零或越界;析构释放底层数组。

题目2:MySet

思路梳理

  • 内部使用 unordered_set<int> 存储;通过基础操作 add/contains/remove 复用逻辑。
  • 交并差:二元运算返回新集合,赋值运算在当前集合原地更新(可用临时容器后 swap)。
  • int 的混合运算:将单个整数视为 {value},提供对称友元实现前置写法(如 1 + A)。
  • 类型转换与输出:转换向量后排序,输出 {a0, a1, ...} 升序保证稳定展示。

参考代码

#include <algorithm>
#include <iostream>
#include <unordered_set>
#include <vector>

using namespace std;

class MySet {
 private:
  unordered_set<int> data;

 public:
  MySet() = default;

  MySet(const initializer_list<int> init) : data(init) {}

  // ========== 基础方法 ==========
  size_t size() const {
    return data.size();
  }

  bool empty() const {
    return data.empty();
  }

  bool contains(const int value) const {
    return data.find(value) != data.end();
  }

  void add(const int value) {
    data.insert(value);
  }

  void remove(const int value) {
    data.erase(value);
  }

  void clear() {
    data.clear();
  }

  //交集
  MySet operator*(const MySet& other) const;
  MySet& operator*=(const MySet& other);

  //并集
  MySet operator+(const MySet& other) const;
  MySet operator+(int value) const;
  friend MySet operator+(int value, const MySet& set);
  MySet& operator+=(const MySet& other);
  MySet& operator+=(int value);

  //差集
  MySet operator-(const MySet& other) const;
  MySet operator-(int value) const;
  friend MySet operator-(int value, const MySet& set);
  MySet& operator-=(const MySet& other);
  MySet& operator-=(int value);

  //类型转换
  explicit operator bool() const;
  explicit operator int() const;
  explicit operator std::vector<int>() const;

  //输出流重载
  friend ostream& operator<<(ostream& os, const MySet& s);
};

//交集实现
inline MySet MySet::operator*(const MySet& other) const {
  MySet result;
  for (const int elem : data) {
    if (other.contains(elem)) {
      result.add(elem);
    }
  }
  return result;
}

inline MySet& MySet::operator*=(const MySet& other) {
  unordered_set<int> new_data;
  for (int elem : data) {
    if (other.contains(elem)) {
      new_data.insert(elem);
    }
  }
  data.swap(new_data);
  return *this;
}

//并集实现
inline MySet MySet::operator+(const MySet& other) const {
  MySet result = *this;
  for (const int elem : other.data) {
    result.add(elem);
  }
  return result;
}

inline MySet MySet::operator+(const int value) const {
  MySet result = *this;
  result.add(value);
  return result;
}

inline MySet operator+(const int value, const MySet& set) {
  return set + value;
}

inline MySet& MySet::operator+=(const MySet& other) {
  for (const int elem : other.data) {
    this->add(elem);
  }
  return *this;
}

inline MySet& MySet::operator+=(const int value) {
  this->add(value);
  return *this;
}

//差集实现
inline MySet MySet::operator-(const MySet& other) const {
  MySet result;
  for (const int elem : data) {
    if (!other.contains(elem)) {
      result.add(elem);
    }
  }
  return result;
}

inline MySet MySet::operator-(const int value) const {
  MySet result = *this;
  result.remove(value);
  return result;
}

inline MySet operator-(const int value, const MySet& set) {
  MySet result;
  if (!set.contains(value)) {
    result.add(value);
  }
  return result;
}

inline MySet& MySet::operator-=(const MySet& other) {
  unordered_set<int> new_data;
  for (int elem : data) {
    if (!other.contains(elem)) {
      new_data.insert(elem);
    }
  }
  data.swap(new_data);
  return *this;
}

inline MySet& MySet::operator-=(const int value) {
  this->remove(value);
  return *this;
}

//类型转换
inline MySet::operator bool() const {
  return !this->empty();
}

inline MySet::operator int() const {
  return static_cast<int>(this->size());
}

inline MySet::operator vector<int>() const {
  vector vec(this->data.begin(), this->data.end());
  sort(vec.begin(), vec.end());
  return vec;
}

//输出流
inline ostream& operator<<(ostream& os, const MySet& s) {
  const auto vec = static_cast<vector<int>>(s);
  os << "{";
  for (size_t i = 0; i < vec.size(); ++i) {
    if (i > 0) {
      os << ", ";
    }
    os << vec[i];
  }
  os << "}";
  return os;
}




代码解析

  • 重载对称性:int + MySetint - MySet 通过友元实现,确保单元素集合场景语义明确。
  • 赋值类操作:使用临时 unordered_setswap,避免边遍历边修改导致逻辑混乱。
  • 输出与向量转换:统一排序后输出,保证展示顺序稳定、可读。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值