努力努力再努力的博客

每天会不定时更新一些我的学习心得,欢迎大家共同交流,共同进步

经典面试题—string类的详细分析与实现

【摘要】在常见的面试场景中,如果面试官想要考察你对于C++的掌握程度
能够很完整的写出一个string类是很重要的。因为string类包含了C++的
很多知识,可以系统的将你的知识发挥出来。在这篇博客中,我将会详细地
说明string类的实现过程,方便你们理解。
   目录
          string类的成员分析
 
          想要完成的常见操作

          实现过程
 
          测试代码

          总结

1.要构建一个类,必须要具有基本的一些函数,比如构造函数和析构函数
       如果要进行赋值操作或者拷贝操作,那就还得有拷贝构造函数和赋值运算符重载为了方便,我把所有的函数都放在类的内部完成,这样可以最大限度的避免成员使用权限问题。但是,当工程量比较大时我并不建议这么做,这样很容易导致混淆。
2.分析string类的需求
 我们想要完成的string类,可以进行一些基本的增删查改操作,它是动态的存储,所以内存不够时还需要扩容。通过运算符的重载我们还可以完成一些字符串的+操作,比较大小操作,这些就是我们基本要完成的东西。
3.实现过程
1.既然是对字符串进行操作,那么我们就需要做第一个工作,完成字符串的构造函数还有字符串的拷贝构造函数和赋值操作符重载,有了构造函数,那么相对应的也就需要一个析构函数用于内存的动态释放
这只是第一步
2.如果内存大小不够继续进行操作时,还需要一个动态开辟内存的函数
3.要实现增删查改的第一步,尾部插入一个字符或者一个字符串,尾部删除一个字符,关于尾部删除一个字符串的操作也就是
删除一个字符的情况的变形,还有一种情况就是在任意位置插入一个字符或者字符串
4.第四步就是操作符的重载函数了。关于/+=(一个字符)/+=(一个字符串)/+(一个字符)/+(一个字符串)/
关于 />/</>=/<=/==/!=/这些基本上都只要复用函数的返回值就可以实现了,因此只需要实现两个函数即可
5.查找函数的实现,查找一个字符或者一个子串
6.替换函数:替换一个字符或者替换一个字符串

代码如下
#define _CRT_SECURE_NO_WARNINGS -1

#include <new.h>
#include <iostream>
using namespace std;

class String
{
public:
    //构造函数
    String(const char* str = "")
        :_str(new char[strlen(str) + 1])
    {
        strcpy(_str, str);
        _size = strlen(str);
        _capacity = _size;
    }

    ////拷贝构造函数
    //String(const String& s)//传统写法
    //  :_str(new char[s._capacity])
    //{
    //  strcpy(_str, s._str);
    //  _size = s._size;
    //  _capacity = s._capacity;
    //}

    ////赋值操作符重载
    //String& operator=(String s)//传统写法
    //{
    //  if (this != &s)
    //  {
    //      char* tmp = new char[strlen(s._str) + 1];
    //      delete[] _str;
    //      strcpy(_str, s._str);
    //      _size = s._size;
    //      _capacity = s._capacity;
    //  }

    //  return *this;
    //}

    // s1.Swap(s2); 
    void Swap(String& s)
    {
        char* tmp = _str;
        _str = s._str;
        s._str = tmp;
    }
    // 拷贝构造函数
    // String s2(s1) 
    String(const String& s)//现代写法
        :_str(NULL)
    {
        String tmp(s._str);
        this->Swap(tmp);
        _size = s._size;
        _capacity = s._capacity;
    }
    //赋值操作符重载
    // s1 = s2 
    String& operator=(String s)//现代写法
    {
        if (this != &s)
        {
            String tmp(s._str);
            this->Swap(s);
            _size = s._size;
            _capacity = s._capacity;
        }
        return *this;   
    }
    //析构函数
    ~String()
    {
        if (_str != NULL)
        {
            delete[] _str;
            _str = NULL;
            _size = 0;
            _capacity = 0;
        }
    }
    //获取类中的字符串成员变量
    const char* c_str()
    {
        return _str;
    }

