串的数据结构表-----顺序串与链式串

串的结构类似与线性表,只不过串的数据元素是一个字符,即是由零个或多个字符组成的有限序列。

一、串的顺序存储

串的顺序存储结构也就是顺序存储,即串中的字符被一次的存在一组连续的存储单元中,可以类比线性表的顺序存储,可以写出其数据结构如下:

typedef struct st
{
    char *ch;       //串存放的起始地址,串中第i个字符存储在ch[i-1]中
    int length;     //串的长度
    int strsize;    //分配的存储空间的大小,如果不足,在通过realloc()分配增加空间
}string;

假设现在的字符串是“friend”,其结构可以用如图所示:

现在我们拿到这个数据结构第一步就是要初始化一个串,即首先在内存中开辟一段连续的存储空间(大小可以假先预定MAXSIZE个存储空间),初始化其长度length为0,同时制定其串的最大容量是MAXSIZE,如下:

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

初始化完成后,我们可以类比顺序表,对串完成一系列操作,如串拷贝、取子串、串赋值等,

程序示例如下:

#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
 
typedef struct st
{
    char *ch;       //串存放的起始地址,串中第i个字符存储在ch[i-1]中
    int length;     //串的长度
    int strsize;    //分配的存储空间的大小,如果不足,在通过realloc()分配增加空间
}string;
 
//串的初始化操作
string CreateNullString()
{
    string s;
    s.length=0;
    s.ch=(char*)malloc(MAXSIZE *sizeof(char));
    s.strsize=MAXSIZE;
    return s;
}
 
//判断空串
int isEmpty(string s)
{
    if(s.length==0)
        return 1;
    else
        return 0;
}
 
//赋值操作
void StringAssign(string *s1,char s2[])
{
    int i=0;
    while(s2[i]!='\0')  // '\0' 是字符串的结束符,任何字符串之后都会自动加上'\0'
        i++;            //计算s2的长度
    if(i>s1->strsize)
    {
        //所赋值的字符数组超过字符串的默认容量,则增加存储空间
        s1->ch=(char*)malloc(i*sizeof(char));
        s1->strsize=i;
    }
    s1->length=i;
    for(i=0;i<s1->length;i++)
        s1->ch[i]=s2[i]; //从第一个字符开始逐个字符赋值
}
 
//串拷贝操作
void StringCopy(string *s1,string s2)
{
    if(s1->strsize<s2.length)
    {
        s1->ch=(char*)realloc(s1->ch,s2.length*sizeof(char));
        s1->strsize=s2.length;
    }
    s1->length=s2.length;
    int i;
    for(i=0;i<s1->length;i++)
        s1->ch[i]=s2.ch[i];
}
 
//求串的长度
int StringLength(string s)
{
    return s.length;
}
 
//串的连接操作
void concat(string *s,string s1,string s2)
{
    if(s->strsize<s1.length+s2.length)
    {
        s->ch=(char*)realloc(s->ch,(s1.length+s2.length)*sizeof(char));
        s->strsize=s1.length+s2.length;
    }
    s->length=s1.length+s2.length;       //两串连接
    int i;
    for(i=0;i<s1.length;i++)         //将s1复制到s中
        s->ch[i]=s1.ch[i];
    for(;i<s->length;i++)
        s->ch[i]=s2.ch[i-s1.length]; //将s2复制到s中去
}
 
