一、核心数据结构设计
我们的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;
}
输入处理:
- 以空格和换行作为分隔符
- 逐个字符读取避免缓冲区溢出