【数据结构】模拟实现string

cpp 复制代码
namespace simulate_string
{





	class string 
	{
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		const static int npos = -1;//类型说明+作用域变量;
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		//迭代器相当于直接调用该类型的指针
		iterator begin()//指向首元素地址
		{
			return _str;
		}

	    const_iterator begin() const
		{
			return _str;
		}

		iterator end()//指向末尾元素的下一个地址,在string类中该地址存放的是'\0'
		{
			return _str+_size;
		}

		const_iterator end()const
		{
			return _str + _size;
		}

		//构造函数
		string(const char* str="")
			:_size(strlen(str))
		{
			_capacity = _size;//防止_size和_capacity声明顺序与初始化列表顺序相反;

			//开空间(_capacity是有效容量不包括'\0')
			_str = new char[_capacity+1];
			strcpy(_str,str);
		}

		//拷贝构造
		string(const string& s)
			:_size(s._size)
		{
			_capacity = s._capacity;				
			_str = new char[_capacity + 1];//多一个空间存放'\0'
			strcpy(_str,s._str);//会拷贝'\0';
			std::cout << "string(const string& s)" << std::endl;

		}

		//移动拷贝构造(移动语义)
		string(string&& s)//这里右值引用为什么不需要加const?因为要对右值进行资源转移。
		{
			swap(s);
			std::cout << "string(string&& s)" << std::endl;
		}

		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

		~string()
		{
			delete[] _str;
			_str = nullptr;
			_capacity = _size = 0;
		}

		size_t size() const
		{
			return _size;
		}

		
		char& operator[](size_t pos) 
		{
			assert(pos<_size);
			return _str[pos];
		}

		const char& operator[](size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}

		const char* c_str() 
		{
			return _str;
		}

		//赋值运算符重载
		string& operator=(const string& s)
		{		
			if (this != &s)
			{
				char* tmp = new char[s._capacity + 1];
				strcpy(tmp, s._str);
				delete[] _str;
				_str = tmp;
			
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}

		// 不修改成员变量数据的函数,最好都加上const

		//strcmp会返回0,-1,1;分别代表相等,小于,大于;
		bool operator==(const string& s)const
		{
			return strcmp(_str,s._str)==0;
		}
		bool operator>(const string& s)const 
		{
			return strcmp(_str, s._str)>0;
		}

		bool operator>=(const string& s)const
		{
			return *this>s||*this==s;
		}

		bool operator<(const string& s)const
		{
			return !(*this >= s);
		}

		bool operator<=(const string& s)const
		{
			return !(*this > s);
		}

		bool operator!=(const string& s)const
		{
			return !(*this == s);
		}


		
		

		void push_back(char& ch)
		{
			insert(_size,ch);
		}

		void append(const char* str)
		{
			insert(_size,str);
		}

		//如果出现s1+=s1的情况,阁下该如何应对?
		string& operator+=(const string& s)
		{
			if (this!= &s)
			{
				append(s._str);
			}
			else
			{

				//创建临时对象;
				string news(s);
				append(news._str);
			}
			
			return *this;
		}

		string& operator+=(char& ch)
		{
			push_back(ch);
			return *this;
		}

		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}

		void reserve(size_t n)//不能缩容
		{
			if (n > _capacity)//需要的空间大于当前容量才进行扩容!
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;//有效容量不包括\0;
			}
		}
		void resize(size_t n,char ch='\0')//开空间加初始化
		{
		    
			if (n <= _size)
			{
				_size = n;
				_str[_size] = '\0';
			}

			else 
			{
				if (n>_capacity)
				{
					reserve(n);
				}

				int i = _size;

				while (i < n)
				{
					_str[i] = ch;//初始化为传递的字符,没有就使用默认缺省;
					++i;
				}

				_size = n;
				_str[_size] = '\0';

			}
	
		}

