链串的基本操作

链串,就是用链表存储字符串,一些基本操作和顺序串一样,但是写法不同,单链表类似。
存储结构部分:

#include<iostream>
#include<stdio.h>
#define maxn 100
using namespace std;
typedef struct Lnode
{
    char data;//链串的数据域是char类型的
    struct Lnode *next;//next域是结构体 Lnode,递归定义
}Lnode,*Linkstring;//起两个其他名字的,一个是Lnode普通结构体类型,另一个是指针类型的。

先讲输入,这个输入就是链表的尾插法创建。输入以#结尾的字符串,来创建串。

void CreateList(Linkstring &L)//这里要传引用型的参数
{
    char temp;
    Lnode *r,*p;//定义两个结点指针
    L=(Linkstring)malloc(sizeof(Lnode));
    L->next=NULL;//这两行相当于给串的头结点开辟空间,初始化。
    r=L;//这个一定要有。我们每次移动的相当于头结点地址的副本。
    //这样我们就能保留头结点地址,因此才能保证找到串。
    cin>>temp;//输入第一个字符,这里的逻辑和顺序串一样。
    while(temp!='#')
    {
        p=(Linkstring)malloc(sizeof(Lnode));
        p->data=temp;//一定要写这两句话,开辟新节点。
        			//新节点存放新元素
        r->next=p;//新结点插入到尾部
        r=p;	  //尾指针指向新节点,指到最后
        cin>>temp;//再次输入
    }
    r->next=NULL;//加上这句话好知道链表的结束标志,输出时能用到。
}

这个输入就相当于插入的特殊情况,搞清楚while里面的几句话就明白链串的核心操作了。想插入新元素的时候,一定要先new 新结点,这是重重之中。

再讲一下输出,输出比较简单。

void print_Mystring(Linkstring L)//不需要引用型变量
{
    Lnode *p;
    p=L->next;//p指向头结点的下一个结点,即首元结点
    while(p)//当p非空指针时
    {
        cout<<p->data;//输出数据域
        p=p->next;//向后移动
    }
    cout<<endl;//输出换行
}

获取长度,和输出差不多,就是遍历,只不过是吧=把输出换成计数,i++,然后return

int string_leng(Linkstring s)
{
    int i=0;
    Lnode *p;
    p=s->next;
    while(p!=NULL)
    {
        i++;
        p=p->next;
    }
    return i;
}

插入算是几个操作中最难的了,这里设计的几个操作都是不改变传入的,母串,生成新的子串。所以我们用结构体指针 返回类型的函数。

Linkstring string_insert(Linkstring s,int index,Linkstring temp)//被插入的串,开始插入的位置,插入的串。
{
    int i=1,j=0;
    int temp_len=string_leng(temp),s_len=string_leng(s);//获取长度
    Lnode *p,*q,*result,*re,*tmp;//定义许多临时指针结点,并开辟空间。
    p=(Linkstring)malloc(sizeof(Lnode));
    q=(Linkstring)malloc(sizeof(Lnode));
    result=(Linkstring)malloc(sizeof(Lnode));//存放结果,需要return 的结点。
    re=(Linkstring)malloc(sizeof(Lnode));
    p=s->next;//母串首元结点的副本
    q=temp->next;//同上
    re=result;//同上
    while(i<index)//当小于开始位置时,把母串结点一次赋给结果结点。都是通过副本进行操作。
    {
        tmp=(Linkstring)malloc(sizeof(Lnode));//这个temp,叫临时结点,和输入操作的p结点一样,new一个新节点。新结点存数据,然后接到单链表的后面
        tmp->data=p->data;//赋值
        re->next=tmp;//接到结果结点副本后面
        re=tmp;//re往后移动,总是代表位结点。
        p=p->next;//母串也向后移
        i++;//计数
    }
    while(j<temp_len)//同样的道理,从start以后,把插入的串,拼到结果串的后面。
    {
        tmp=(Linkstring)malloc(sizeof(Lnode));
        tmp->data=q->data;
        re->next=tmp;
        re=tmp;
        q=q->next;
        j++;
    }//拼完插入串,我们接着拼母串,这就相当于在母串中间插入一个其他的串,从而生成新串。
    while(i<=s_len)
    {
        tmp=(Linkstring)malloc(sizeof(Lnode));
        tmp->data=p->data;
        re->next=tmp;
        re=tmp;
        p=p->next;
        i++;
    }
    re->next=NULL;//尾结点的next指向NULL
    return result;//返回result
}

搞懂了插入串之后,其他和他类似,创建副本,对副本进行操作,然后return。

删除操作和插入类似,相同的语句完全可以复制上面的,稍微改一下即可。不然每次都打这么多,效率比较低

Linkstring string_delete(Linkstring s, int start,int num)
{
    int i=1,j=0;
    int s_len=string_leng(s);
    Lnode *result,*re,*p,*tmp;
    result=(Linkstring)malloc(sizeof(Lnode));
    re=(Linkstring)malloc(sizeof(Lnode));
    p=(Linkstring)malloc(sizeof(Lnode));
    p=s->next;
    re=result;
    while(i<start)//这部分和插入第一部分一样
    {
        tmp=(Linkstring)malloc(sizeof(Lnode));
        tmp->data=p->data;
        re->next=tmp;
        re=tmp;
        p=p->next;
        i++;
    }
    if(start+num>s_len)//从起始位置没有num个字符,即不够删的就全删
    {
        re->next=NULL;
        return result;
    }
    else
    {
        while(i<start+num)//这步就相当于删除,我们把往后移num,但是没有赋值给result的副本
        {
            i++;
            p=p->next;
        }
        while(i<=s_len)//这和插入的第三部分一样
        {
            tmp=(Linkstring)malloc(sizeof(Lnode));
            tmp->data=p->data;
            re->next=tmp;
            re=tmp;
            p=p->next;
            i++;
        }
        re->next=NULL;
        return result;
    }
}