    //扩容
    void Expand(size_t n)
    {
        if (n > _capacity)
        {
            char* tmp = new char[n + 1];
            strcpy(tmp, _str);
            delete[] _str;
            _str = tmp;
            _capacity = n;
        }
    }
    //尾插一个字符
    void PushBack(char ch)
    {
        if (_size >= _capacity)
        {
            Expand(_capacity * 2);
        }
        _str[_size++] = ch;
        _str[_size] = '\0';
    }
    //尾插一个字符串
    void PushBack(const char* str)
    {
        if (str == NULL)
        {
            return;
        }
        int len = strlen(str);
        if (_size + len > _capacity)
        {
            Expand(_size + len);
        }
        strcpy(_str + _size, str);
        _size += len;
    }
    //+操作符重载,+一个字符
    String operator+(char ch)
    {
        String tmp(*this);
        tmp.PushBack(ch);
        return tmp;
    }
    //+=操作符重载,+=一个字符
    String& operator+=(char ch)
    {
        //this->PushBack(ch);
        PushBack(ch);
        return *this;
    }

    //+操作符重载,+一个字符串
    String operator+(const char* str)
    {
        String tmp(*this);
        tmp.PushBack(str);
        return tmp;
    }
    //+=操作符重载,+=一个字符串
    String& operator+=(const char* str)
    {
        //this->PushBack(str);
        PushBack(str);
        return *this;
    }
    //尾删一个字符
    void PopBack()
    {
        _str[_size] = '\0';
        _size--;
    }
    //指定位置插入一个字符
    void Insert(size_t pos, char ch)
    {
        if (pos > _size)//插入位置不合法
        {
            return;
        }
        if (_size >= _capacity)//扩容
        {
            Expand(_capacity * 2);
        }
        if (pos == _size)
        {
            _str[_size++] = ch;
        }
        else
        {
            char* tmp = new char[_size - pos + 1];
            strcpy(tmp, _str + pos);
            _str[pos] = ch;
            strcpy(_str + pos + 1, tmp);
            _size++;
            delete[] tmp;
        }
    }
    //指定位置插入一个字符串
    void Insert(size_t pos, const char* str)
    {
        if (pos > _size || str == NULL)
        {
            return;
        }
        int len = strlen(str);
        if (_size + len > _capacity)//扩容
        {
            Expand(_size + len);
        }
        if (pos == _size)
        {
            strcat(_str, str);
        }
        else
        {
            char* tmp = new char[_size - pos + 1];
            strcpy(tmp, _str + pos);
            strcpy(_str + pos,str);
            strcpy(_str + pos + len, tmp);
            ////或直接使用strcat
            //strcat(_str, tmp);
            delete[] tmp;
        }
    }
    //删除pos下标开始往后n个元素
    void Erase(size_t pos, size_t n = 1)
    {
        if (pos > _size)
        {
            return;
        }
        char* str = _str + pos;
        while (*str != '\0' && n > 0)
        {
            *str = '\0';
            str++;
            n--;
            _size--;
        }
        strcpy(_str + pos, str);
    }
    //查找字符串中的某个字符
    size_t Find(char ch)
    {
        char* str = _str;
        while (*str != '\0')
        {
            if (*str == ch)
            {
                return (int)(str - _str);
            }
            str++;
        }
        return -1;
    }
    //查找第一个子串的的位置
    size_t Find(const char* str)
    {
        if (str == NULL)
        {
            return -1;
        }
        char* tmp = strstr(_str, str);
        if (tmp != NULL)
        {
            return (size_t)(tmp - _str);
        }
        return -1;
    }
    //更改字符串中的某个字符
    void Replace(char ch1, char ch2)
    {
        char* str = _str;
        while (*str != '\0')
        {
            if (*str == ch1)
            {
                *str = ch2;
            }
            str++;
        }
    }
    //替换字符串中的某个字串
    void Replace(const char* sub1, const char* sub2)
    {
        if (sub1 == NULL || sub2 == NULL || strcmp(sub1, sub2) == 0)
        {
            return;
        }
        size_t pos = Find(sub1);
        if (pos != -1)
        {
            char* str = _str;
            int len = strlen(_str);
            int len1 = strlen(sub1);
            int len2 = strlen(sub2);

            if (len1 == len2)
            {
                while (pos != -1)
                {
                    _str = _str + pos;
                    int i = 0;
                    while (i < len1)
                    {
                        _str[i] = sub2[i];
                        i++;
                    }
                    pos = Find(sub1);
                }
                _str = str;
            }
            else
            {
                int count = 0;
                char** arr = new char*[len];
                memset(arr, 0, sizeof(char*)*len);
                while (pos != -1)
                {
                    _str =_str + pos + 1;
                    arr[count] = _str - 1;
                    count++;
                    pos = Find(sub1);
                }
                _str = str;
                int capacity = len + count*(len2 - len1);
                char* newStr = new char[capacity + 1];
                memset(newStr, 0, capacity + 1);
                count = 0;
                char* cur = newStr;
                while (*_str != '\0')
                {
                    if (_str == arr[count])
                    {
                        for (int i = 0; i < len2; i++)
                        {
                            cur[i] = sub2[i];
                        }
                        _str += len1;
                        cur += len2;
                        count++;
                    }
                    else
                    {
                        *cur++ = *_str++;
                    }   
                }
                _str = newStr;
                _size = capacity;
                _capacity = capacity;
                newStr = str;
                delete[] newStr;
            }
        }
        else
        {
            return;
        }
    }

