数据结构之串的基本操作

1.串的实现相比较而言简单一些,但个人觉得有一些需要注意的地方,以下一 一列举:

(1)串基本术语:

空串:空串指长度为0的串,其不包含任何字符;

空格串:不同于空串,它是由一个或多个空格构成的串。虽然是空格,但在计算长度时要把空格的个数算在内;

串比较:串的大小比较时以字符的ASCII码值作为依据。

(2)串基本操作:赋值操作、连接操作、求串长、窜的比较和求子串。

(3)串的存储结构:顺序存储和链式存储。其中链式存储可以指定节点大小,存储若干个字符。

2.串的模式匹配算法:求解子串在主串中首次出现的位置:Index(S,T,pos)

算法的实现使具有暴力的性质,模式串和主串同时从第一个位置开始进行判断,若对应位置字符相等则继续向后判断,若不相

等,则模式串回到串首,主串字符位置指针回退,重新匹配。

int Index(String s,String t,int pos){
    //返回子串t在主串s中第pos个字符之后的位置,若不存在,则返回0
    if(isEmpty(t) || pos<0 || pos>t.length-1) exit(0);
    int i=pos;
    int j=0;
    while(i<=s.length && j<=t.length){
        if(s.ch[i] == t.ch[j]){
            ++i;
            ++j;   //继续比较后续的字符
        }
        else{
            i=i-j+1;j=0;//指针回退,重新开始匹配
        }
    }
    if(j>t.length) {
        return i-t.length;
    }
    else
        return 0;

}

串的模式匹配算法优化:KMP算法

此算法可以在O(m+n)的数量级上完成串的匹配操作。其改进在于,每一趟匹配过程中出现字符比较不相等的时候,不需要回

退指针i,而是利用已经匹配到的部分结果将模式串向右滑动尽可能远的距离,继续匹配。

#include<iostream>
#include<cstdlib>
using namespace std;
#define MAXSTRLEN 100

typedef char SString[MAXSTRLEN+1];


//返回模式串T在主串中第pos位置之后的位置,若存在,返回1,否则返回0

int KMPindex(SString S,SString T,int pos){
    if(pos < 1 || pos>S[0]) exit(0);
    int i=pos;
    int j=1;
    int next[MAXSTRLEN];
    GetNext(T,next);
    while(i <= S[0] && j<= T[0]){
        if(S[i] == T[j]){
            i++;j++;
        }else{
            j=next[j];
        }
    }
    if(j >T[0]) return i-T[0];
    return 0;
}

//求子串next[i]的值
void GetNext(SString T,int next[]){
    int j=1,k=0;
    next[1]=0;
    while(j<T[0]){
        if(k==0 || T[j]==T[k]){ //子串自己与机子进行比较
            ++j;
            ++k;
            next[j]=k;
        }else{
            k = next[k];
        }
    }

}
int main()
{
    SString S = {13,'a','b','a','b','c','a','b','c','a','c','b','a','b'};  
    SString T = {5,'a','b','c','a','c'};  
    int pos;  
    pos = KMPindex( S,  T, 1);  
    cout<<"匹配位置为:"<<pos;
    return 0;
}

 

3.顺序串与链式串的实现(C语言)

(1)顺序串:

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define MAXSIZE 100
//串的顺序存储
typedef struct st{
    char *ch;//串存放的起始地址
    int length;//串的长度
    int strsize;//分配的存储空间的大小
}String;

//1.串的初始化操作
String CreateNullString(){
    String str;
    str.length = 0;
    str.ch = (char *)malloc(MAXSIZE*sizeof(char));
    str.strsize = MAXSIZE;
    return str;
}

//2.判断空串
int isEmpty(String str){
    if(str.length == 0){
        return 1;
    }else{
        return 0;
    }
}

//3.串的赋值操作
void StrAssign(String *str1,char str2[]){
    int i=0;
    while(str2[i] != '\0') i++;//计算str2的长度
    if(str1->length < i){   //结构指针成员的访问
        //增加存储空间,将较长的空间赋值为新的值
        str1->ch = (char *)malloc(sizeof(char));
        str1->strsize = i;
    }
    
    str1->length = i;
    for(i=0;i<str1->length;i++){
        str1->ch[i] = str2[i];//从第一个字符开始,着个赋值
        
    }
}
//4.串的拷贝
void StrCopy(String *str1,String str2){
    if(str1->strsize < str2.strsize){
        str1->ch = (char *)realloc(str1->ch,str2.length*sizeof(char));
        str1->strsize = str2.length;;
    }
    
    str1->length = str2.length;
    int i;
    for(i=0;i<str1->length;i++){
        str1->ch[i] = str2.ch[i];
    }
}

//5.串的长度
int StrLength(String str){
    return str.length;
}

//6.串的连接操作
void StrConcat(String *str,String str1,String str2){
    if(str->strsize < str1.strsize + str2.strsize){
        str->ch = (char *)realloc(str->ch,(str1.length+str2.length)*sizeof(char));
        str->strsize = str1.length+str2.length;
    }
    
    str->length = str1.length+str2.length;
    
    int i;
    for(i=0;i<str1.length;i++){
        str->ch[i] = str1.ch[i];
    }//将str1赋值到str
    for(;i<str->length;i++){
        str->ch[i] = str2.ch[i-str1.length];
    }//将str2赋值到str
}