这样看来,是不是插入和删除非常像啊。其他几个操作也类似。

替换也类似。

Linkstring string_replace(Linkstring s,Linkstring s1,int start)//开始位置,和替换的字符串
{
    int i=1,j=0;
    int s_len=string_leng(s),s1_len=string_leng(s1);
    Lnode *result,*re,*p,*tmp,*q;
    result=(Linkstring)malloc(sizeof(Lnode));
    re=(Linkstring)malloc(sizeof(Lnode));
    p=(Linkstring)malloc(sizeof(Lnode));
    q=(Linkstring)malloc(sizeof(Lnode));
    p=s->next;
    q=s1->next;
    re=result;
    while(i<start)//和插入第一部分一样
    {
        tmp=(Linkstring)malloc(sizeof(Lnode));
        tmp->data=p->data;
        re->next=tmp;
        re=tmp;
        p=p->next;
        i++;
    }
   
    while(i<=s_len&j<s1_len)//设计是是不改变原来字符串的长度去替换 
    //啥意思呢,比如:ABCDEF 从第5的个位置替换成 XYZ 得 ABCDXY
    {
        tmp=(Linkstring)malloc(sizeof(Lnode));
        tmp->data=q->data;
        re->next=tmp;
        re=tmp;
        q=q->next;
        p=p->next;//s也要向前走!!!!!!!!,母串也向前走
        i++;j++;
    }
    while(i<=s_len)//和插入第三部分一样
    {
        tmp=(Linkstring)malloc(sizeof(Lnode));
        tmp->data=p->data;
        re->next=tmp;
        re=tmp;
        p=p->next;
        i++;
    }
    re->next=NULL;
    return result;
}

到这是不是和插入操作都差不多啊,下面就剩下两个操作了。

先看提取

Linkstring string_sub(Linkstring s,int start,int sub_len)
{
    int i=1,j=0;
    int s_len=string_leng(s);
    Lnode *result,*re,*p,*tmp;
    result=(Linkstring)malloc(sizeof(Lnode));
    re=(Linkstring)malloc(sizeof(Lnode));
    p=(Linkstring)malloc(sizeof(Lnode));
    p=s->next;
    re=result;
    while(i<start)//这个稍微不太一样,我们一直往后移,移动的开始位置,而不赋值
    {
        p=p->next;
        i++;
    }
    while(i<=s_len&&j<sub_len)//这个和插入第二部分是不是一样。我们加了一个i<=s_len条件,就是想不够提取的时候停止提取,例如:ABCDEF 从第五个提取4个得 EF
    {
        tmp=(Linkstring)malloc(sizeof(Lnode));
        tmp->data=p->data;
        re->next=tmp;
        re=tmp;
        p=p->next;
        i++;j++;
    }
    re->next=NULL;
    return result;
}

剩下一个连接也很简单。可以看成插入到最后位置。所以就少了,插入操作的第三while部分。

Linkstring string_connect(Linkstring s,Linkstring s2)
{
    int i=0,j=0;
    int s2_len=string_leng(s2),s_len=string_leng(s);
    Lnode *p,*q,*result,*re,*tmp;
    p=(Linkstring)malloc(sizeof(Lnode));
    q=(Linkstring)malloc(sizeof(Lnode));
    result=(Linkstring)malloc(sizeof(Lnode));
    re=(Linkstring)malloc(sizeof(Lnode));
    p=s->next;
    q=s2->next;
    re=result;
    while(i<s_len)//把第一个串一直赋值给结果串
    {
        tmp=(Linkstring)malloc(sizeof(Lnode));
        tmp->data=p->data;
        re->next=tmp;
        re=tmp;
        p=p->next;
        i++;
    }
    while(j<s2_len)//把第二串一直赋值给结果串
    {
        tmp=(Linkstring)malloc(sizeof(Lnode));
        tmp->data=q->data;
        re->next=tmp;
        re=tmp;
        q=q->next;
        j++;
    }
    re->next=NULL;
    return result;
}

这样就写完了几个重要操作,起始都是大同小异,无非就是,遍历找起始位置,然后赋值。理解一个了,其他自然理解。
下面简单写一下主函数如何调用的。

int main()
{
    int length,index;
    //定义
    Linkstring s,s1,s2,s3,s4;
    Linkstring &temp=s;
    Linkstring &temp1=s1;
    //创建,输出
    CreateList_R(temp);
    CreateList_R(temp1);
    print_Mystring(s);
    //串长
    length=string_leng(s);
    cout<<"s的串长为:"<<length<<endl;
    //插入
    cin>>index;
    s2=string_insert(s,index,s1);
   //删除
    int start,del_len;
    cin>>start>>del_len;
    s2=string_delete(s,start,del_len);
    //替换 
    cin>>start;
    s2=string_replace(s,s1,start);
    //提取
    int sub_len;
    cin>>start>>sub_len;
    s3=string_sub(s,start,sub_len);
     //连接
    s4=string_connect(s,s2);
    print_Mystring(s4);
    return 0;
}
    
  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值