    // >操作符重载,比较字符串大小
    bool operator>(const String& s)
    {
        if (this == &s || strcmp(_str, s._str) > 0)
        {
            return true;
        }
        return false;
    }
    // =操作符重载,判断字符串是否相等
    bool operator==(const String& s)
    {
        if (this == &s || strcmp(_str, s._str) == 0)
        {
            return true;
        }
        return false;
    }
    bool operator>=(const String& s)
    {
        if (*this > s && *this == s)
        {
            return true;
        }
        return false;
    }
    bool operator<(const String& s)
    {
        if (!(*this >= s))
        {
            return true;
        }
        return false;
    }
    bool operator<=(const String& s)
    {
        if (!(*this > s))
        {
            return true;
        }
        return false;
    }
    bool operator!=(const String& s)
    {
        if (!(*this == s))
        {
            return true;
        }
        return false;
    }

private:
    //char _buffer[16];
    char* _str;
    size_t _size;
    size_t _capacity;
};

int main()
{   
    //String s1("abc");
    //String s2(s1);
    //String s3("123abc");
    //s3 = s1;
    //cout << (s3 + 'd').c_str() << endl;
    //cout << (s3 + 'e').c_str() << endl;
    //cout << (s3 + 'f').c_str() << endl;
    //cout << (s3 + 'g').c_str() << endl;
    //cout << (s3 + 'h').c_str() << endl;
    //s3 += "123456";
    //s3.Insert(1, 'x');
    //s3.Insert(2, 'y');
    //s3.Insert(3, 'z');
    //s3.Insert(1, '0');
    //s3.Insert(0, "789");
    //cout << s3.Find('a') << endl;
    //s3.Replace('a', '1');
    //cout << s3.Find('a') << endl;
    //s3.Erase(0, 3);
    ////string s="abc123abc";
    ////s = s.replace("abc", "xx");
    //cout << s3.Find('b') << endl;
    //cout << s3.Find('w') << endl;

    String s("abc123");
    s.Replace("xyz", "asd");
    s.Replace("a", "ddd");
    s.Replace("123", "f");
    s.Replace("dbc", "666");
    s.Replace("666", "6");
    cout << s.c_str() << endl;
    system("pause");
    return 0;
}

测试用例结果


阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zb1593496558/article/details/79965368
个人分类: c++
上一篇经典面试题-(日期类的实现)
下一篇深浅拷贝剖析
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