C++手写string类

一、核心数据结构设计

我们的String类包含三个核心成员变量:

class string {
private:
    char* _str;       // 字符串存储的堆内存指针
    size_t _size;     // 有效字符数量(不含'\0')
    size_t _capacity; // 当前分配的内存容量
};

设计遵循了C++标准库的基本思路:

  • _str:动态分配在堆内存中的字符数组
  • _size:实际字符串长度(O(1)时间复杂度获取长度)
  • _capacity:当前分配的内存空间(实现高效扩容)

 二、关键功能实现

1. 构造函数与资源管理

// 带参构造函数
string::string(const char* str)
    :_size(strlen(str)) 
{
    _capacity = _size;
    _str = new char[_capacity + 1]; // 额外空间存储'\0'
    strcpy(_str, str);
}

// 拷贝构造(深拷贝)
string::string(const string& str) {
    _size = str._size;
    _capacity = _size;
    _str = new char[_capacity + 1];
    strcpy(_str, str._str); // 深度复制内容
}

// 析构函数
string::~string() {
    delete[] _str;  // 释放堆内存
    _str = nullptr;
    _size = 0;
    _capacity = 0;
}

核心要点

  • 深拷贝避免多个对象共享内存
  • 构造函数预留+1空间存储结束符\0
  • 析构函数确保资源释放

2. 高效内存管理

void string::reserve(size_t n) {
    if (n > _capacity) {
        char* tmp = new char[n + 1]; // 申请新空间
        strcpy(tmp, _str);           // 复制内容
        delete[] _str;               // 释放旧空间
        _str = tmp;
        _capacity = n;              // 更新容量
    }
}

扩容策略

  • _size == _capacity时触发扩容
  • 扩容倍数:newCapacity = (_capacity == 0) ? 4 : 2 * _capacity

3. 插入操作实现

void string::insert(size_t pos, char ch) {
    // 边界检查...
    
    if (_capacity == _size) {
        size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;
        reserve(newcapacity);
    }
    
    // 移动元素
    size_t end = _size + 1;
    while (end > pos) {
        _str[end] = _str[end - 1];
        end--;
    }
    
    _str[pos] = ch;  // 插入新字符
    _size++;
}

时间复杂度

  • 最坏情况(头部插入):O(n)
  • 最佳情况(尾部插入):O(1)

4. 迭代器实现

typedef char* iterator;
iterator begin() { return _str; }
iterator end() { return _str + _size; }

// const版本迭代器
typedef const char* const_iterator;
const_iterator begin() const { return _str; }
const_iterator end() const { return _str + _size; }

三、核心算法实现

1. 子串截取

string string::substr(size_t pos, size_t len) {
    if (len >= _size - pos) {
        return string(_str + pos); // 直接构造
    } 
    else 
    {
        string sub;
        sub.reserve(len);
        for (size_t i = 0; i < len; i++) 
        {
            sub.push_back(*(_str + pos + i));
        }
        return sub;
    }
}

策略选择

  • 当请求长度超过可用长度时,返回从pos到结尾的子串
  • 否则精确截取指定长度

2. 字符串查找

size_t string::find(char ch, size_t pos) {
    for (size_t i = pos; i < _size; i++) {
        if (_str[i] == ch) return i;
    }
    return npos;
}

size_t string::find(const char* sub, size_t pos) {
    char* p = strstr(_str + pos, sub); // 使用标准库函数
    return  p - _str;
}

算法选择

  • 单字符查找:直接遍历O(n)
  • 子串查找:使用strstr()库函数(通常为O(n+m))
char* strstr(const char* haystack, const char* needle);
  • 返回值:找到时返回子串首次出现的地址指针,未找到返回NULL
  • 参数haystack(被搜索的主字符串),needle(要查找的子字符串)

四、操作符重载

1. 下标访问操作符

char& operator[](size_t pos) {
    // 边界检查
    if (pos >= _size) {
        cerr << "Error: Access out of bounds" << endl;
        exit(1);
    }
    return _str[pos]; // 返回引用支持修改
}

关键点

  • 提供const和非const两个版本
  • 严格边界检查防止越界

2. 比较操作符

bool operator<(const string& s) const {
    return strcmp(_str, s._str) < 0;
}

bool operator==(const string& s) const {
    return strcmp(_str, s._str) == 0;
}

// 其他比较操作符基于<和==实现

实现技巧

  • 基于strcmp()实现核心比较
  • 派生操作符复用基础操作符

3. 流操作符重载

istream& operator>>(istream& is, string& str) {
    str.clear(); // 清空原有内容
    char ch = is.get();
    while (ch != ' ' && ch != '\n') {
        str += ch;  // 追加字符
        ch = is.get();
    }
    return is;
}

输入处理

  • 以空格和换行作为分隔符
  • 逐个字符读取避免缓冲区溢出

以下是一个简单的基于链表实现的手写Map示例,你可以参考一下: ```c++ #include <iostream> #include <string> using namespace std; template <typename KeyType, typename ValueType> class Map { private: struct Node { KeyType key; ValueType value; Node* next; Node(const KeyType& k, const ValueType& v) : key(k), value(v), next(nullptr) {} }; Node* head; public: Map() : head(nullptr) {} ~Map() { Node* node = head; while (node != nullptr) { Node* next = node->next; delete node; node = next; } } void insert(const KeyType& k, const ValueType& v) { Node* node = head; while (node != nullptr) { if (node->key == k) { node->value = v; return; } node = node->next; } node = new Node(k, v); node->next = head; head = node; } const ValueType& operator[](const KeyType& k) const { Node* node = head; while (node != nullptr) { if (node->key == k) { return node->value; } node = node->next; } throw "Key not found!"; } bool contains(const KeyType& k) const { Node* node = head; while (node != nullptr) { if (node->key == k) { return true; } node = node->next; } return false; } }; int main() { Map<string, int> myMap; myMap.insert("apple", 3); myMap.insert("banana", 6); myMap.insert("cherry", 9); cout << myMap["apple"] << endl; // 3 cout << myMap["banana"] << endl; // 6 cout << myMap["cherry"] << endl; // 9 cout << myMap["durian"] << endl; // throws "Key not found!" if (myMap.contains("apple")) { cout << "myMap contains 'apple'" << endl; } if (!myMap.contains("durian")) { cout << "myMap does not contain 'durian'" << endl; } return 0; } ``` 在这个示例中,我们使用了一个简单的单向链表来存储键值对。Map提供了三个基本的操作:insert、operator[]和contains。insert操作将一个键值对插入到链表中,如果键已经存在,则更新对应的值。operator[]操作用于获取特定键的值,如果键不存在,则抛出异常。contains操作用于检查特定键是否存在于Map中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值