//取子串操作
int substr(string s,int i,int len,string *t)
{
    /*
        i表示从字符串s的第i个位置开始截取(索引从1开始)
        len表示截取字符串的长度
    */
    if(i<=0 || i>s.length  || len<0 || len>s.length-i+1)    //参数不合法
        return 0;
    if(t->length<len) //存储空间不够,继续分配存储空间
    {
        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;
}
 
//插入操作
int insertString(string *s,int i,string t)
{
    //在字符串s的第i个位置插入字符串t
    if(i<=0 || i>s->length+1)
        return 0;
    if(s->strsize<s->length+t.length)  //空间不足
    {
        s->ch=(char*)realloc(s->ch,(s->length+t.length)*sizeof(char));
        s->strsize=s->length+t.length;
    }
    int k;
    for(k=s->length-1;k>=i-1;k--) //将s中的后i个字符后移到后面
        s->ch[k+t.length]=s->ch[k];
    s->length=s->length+t.length;
    for(k=0;k<t.length;k++)              //将t的值赋值给s
        s->ch[k+i-1]=t.ch[k];
    return 1;
}
 
//删除操作
int deleteString(string *s,int i,int len)
{
    //从s的第i个字符开始删除len个字符
    if(i<=0 || i>s->length  || len<0 || len>s->length-i+1)    //参数不合法
        return 0;
    int k;
    for(k=i+len-1;k<s->length;k++)    //从s的i+len-1个位置开始将其后的所有字符前移
        s->ch[k-len]=s->ch[k];
    s->length-=len;
    return 1;
}
 
//输出操作
void print(string s)
{
    int i;
    for(i=0;i<s.length;i++)
        printf("%c",s.ch[i]);
    printf("\n");
}
 
void main()
{
    string s1=CreateNullString();
    string s2=CreateNullString();
    string s3=CreateNullString();
    char ch[MAXSIZE];
    printf("请输入主串:\n");
    gets(ch);
    StringAssign(&s1,ch);
    printf("主串 s1 为:");
    print(s1);
    StringCopy(&s2,s1);
    printf("拷贝串操作结果如下,结果如下 s2 :");
    print(s2);
    printf("删除操作(1——s1.length-3 全删):");
    deleteString(&s2,1,s1.length-3);
    print(s2);
    printf("插入操作,插入到s2的第2个位置上,请输入插入的字符串:");
    gets(ch);
    StringAssign(&s3,ch);
    insertString(&s2,2,s3);
    print(s2);
    printf("取子串操作(取s1的子串【2-4】):");
    substr(s1,2,3,&s3);
    print(s3);
    printf("串连接操作【将s1与s3合并】:");
    concat(&s1,s1,s2);
    print(s1);
}

结果如下:


 

二、串的链式存储

串的链式存储结构称为串的链式存储,即串中的每一个节点包括两个部分:数据域和指针域,其中数据域用来存放字符,指针域用来存放指向下一个节点的指针。

由此可得串的链式数据结构如下:

typedef struct node
{
    char ch;            //字符域
    struct node *next;  //指针域,存放下一个结点的地址
}node,*linkstr;

如图所示:

其初始化操作,主要是开辟头结点,同时,让它的下一个指针指向为NULL:

//初始化操作
linkstr CreateNullString()
{  
    linkstr s;
    s=(linkstr)malloc(sizeof(node));
    if(s!=NULL)
        s->next=NULL;
    return s;
}

由此,完整的案例如下:

#include<stdio.h>
#include<stdlib.h>
 
//链式串
 
typedef struct node
{
    char ch;            //字符域
    struct node *next;  //指针域,存放下一个结点的地址
}node,*linkstr;
 
 
//初始化操作
linkstr CreateNullString()
{  
    linkstr s;
    s=(linkstr)malloc(sizeof(node));
    if(s!=NULL)
        s->next=NULL;
    return s;
}
 
//判断空串
int iEmpty(linkstr s)
{
    if(s->next==NULL)
        return 1;
    else
        return 0;
}
 
//赋值操作
void Stringassign(linkstr s,char t[])
{
    linkstr p,q,r;
    r=s;        //r始终表示的是尾结点(最后一个非空节点,而不是最后一个NULL节点)。
    q=s->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;
        }
}
 
//串拷贝操作
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;
        }
        //若串s原先的空间不够用
        else
        {
            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;
}
 
//求串的长度
int length(linkstr s)
{
    linkstr p;
    int n=0;
    p=s->next;
    while(p!=NULL)
    {
        n++;
        p=p->next;
    }
    return n;
}
 
//串的连接操作
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)
        {
            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;   
     
}
 
//截取子串
int substr(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;
}
 
 
//插入操作
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;
}
 
//删除操作
int deleteString(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;
 
}
 
//打印输出
void print(linkstr s)
{
     linkstr p=s->next;
     while(p!=NULL)
     {
        printf("%c",p->ch);
        p=p->next;
     }
     printf("\n");
}
 
void main()
{
    linkstr s1;
    linkstr s2;
    linkstr s3;
    s1=CreateNullString();
    s2=CreateNullString();
    s3=CreateNullString();
    char str[100];
    printf("请输入字符串:\n");
    gets(str);
    Stringassign(s1,str);
    printf("串s1:");
    print(s1);
    printf("串s1的长度为:%d\n",length(s1));
    assign(s2,s1);
    printf("串s2:");
    print(s2);
    printf("串s2删除操作(第三个位置的三个字符删除 :");
    deleteString(s2,3,3);
    print(s2);
    printf("串连接操作(s3=s1+s2 ):");
    contact(s3,s1,s2);
    print(s3);
    printf("插入操作(从s1的第6个位置插入s3):");
    insert(s1,6,s3);
    print(s1);
    printf("测试截取子串的功能s2(截取s3的第四个位置长度为4的字符串:");
    substr(s3,4,4,s2);
    print(s2);
    printf("测试字Contact的清除过多存储空间的功能:(将两个较短的字符[两个s2]合并写到s1上去:");
    contact(s1,s2,s2);
    print(s1);
}   

结果如图:

 

 

 

 

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值