目录
- [1. 基础:实现迭代器基类(模拟 std::iterator)](#1. 基础:实现迭代器基类(模拟 std::iterator))
- [2. 实现 my_std::string(模拟 std::string)](#2. 实现 my_std::string(模拟 std::string))
- [3. std::vector](#3. std::vector)
- [4. std::list](#4. std::list)
- [5. std::map](#5. std::map)
- [6. std::set](#6. std::set)
1. 基础:实现迭代器基类(模拟 std::iterator)
C++17 已弃用 std::iterator 基类,但我们可以手动实现一个迭代器特性基类,定义迭代器的核心类型别名:
伪代码:
cpp
// 迭代器基类伪代码(核心是定义迭代器的能力和类型)
struct 迭代器基类 {
迭代器类别; // 随机访问/双向/前向
值类型; // 迭代器指向的数据类型
指针类型; // 指向数据的指针
引用类型; // 数据的引用
}
// 随机访问迭代器(vector/string用)
struct 随机访问迭代器 : 迭代器基类 {
核心操作:
- 解引用:*it → 获取数据
- 自增/自减:++it/--it → 指针±1
- 随机跳转:it+n/it-n → 指针±n
- 比较:==/!= → 指针是否相等
}
// 双向迭代器(list/map/set用)
struct 双向迭代器 : 迭代器基类 {
核心操作:
- 解引用:*it → 获取数据
- 自增/自减:++it/--it → 节点跳next/prev
- 比较:==/!= → 节点是否相等
// 无随机跳转能力
}
2. 实现 my_std::string(模拟 std::string)
底层基于动态字符数组实现,核心功能包括构造、析构、拼接、访问等:
cpp
#include <cstring>
#include <iostream>
// 极简string:仅保留核心功能
class MyString {
public:
// 构造
MyString(const char* str = "") {
len = strlen(str);
cap = len;
data = new char[cap + 1]; // +1存\0
strcpy(data, str);
}
// 析构
~MyString() { delete[] data; }
// 拼接
void append(const MyString& other) {
int new_len = len + other.len;
// 扩容
if (new_len > cap) {
cap = new_len * 2;
char* new_data = new char[cap + 1];
strcpy(new_data, data);
delete[] data;
data = new_data;
}
// 拼接
strcpy(data + len, other.data);
len = new_len;
}
// 访问
char& operator[](int pos) { return data[pos]; }
// 辅助:获取C字符串
const char* c_str() { return data; }
private:
char* data = nullptr;
int len = 0; // 长度
int cap = 0; // 容量
};
// 测试
int main() {
MyString s1 = "hello";
MyString s2 = " world";
s1.append(s2);
std::cout << s1.c_str() << std::endl; // 输出:hello world
return 0;
}
cpp
// string核心逻辑
class string {
成员变量:
- char* 数据指针; // 存储字符的动态数组
- int 长度; // 有效字符数(不含\0)
- int 容量; // 数组总大小
核心方法:
1. 构造:
- 分配容量 = 字符串长度
- 数据指针 = 新数组,拷贝字符串内容
2. 扩容:
- 若长度 ≥ 容量 → 新容量=原容量×2
- 分配新数组,拷贝旧数据,释放旧数组
3. 拼接(+=):
- 扩容(如果需要)
- 把新字符串拷贝到旧字符串末尾
- 更新长度
4. 访问:[] → 数据指针[下标](检查下标越界)
5. 析构:释放数据指针
}
3. std::vector
cpp
#include <iostream>
// 极简vector:仅支持int类型,核心功能
class MyVector {
public:
// 构造
MyVector() : data(nullptr), len(0), cap(0) {}
// 析构
~MyVector() { delete[] data; }
// 尾部插入
void push_back(int val) {
// 扩容:空则初始容量1,否则×2
if (len >= cap) {
int new_cap = (cap == 0) ? 1 : cap * 2;
int* new_data = new int[new_cap];
// 拷贝旧数据
for (int i = 0; i < len; i++) {
new_data[i] = data[i];
}
delete[] data;
data = new_data;
cap = new_cap;
}
data[len++] = val;
}
// 访问
int& operator[](int pos) { return data[pos]; }
// 辅助:获取长度
int size() { return len; }
private:
int* data = nullptr;
int len = 0; // 长度
int cap = 0; // 容量
};
// 测试
int main() {
MyVector vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
for (int i = 0; i < vec.size(); i++) {
std::cout << vec[i] << " "; // 输出:1 2 3
}
return 0;
}
伪代码
cpp
// vector核心逻辑
class vector {
成员变量:
- T* 数据指针; // 动态数组(泛型)
- int 长度; // 元素个数
- int 容量; // 数组总大小
核心方法:
1. 构造:分配数组,初始化元素
2. 尾部插入(push_back):
- 若长度≥容量 → 扩容(容量×2)
- 数据指针[长度] = 新元素,长度+1
3. 尾部删除(pop_back):长度-1(仅标记,不释放内存)
4. 访问:[] → 数据指针[下标]
5. 析构:释放数据指针
}
4. std::list
cpp
#include <iostream>
// 极简list:仅支持int类型,核心功能
class MyList {
// 链表节点
struct Node {
int val;
Node* prev;
Node* next;
Node(int v) : val(v), prev(nullptr), next(nullptr) {}
};
public:
// 构造:创建哨兵节点(循环链表)
MyList() {
head = new Node(0); // 哨兵节点,值无意义
head->prev = head;
head->next = head;
len = 0;
}
// 析构
~MyList() {
Node* cur = head->next;
while (cur != head) { // 遍历删除所有节点
Node* tmp = cur;
cur = cur->next;
delete tmp;
}
delete head; // 删除哨兵节点
}
// 尾部插入
void push_back(int val) {
Node* new_node = new Node(val);
// 调整指针
new_node->prev = head->prev;
new_node->next = head;
head->prev->next = new_node;
head->prev = new_node;
len++;
}
// 遍历(简化:无迭代器,直接打印)
void print() {
Node* cur = head->next;
while (cur != head) {
std::cout << cur->val << " ";
cur = cur->next;
}
}
private:
Node* head = nullptr; // 哨兵节点
int len = 0; // 长度
};
// 测试
int main() {
MyList lst;
lst.push_back(10);
lst.push_back(20);
lst.push_back(30);
lst.print(); // 输出:10 20 30
return 0;
}
伪代码
cpp
// list核心逻辑
// 链表节点
struct 节点 {
数据;
节点* 前驱;
节点* 后继;
}
class list {
成员变量:
- 节点* 头节点; // 哨兵节点(简化循环链表)
- int 长度; // 元素个数
核心方法:
1. 构造:创建哨兵节点(前驱/后继指向自己)
2. 尾部插入(push_back):
- 创建新节点
- 新节点前驱 = 哨兵节点前驱,新节点后继 = 哨兵节点
- 哨兵节点前驱的后继 = 新节点,哨兵节点前驱 = 新节点
- 长度+1
3. 尾部删除(pop_back):
- 找到最后一个节点(哨兵节点前驱)
- 前驱节点的后继 = 哨兵节点,哨兵节点前驱 = 前驱节点
- 删除最后一个节点,长度-1
4. 析构:遍历删除所有节点,释放哨兵节点
}
5. std::map
cpp
#include <iostream>
#include <string>
// 极简map:仅支持<int, string>,核心功能
class MyMap {
// BST节点
struct Node {
int key;
std::string val;
Node* left;
Node* right;
Node(int k, std::string v) : key(k), val(v), left(nullptr), right(nullptr) {}
};
public:
// 构造
MyMap() : root(nullptr), len(0) {}
// 析构:递归删除节点
~MyMap() { destroy(root); }
// 插入/访问([]运算符)
std::string& operator[](int key) {
// 空树:创建根节点
if (!root) {
root = new Node(key, "");
len++;
return root->val;
}
// 遍历BST找位置
Node* cur = root;
while (true) {
if (key < cur->key) { // 键更小→左子树
if (!cur->left) {
cur->left = new Node(key, "");
len++;
return cur->left->val;
}
cur = cur->left;
} else if (key > cur->key) { // 键更大→右子树
if (!cur->right) {
cur->right = new Node(key, "");
len++;
return cur->right->val;
}
cur = cur->right;
} else { // 键已存在→返回值
return cur->val;
}
}
}
// 中序遍历(输出有序键值对)
void inorder(Node* node) {
if (!node) return;
inorder(node->left);
std::cout << node->key << ":" << node->val << " ";
inorder(node->right);
}
// 辅助:打印所有元素
void print() { inorder(root); }
private:
// 递归销毁节点
void destroy(Node* node) {
if (!node) return;
destroy(node->left);
destroy(node->right);
delete node;
}
Node* root = nullptr;
int len = 0;
};
// 测试
int main() {
MyMap mp;
mp[1] = "one";
mp[3] = "three";
mp[2] = "two";
mp.print(); // 输出:1:one 2:two 3:three(中序遍历有序)
return 0;
}
伪代码
cpp
// map核心逻辑(键值对,键唯一且有序)
// BST节点
struct 节点 {
键值对<键, 值>;
节点* 左子树; // 键更小
节点* 右子树; // 键更大
}
class map {
成员变量:
- 节点* 根节点;
- int 长度;
核心方法:
1. 插入([]运算符):
- 若根节点为空 → 根节点=新节点
- 否则:遍历BST,找到插入位置(键小→左,键大→右)
- 若键已存在 → 更新值;否则 → 创建新节点,长度+1
2. 查找:遍历BST,找到键相等的节点,返回值
3. 析构:递归删除所有节点
}
6. std::set
cpp
// set核心逻辑(仅存键,无值,键唯一有序)
class set {
成员变量:
- map 内部map; // 复用map的BST逻辑,值用bool占位
核心方法:
1. 插入:map.insert(键, true) → 键不存在则插入
2. 查找:map.find(键) → 是否存在
3. 遍历:遍历map的键(中序遍历有序)
}
// 极简实现:直接复用上面的MyMap,只存键,值忽略
class MySet {
MyMap mp;
public:
void insert(int key) { mp[key] = ""; } // 值无意义,仅占位
void print() { mp.print(); } // 复用map的遍历
};