串的顺序存储:
概念:顺序串是用一组地址连续的存储单元来存储串中的字符序列,顺序串具有随机存取功能,缺点是插入删除元素时需要移动串中的有关元素
1.串空间的大小在编译时就已经确定,是静态的。难以适应插入、链接等操作
2.除了直接使用定长的字符数组存放串内容外,一般使用一个不会出现在串中的特殊字符放在串值的末尾来表示串的结束。所以串空间最大值为n时,最多只能放n-1个字符,所以此字符串的选择很重要,C++中以\0表示串值的终结
串的链式存储:
链式存储是利用单链表方式存储串值,串的这种链式存储结构分成单字符链表和快字符链表俩中,单字符链表每个结点的数据域只能存放一个字符,块链表的每个结点的数据域包含若干个字符。单字符链表的插入删除操作不需要移动元素,但指针使用空间浪费,快链表插入删除操作的元素移动限制在较小的范围内,但效率不高
求子串:返回当前串中指定位置i开始,长度为n的子串,不改变当前串,数组下标越界,当所需返回的字符串已超出了当前字符串n>len-i,修改为返回由i开始到串尾的字符串
串的插入:串的插入是指在当前串source的第i个字符处插入指定串target,显然,source串中的元素就需要向后移动,腾空放入target,可能出现source串字符数组越界的问题,需要申请更大容量的数组
串的删除:串的删除是指在当前串source的第i个字符处开始,删除长度为n的子串,显然,source串中第i+n开始的元素就需要向前移动,此时会出现俩个'\0';
#include<iostream.h>
#include<string.h>
class MyString
{
private:
char *element; //动态字符串数组
int size; //数组容量
int len; //串长度
void init(char *str=" ", int size=64); //初始化指定容量的串对象
public:
MyString(char *str=" "); //以字符串常量构造串对象
MyString(int size); //构造指定容量的空串对象
MyString(MyString &str); //拷贝构造,由已知新串复制
~MyString();
int length();
char charAt(int i);//返回地i个字符
bool setCharAt(int i,char ch);//设置第i个字符为ch
MyString substring(int i,int n);//返回地i个字符开始n个长度的子串
MyString substring(int i);//返回第i个字符到串尾的子串
void insert(int i, char *str); //第i个字符处插入子串
void insert(int i,MyString &str);//在第i个字符处插入串str
void comcat(MyString &str);//在当前串之后连接串str
bool remove(int i,int n); //删除第i个字符开始长度为n的子串
bool remove(int i); //删除第i个字符开始到串尾的子串
friend ostream& operator<<(ostream& out,MyString &s);
MyString& operator=(MyString &str);
MyString& operator+=(MyString &str); //连接串 在当前串之后连接串str
MyString operator +(MyString &str);//连接串,返回连接起来的新串
bool operator==(char *str);//比较俩个串是否相等
bool operator<(char *str);//比较俩个串的大小
bool operator<(MyString &str);
int index(MyString pattern); //返回模式串pattern在串中的首次匹配位置
int index(MyString pattern,int start);//返回模式串pattern从start开始的首次匹配位置支持通配符?
int indexGen (MyString pattern, int start);//返回模式串pattern从start开始的首次匹配位置支持通配符*
int lastIndex(MyString pattern);
void replace(MyString sub,MyString replacement);//替换串中包含的首个sub子串
void replaceAll(MyString sub,MyString replacement);//替换串中包含的所有sub子串
void remove(MyString sub);//删除串中包含的首个sub子串
void removeAll(MyString sub);//删除串中包含的所有sub子串
void uppercase();//将串中小写字母转化成大写字母
void trim(); //删除串对象中的空格字符
private:
void getNext(int next[]);//返回模式串pattern改进的next数组
};
MyString::init(char *str = " ", int size )
{
int i;
while(str[i]!='\0')
i++;
len = i;
size=size>len?size:len;
this->size=size<64?64:size;
element = new char[this ->size];
for(i=0;str[i]!='\0';i++)
element[i] =str[i];//复制字符串
element[i]='\0';
}
MyString::MyString(int size)
{
init(" ",size);
}
MyString::MyString(char *str )
{
init(str);
}
MyString::MyString(MyString &str)
{
init(str.element);
}
MyString::~MyString()
{
delete[]element;
}
int MyString::length()
{
return len;
}
char MyString::charAt(int i) //返回第i个字符
{
if(i>=0&&i<len)
{
element[i] = ch;
return true;
throw"字符序号越界";
}
}
bool MyString::setCharAt(int i, char ch) //设置第i个字符为ch
{
if(i>=0&&i<len)
{
element[i]=ch;
return true;
}
return false;
}
ostream& operator<<(ostream& out,MyString &str)
{
out<<"\" "<<str.element<<"\" ";
return out;
}
void MyString::comcat (MyString &str) //当前串最后插入str
{
insert(len, str.element );
}
MyString::MyString (char ch)
{
len = 1;
size =16;
element = new char[size];
element [0] =ch;
element [1] ='\0';
}
void MyString::uppercase()
{
for(int i=0;i<len;i++)
if(element[i]>='a'&&element[i]<='z')
element[i]-='a'-'A';
}
void MyString::trim ()
{
int i=0,j;
while(element[i]!=' '&&element[i]!='\0')
i++;
for(j=i;element[j]!='\0';j++)
if(element[j]!=' ')
element[i++]=element[j];
len = i;
element[len]='\0';
}
int MyString::index (char ch) //返回ch在当前串中的位置
{
for(int i=0;i<len;i++)
if(element[i]==ch)
return i;
return -1;
}
int MyString::index(MyString pattern)
{
return index(pattern, 0);
}
void MyString::replace(MyString sub, MyString replacement)
{
int i = index(sub);
if(i!=-1)
{
remove(i,sub.len); //删除
insert(i,replacement);//插入
}
}
void MyString::replaceAll(MyString sub, MyString replacement)
{
int i=index(sub);
while(i!=-1)
{
remove(i,sub.len);
insert(i,replacement);
i=index(sub,i++);
}
}
void MyString::remove(MyString sub)
{
remove(index(sub), sub.len);
}
void MyString::removeAll(MyString sub)
{
int i=0;
do{
i=index(sub,i);
remove(i,sub.len);
}while(i!=-1);
}
int MyString:index(MyString pattern,int start)//返回模式串pattern从start开始首次匹配位置
{
if(pattern.len>0&&len>=pattern.len)
{
int *next = new int [pattern.len];
pattern.getNext(next);
cout<<"next[]:";
for(int h=0;h<pattern.len;h++)
cout<<next[h]<<" ";
int i=start,j=0;
int count = 0;
while(i<len&&j<pattern.len)
{
if(j!=-1)count++;
cout<<"\ni="<<i<<" j="<<j<<" count="<<count;
cout<<" \n"<<element<<endl;
for(int space =0;space<i-j;space++)
{
cout<<" ";
}
cout<<pattern<<endl;
for(space = 0;space<=i;space++)
{
cout<<" ";
}
cout<<" ^"<<endl;
if(j==-1||element[i]==pattern.elemnet[j]||pattern.element[j]=='?')
{
i++;
j++;
}
else
j=next[j];
}
cout<<"\ncount="<<count<<endl;
if(j==pattern.len)
return i-j;
}
return -1;
}
void MyString::getNext(int next[])
{
next[0]=-1;
int j=0,k=-1;
while(j<len-1)
if(k==-1||element[j]==element[k]||element[j]=='?')
{
j++;
k++;
if(element[j]!=element[k])
next[j]=k;
else
next[j]=next[k];
}
else
k=next[k];
}
int MyString::indexGen(MyString pattern, int place)
{
MyString sonPattern;
int sonPlace = pattern.index("*",0);
if(sonPlace!=-1){
sonPattern = pattern.substring(0,sonPlace);
int tempPlace =this->index(sonPattern.place);
if(tempPlace!=-1)
{
int sonPatternSize =sonPattern.length();
MyString sonSubPattern = pattern.substring(sonPlace+1);
this->indexGen(sonSubPattern,tempPlace+sonPatternSize);
return place;
}
else
return tempPlace;
}else
this->index(pattern,place);
}
MyString MyString::substring(int i, int n)//返回从第i个字符开始长度为n的子串
{
if(len == 0||i>=len||n<=0)
{
Mystring sub;
return sub;
}
if(n>len-i)
n=len-i;
MyString sub(n);
for(int j=0;j<n;j++)
sub.element[j] = this->element[i+j];
sub.element[n] = '\0';
sub.len = n;
return sub;
}
MyString MyString::substring(int i)
{
return substring(i,len-i+1);
}
void MyString::insert(int i, char *str)
{
int n=strlen(str),j;
if(n==0)
return ;
if(i<0)
i=0;
if(i>len)
i=len;
char *p=element;
if(size-len<=n)
{
size =(len+n+1)*2;
element = new char[size];
for(j=0;j<i;j++)
element[j] = p [j];
}
for(j=len;j>=i;j--)
element[j+n]=p[j];
if(p!=element)
delete []p;
for(j=0;j<n;j++)
element[i+j]=str[j];
len +=n;
}
void MyString::insert(int i; MyString&str)
{
insert(i,srt.element);
}
bool MyString::remove(int i, int n)
{
if(len ==0 ||i<0||i>=len||n<=0)
return false;
if(n>len -i)
n=len-i;
for(int j=i+n;j<=len;j++)
element[j-n]=element[j];
len-=n;
return true;
}
bool MyString::remove(int i)
{
return remove(i,len-i);
}
MyString& MyString::operator =(MyString &str)
{
len =0;
concat (str);
return *this;
}
MyString&MyString::operator +=(MyString &str) //链接串 返回新串 改变当前串
{
concat(str);
return *this;
}
MyString MyString::operator +(MyString &str) //链接串,返回新串 ,不改变当前串
{
MyString result(*this);
result+=str;
return result;
}
bool MyString::operator ==(char *str)
{
int i=0;
while(element[i]!='\0'&&str[i]!='\0')
if(element[i]!=str[i])
return false;
else i++;
return (element[i]=='\0'&&str[i]=='\0')?true:false;
}
bool MyString::operator ==(MyString &str)
{
return (*this == str.element);
}
bool MyString::operator<(char *str)
{
int i = 0;
while(element[i]!='\0'&&str[i]!='\0')
if(element[i]==str[i])
i++;
else if(element[i]<str[i])
return true;
else
return false;
return (element[i]=='\0'&&str[i]=='\0'?false:true);
}
bool MyString::operator <(MyString &str)
{
return (*this<str.element);
}
Brute-Force算法:
概念:从目标串target的第一个字符起和模式串pattern的第一个字符串进行比较,若相等,继续逐个比较后续字符,否则从target的第二个字符起再重新和pattern的第一个字符比较
1.当模式串pattern的长度大于目标串target,或者比较目标串中i失败,而n-i-1<模式串长度时,不需要再进行比较。
2.模式匹配时,由于采用的是从头到尾穷尽查找的方式,不会丢失可能的匹配。
3.由于经常会利用字符串的尾部几个字符表示相关信息,从头到尾去查找就浪费了时间。所以添加lastIndex进行判断
缺点:Brute-Force算法是一种回溯的模式匹配算法。虽没有任何丢失匹配的可能,但是每次匹配都没有利用前一次匹配结果,算法中存在较多重复比较,增加了时间复杂度
int MyString::index (pattern)
{
return index(pattern,0);
}
int MyString::index(MyString pattern, int start)
{
if(pattern.len>0&&len>=pattern.len)
{
int i=start,j=0,count=0;
while(i<=len-pattern.len &&j<=pattern.len )
{
count ++;
cout<<" \ni="<<i<<" j="<<j<<" count="<<count;
if(element[i+j]==pattern.element[j])
j++;
else
{
i++;
j=0;
}
}
cout<<" \ncount="<<count<<endl;
if(j==pattern.len)
return i;
}
return -1;
}
int MyString::lastIndex(MyString pattern)
{
return index(pattern.len-pattern.length());
}
#define _CRT_SECURE_NO_WARNINGS
#include"MyString.h"
int main()
{
MyString target("data.doc"),pattern(" .doc");
cout<<target.lastIndex(pattern);
}