手动实现std:iterator/std:string/std::vector/std::list/std::map/std:set

目录

  • [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的遍历
};
相关推荐
小羊羊Python2 小时前
Sound Maze - 基于 SFML+C++14 的音效迷宫开源游戏 | MIT 协议
c++·游戏·开源
txinyu的博客2 小时前
HTTP服务实现用户级窗口限流
开发语言·c++·分布式·网络协议·http
代码村新手2 小时前
C++-类和对象(上)
开发语言·c++
txinyu的博客2 小时前
map和unordered_map的性能对比
开发语言·数据结构·c++·算法·哈希算法·散列表
mjhcsp2 小时前
C++ 后缀数组(SA):原理、实现与应用全解析
java·开发语言·c++·后缀数组sa
hui函数3 小时前
如何解决 pip install 编译报错 ‘cl.exe’ not found(缺少 VS C++ 工具集)问题
开发语言·c++·pip
码农小韩3 小时前
基于Linux的C++学习——循环
linux·c语言·开发语言·c++·算法
消失的旧时光-19433 小时前
C++ 命名空间 namespace 讲透:从 std:: 到工程实践
开发语言·c++
程序员Jared3 小时前
C++11—thread库
c++·thread