串说白了就是,元素是字符的线性表。这样一来就分为顺序存储和链式存储。
顺序存储我们用数组,加上当前表长。用一个结构体构造。
#include<iostream>
#include<stdio.h>
#define maxn 100
#define ERROR 0
#define OK 1//定义一些标志
typedef int Statue;//重命名 int,用bool也行,来标记函数运行是否成功
using namespace std;
typedef struct mystring//结构体定义
{
char ch[maxn];
int length=0;//当前表长
}Mystring;
存储写好了,我们先写创建(输入)。以#为结束符创建字符串。例,ABCDEF# 这样在屏幕上输入。
void create_Mystring(Mystring &s)//传的是引用型,这样,才能改变数组里的内容
{
int i=0;
char temp;
cin>>temp;//输入字符
while(temp!='#')//当输入不是#时,一直输入
{
s.ch[i]=temp;//赋值
i++;
s.length++;//非常重要的表长加一!!!!!!
cin>>temp;//继续输入
}
}
写完输入我们写输出,有了输入和输出才能调试其他的函数。
void print_Mystring(Mystring s)//输出类型,可以不用引用型,因为我们输出不要改变字符串
{
int i;
for(i=0;i<s.length;i++)//小于表长时,一直输出
cout<<s.ch[i];
cout<<endl;//输出换行
}
为了统一,我们写了一个获取字符串长度的函数,很简单的return。
int string_leng(Mystring s)
{
return s.length;
}
接下来的操作我们写插入,我愿称为顺序表插入的增强版。顺序表的时候,我们只要插入一个元素,我们这是吧一个串插入到另一个串中。
Mystring string_insert(Mystring s,int index,Mystring temp)
{//注意参数,第一个是被插入的串,第二个是插入的起始位置,第三是插入的串
int i;
int temp_len=temp.length,s_len=s.length;//这个中间变量必须设,这代表原始串的长度。
//如果不设,我们在下面的循环里,每次都改变串长,循环就停不下来了,后果很严重。
for(i=s_len-1;i>=index-1;i--)//这个循环是把每个字符往后挪temp_len个位置,从后面开始挪
{
s.ch[i+temp_len]=s.ch[i];
}
//上面的循环结束后,我们就从index的位置,挪出来temp_len个位置。接下来把要插入的串挨个放进去,就大功告成了。
for(i=0;i<temp_len;i++)
{
s.ch[i+index-1]=temp.ch[i];
s.length++;//这个很重要!!!!!
}
return s;//这里返回一个结构体类型,所以函数定义的返回类型也应试Mystring
//因为我们传不是引用型变量,所以,主函数调用,返回时,字符串s不变。想变就传引用型变量
}
第一插入的操作讲的比较详细,下面我讲的不会那么细了,基本操作都一样,就是,挪,往后挪就是插入,往前就是删除。
下面讲删除操作
Mystring string_delete(Mystring s,int start,int num)
{//要删除的字符串,起始位置,删除的个数
int i,s_len=s.length,j=0;
if(start+num>s_len)//从起始位置没有num个字符,即不够删的就全删
//例如 ABCDEFG,从第五个删除5
个,就是ABCD
s.length=s_len-(s_len-start);
else
{
for(i=start-1;i<s_len&&j<num;j++,i++)
{
s.ch[i]=s.ch[i+num];//从起始位置,要删除的元素,都被后面对应删除后的元素覆盖了,就是删除
s.length--;//很重要!!!!!
}
for(;i<s_len-num;i++)
s.ch[i]=s.ch[i+num];
}
return s;
}
替换操作:就是从起始位置,一个串替换原本这个串的元素。区别一下插入
例如:ABCDEF 插入 ZX 从2 得到 AZXBCDEF
而替换得到的就是AZXDEF
Mystring string_replace(Mystring s,Mystring s1,int start)
{
int i,j=0;
//这里,没有改变字符串长度,我们可以直接用s.lenght,来控制循环。
for(i=start-1;i<s.length&&j<s1.length;i++,j++)
//如果替换的开始位置靠后,不能,完全替换,我们的设计是不改变母串的长度,有多少替换多少
s.ch[i]=s1.ch[j];
return s;
}
**提取操作:**例ABCDEF 从 2 提取3个元素得BCD
这个返回值和参数类型稍微不一样,我们传一个布尔类型的,当成结果串。返回类型为void
void string_sub(Mystring s,Mystring &result,int start,int len)
{
int i,j=0;
result.length=0;
for(i=start-1;i<start+len&&j<len;j++,i++)//如果切片的长度超过字符串的长度,让他全切下来
{
result.ch[j]=s.ch[i];
result.length++;//!!!!!!!!!!!
}
}
最后一个个操作有很简单,连接两个字符串
写的是,第二个参数接到第一个参数的后面。
Mystring string_connect(Mystring s,Mystring s1)
{
int i,j=0;
int s_len=s.length,s1_len=s1.length;
for(i=s_len;i<s_len+s1_len&&s_len+j<maxn;j++,i++)
{
s.ch[i]=s1.ch[j];
s.length++;
}
return s;
}
以上我们写完了,顺序串的几个重要操作,有些不足的地方是,我们没有去判断,参数的合法性,比如,插入时,起始位置是负数,或者超过当前的串的长度,中都是不合法的。所以当我们在主函数调用之前,可以写if else分支,先去判断一下。还有一种不合法,字符串连接之后超最大长度maxn,因为顺序从是固定长度。
下面延时在主函数如何调用这些函数(没有加非法判断)
int main()
{
int length,index;
Mystring s,s1,s2,s3;
Mystring &temp=s;
Mystring &temp1=s1;
//输入
create_Mystring(temp);
create_Mystring(temp1);
print_Mystring(s);
//插入
cin>>index;
s2=string_insert(s,index,s1);
print_Mystring(s2);
//删除
int start,del_len;
cin>>start>>del_len;
s2=string_delete(s,start,del_len);
print_Mystring(s2);
//替换
cin>>start;
s2=string_replace(s,s1,start);
print_Mystring(s2);
//提取
cin>>start>>sub_len;
string_sub(s,temp2,start,sub_len);
print_Mystring(s3);
//连接
Mystring s4;
s4=string_connect(s,s2);
print_Mystring(s4);
}