//7.取子串
int SubStr(String s,int i,int len,String *t){
    /*
        i表示从字符串s的第i个位置开始截取(索引从1开始)
        len表示截取字符串的长度
    */
    
    //将s中从i位置起,len长度的串通过t返回
    if(i<=0 || i>s.length || len<0 || len>s.length-i+1){
        t->ch = (char *)realloc(t->ch,len*sizeof(char));
        t->strsize = len;
    }
    t->length = len;
    int k;
    for(k=0;k<t->length;k++){
        t->ch[k] = s.ch[i-1+k];
    }
    return 1;
}

//8.插入操作
int InsertString(String *str,int i,String str1){
    //将str1,插入str的第i个位置
    if(i <= 0 || i>str->length+1) return 0;
    
    if(str->strsize < str->length + str1.length){
        //空间不足
        str->ch = (char *)realloc(str->ch,(str->length+str1.length)*sizeof(char));
        str->strsize = str->length + str1.length;
    }
    int k;
    for(k=str->length-1;k>=i-1;k--){
        //将str中的后i个字符后移
        str->ch[k+str1.length] = str->ch[k];
    }
    str->length = str->length + str1.length;
    for(k=0;k<str1.length;k++){
        str->ch[k+i-1] = str1.ch[k];
    }
    
    return 1;
    
}
//9.删除子串
int deleteStr(String *str,int i,int len){
    //从第i个位置开始,删除len长度的子串
    if(i<=0 || i>str->length || len <0 || len > str->length-i+1){
        return 0;
    }
    int k;
    for(k=i+len-1;k<str->length;k++){
        //从str的i+len-1个位置开始将其后的所有字前移
        str->ch[k-len] = str->ch[k];
    }
    str->length -= len;
    return 1;
}

//10.输出操作
void print(String *str){
    int i;
    for(i=0;i<str->length;i++){
        cout<<str->ch[i]<<" ";
    }
    cout<<endl;
}

//11.串的模式匹配
int Index(String s,String t,int pos){
    //返回子串t在主串s中第pos个字符之后的位置,若不存在,则返回0
    if(isEmpty(t) || pos<0 || pos>t.length-1) exit(0);
    int i=pos;
    int j=0;
    while(i<=s.length && j<=t.length){
        if(s.ch[i] == t.ch[j]){
            ++i;
            ++j;   //继续比较后续的字符
        }
        else{
            i=i-j+1;j=0;//指针回退,重新开始匹配
        }
    }
    if(j>t.length) {
        return i-t.length;
    }
    else
        return 0;
}
int main()
{
    String str1 = CreateNullString();
    String str2 = CreateNullString();
    String str3 = CreateNullString();
    char ch[MAXSIZE];
    cout<<"请输入主串"<<endl;
    gets(ch);
    StrAssign(&str1,ch);
    cout<<"主串为:";
    print(&str1);
    cout<<endl;
    StrCopy(&str2,str1);
    cout<<"拷贝得到的串为:";
    print(&str2);
    cout<<endl;
    
    SubStr(str1,4,4,&str3);
    cout<<"截取的子串为:";
    print(&str3);
    cout<<endl;
    
    int pos = Index(str1,str2,0);
    cout<<"匹配位置为:"<<pos<<endl;
    return 0;

}


(2)链式串:

#include<iostream>
#include<cstdlib>
using namespace std;
//串的链式存储
typedef struct node{
    char ch;   //字符域
    struct node *next; //指针域,存放下一个节点的指针
}node,*Linkstr;
//1.初始化一个空串
Linkstr CreateNullString()
{
    Linkstr str;
    str=(Linkstr)malloc(sizeof(node));
    if(str != NULL){
        str->next = NULL;
    }
    return str;
}

//2.判断空串
int IsEmpty(Linkstr str)
{
    if(str->next ==NULL){
        return 1;
    }
    else{
        return 0;
    }
}

//3.赋值操作
void StringAssign(Linkstr str,char t[])
{
    Linkstr p,q,r;
    r=str;//r始终表示的尾节点(最后一个非空节点,而不是最后一个NULL节点)。
    q=str->next;
    int i;
    for(i=0;t[i] != '\0';i++){
        if(q!=NULL)
        {
            q->ch = t[i]; //一个一个的存入节点
            r=q;
            q=q->next;    
        }
        else{
            //(初始化时只给头结点分配了存储空间或者其他情况),如果需要继续添加数据(其他节点没分配空间)需要继续分配
            p=(Linkstr)malloc(sizeof(node));
            //添加节点
            p->ch = t[i];
            r->next = p;
            r = p;
        }
        r->next = NULL;
        //将s中多余的空间释放掉
        while(q!=NULL){
            p=p->next;
            free(q);
            q=p;
        }
    }
 }
 