    string& insert(size_t pos,char ch)
		{
			assert(pos<=_size);
			if (_size + 1 > _capacity)//需要扩容
			{
				reserve(_capacity * 2);
			}

			size_t end = _size+1;
			while (end>pos)//当pos为0这种情况时,无符号整数0再减1是无符号整数的最大值而不是-1,所以当end从0再减1时,会继续循环,访问_str[max],程序会崩;
			{
				//_str[end+1] = _str[end];不可以程序会崩;
				
				_str[end] = _str[end-1];
				--end;
			}
			_str[pos] = ch;
			++_size;
			return *this;

		}

		
	string& insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);//计算要插入字符的长度;

			if (_size + len > _capacity)
			{
				reserve(len + _size);//需要开辟的有效空间,不包括'\0'
			} 

			size_t end =_size;
		
			while (end>pos)//当end最小为1;
			{
				 _str[end+len-1]=_str[end-1];
				--end;
			}

			strncpy(_str+pos,str,len);//strcpy会把默认字符串的'\0'也加在后面,会覆盖原字符串的后面第一个字符;
			
			_size += len;
			_str[_size] = '\0';
			return *this;

		}


	string& erase(size_t pos=0,size_t len=npos)//如果不说明删除多少个,默认从当前位置删到完;
		{
			assert(pos<_size);
			if (len==npos||pos+len>=_size)//如果前面不判断len==npos,后面pos+len会溢出,size_t无符号正整数最大就是-1的补码,因为是无符号;
			{
				_size = pos;
				_str[_size] = '\0';
			}
			else
			{
				//连'\0'都拷贝,把_str+pos+len以后的所有字符都拷贝过来;
				strcpy(_str+pos,_str+pos+len); 
				_size -= len;
			}
			return *this;
		}



	//返回一个字符在_str中第一次出现的位置;
	size_t find(char ch,size_t pos=0)
	{
		assert(pos<_size);
		int i = 0;
		while (i<_size)
		{
			if (_str[i]==ch)
			{
				return i;
			}
			++i;
		}
		return npos;
	
	}

	//返回一个字符在_str中最后一次出现的位置;
	//实质是在_str中从后往前找与ch相等的下标索引;
	size_t rfind(char ch,size_t pos=npos)//size_t类型的pos被赋予size_t类型的npos=-1,则npos等于max int;
	{
		assert(pos>=0);
		if (pos == npos||pos>=_size)
			pos = _size-1;
		int i =pos;
		while (i>=0)
		{
			if (_str[i]==ch)
			{
				return i;
			}
			--i;
		}
		return npos;
	}


	//按顺序找_str中在str中第一次出现的位置,返回一个指针,指向这个字符;
	size_t find(const char* str,size_t pos=0)
	{
		assert(pos<_size);
		//解释strstr();实际上就是找字符串str在_str中第一次出现的位置;
		//Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
        
		char* p = strstr(_str+pos,str);
		//库里面的,按顺序找字符串2在字符串1中第一次出现的位置;
		
		if (p==nullptr)
		{
			return npos;

		}
		else
		{
			return p-_str;
		}
	}


	};

	

//************* 类外 ***************
	//流插入(写到类外保证cout<<s的格式),不用友元函数也可以访问s对象的每一个字符
	std::ostream& operator<<(std::ostream& out,const string& s)
	{
		for (int i=0;i<s.size();++i)
		{
			out << s[i] <<' ';
		}
	      
		return out;
	}

	//cout和cin分别是输入输出头文件下的一个ostream类对象和istream类对象;


	//流提取
	std::istream& operator>>(std::istream& in,string& s)
	{
		char ch=in.get();//输入流中的函数,每次取一个字符;相当于连空格都可以取到的cin;

		while (ch!=' '&&ch != '\n')//只要不读到enter也就是换行符,就一直提取;
		{
			s += ch;
			ch = in.get();
		}

		return in;//支持连续提取;
	}
相关推荐
ZSYP-S1 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
唐叔在学习1 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA1 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
武昌库里写JAVA4 小时前
浅谈怎样系统的准备前端面试
数据结构·vue.js·spring boot·算法·课程设计
S-X-S5 小时前
代码随想录刷题-数组
数据结构·算法
l138494274515 小时前
每日一题(4)
java·数据结构·算法
kyrie_sakura5 小时前
c++数据结构算法复习基础--13--基数算法
数据结构·c++·算法
XWXnb65 小时前
数据结构:顺序表
数据结构·算法
橘颂TA5 小时前
【C++】数据结构 顺序表的实现(详解)
开发语言·数据结构·c++·算法
R_.L5 小时前
数据结构:双向循坏链表
数据结构·链表