//2.串的拷贝
void Assign(Linkstr s,Linkstr t)
{
    将t串的值赋值给s串
    Linkstr p,q,r,u;
    p=t->next;
    q=s->next;
    r=s;
    while(p!=NULL){
        //串s已经分配了空间
        if(q!=NULL){
            q->ch = p->ch;
            r=q;
            q=q->next;
        }
        else{
            //串s中原先的空间不够
            u=(Linkstr)malloc(sizeof(node));
            u->ch = p->ch;
            r->next =u;
            r=u;
        }
        //p节点后移
        p=p->next;
        //同理,若q的长度过长,可以释放多余的空间
        while(q!= NULL){
            p=p->next;
            free(q);
            q=p;
        }
        r->next = NULL;
    }
}

//3.求串长
int length(Linkstr s)
{
    Linkstr p;
    int len=0;
    p=s->next;
    while(p!=NULL){
        len++;
        p=p->next;
    }
    return len;
}
//4.串的链接操作
void contact(Linkstr s,Linkstr s1,Linkstr s2)
{
    Linkstr p,q,r,t;
    r=s;
    p=s1->next;
    q=s->next;
    while(p!=NULL){
        if(q!=NULL)  //s不是空串
        {
            q->ch = p->ch;
            q=q->next;
            r=q;
        }
        else{
            //串s原来没有分配存储空间,需要申请空间
            t=(Linkstr)malloc(sizeof(node));
            t->ch=p->ch;
            r->next=t;
            r=t;
        }
        p=p->next;
    }
    p=s2->next;
    while(p!=NULL){
        if(q!=NULL){
            q->ch=p->ch;
            q=q->next;
            r=q;
        }else{
            //串s原来没有分配存储空间,需要申请空间
            t=(Linkstr)malloc(sizeof(node));
            t->ch=p->ch;
            r->next=t;
            r=t;
        }
        p=p->next;
    }
    
    //将串s的多余的空间清除掉(这个情况只可能发生在while的if循环中)
    while(q!=NULL){
        p=q->next;
        free(q);
        q=p;
    }
    r->next = NULL;
}  
//5.截取子串
int subString(Linkstr s,int i,int len,Linkstr t)
{
    Linkstr p,q,r,u;
    if(i<=0||i>length(s) || i+len-1>length(s))
        return 0;
    //指针指向s的第i-1个位置
    int j,k;
    for(j=0,p=s;j<i;j++){
        p=p->next;
    }
    for(k=0,r=t,q=t->next;k<len;k++)
    {
        if(q!=NULL){
            q->ch=p->ch;
            r=q;
            q=q->next;
        }
        else{
            u=(Linkstr)malloc(sizeof(node));
            u->ch=p->ch;
            r->next=u;
            r=u;
        }
        p=p->next;
    }
    
    while(q!=NULL){
        p=q->next;
        free(q);
        q=p;
    }
    r->next=NULL;
    return 1;
}
//6.插入子串操作
int insert(Linkstr s,int i,Linkstr t)
{
    Linkstr p,q,r;
    if(i<=0 || i>length(s)+1)
    return 0;
    //指向i-1个位置
    int j;
    for(j=0,p=s;j<i-1;j++){
        p=p->next;
    }
    q=t->next;
    while(q!=NULL)
    {
        r=(Linkstr)malloc(sizeof(node));
        r->ch = q->ch;
        r->next=p->next;
        p->next=r;
        q=q->next;
        p=r;
    }
    return 1;
}
//7.删除操作
int deleteStr(Linkstr s,int i,int len){
    Linkstr p,q,r;
    if(i<=0 || i>length(s) || i+len-1>length(s))
    return 0;
    int j;
    for(j=0,p=s;j<i-1;j++){
        p=p->next;
    }
    for(j=0;j<len;j++){
        q=p->next;
        p->next=q->next;
        free(q);
    }
    return 1;
}
//8.打印输出
void print(Linkstr s)
{
    Linkstr p=s->next;
    while(p!=NULL)
    {
        cout<<p->ch<<" ";
        p=p->next;
    }
    cout<<endl;
 }
int main()
{
    Linkstr s1;
    Linkstr s2;
    Linkstr s3;
    s1=CreateNullString();
    s2=CreateNullString();
    s3=CreateNullString();
    char str[100];
    cout<<"请输入字符:"<<endl;
    gets(str);
    StringAssign(s1,str);
    cout<<"串1:";
    print(s1);
    cout<<endl;
    cout<<"串1的长度为:"<<length(s1)<<endl;
    
    Assign(s2,s1);
    cout<<"串2:";
    print(s2);
    cout<<endl;
    cout<<"串2的长度为:"<<length(s2)<<endl;
    
    cout<<"串s2的删除操作:"<<endl;
    deleteStr(s2,3,3);
    cout<<"串2:";
    print(s2);
    cout<<endl;
    cout<<"串2的长度为:"<<length(s2)<<endl;
    contact(s3,s1,s2);
    cout<<"串3为(串1和串2的连接):";
    
    print(s3);
    return 0;
}


  • 29
    点赞
  • 242
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值