数据结构(C语言)——第四章、串(1)串的顺序存储


说明:串的顺序存储操作,分为静态数组和动态数组两类。两者的操作差别不大,注意看动态数组前面的补充内容。

静态数组

//
// @Author: Brisa
// @Date: 2021/9/4
// @Description: 串的顺序存储
//               静态数组实现(定长顺序存储)
//               舍弃数组0号位,从1开始存取等操作
//
#include<stdio.h>
#include<string.h>

#define MAXLEN 255  //预定义最大串长为255
typedef struct{
    char ch[MAXLEN];  //每个分两存储一个字符
    int length;  //串的实际长度
}SString;

/*函数声明*/
void StrAssign(SString &S, char chars[]);  //1.赋值操作,把串S,赋值为chars
void StrCopy(SString &S, SString T);       //2.复制操作,由串T复制得到S
bool StrEmpty(SString S);                  //3.判空操作,若S为空串返回true,否则返回false
int StrLength(SString S);                  //4.求串长,返回串S的个数
void ClearString(SString &S);              //5.清空操作,将S清为空串
//bool DestroyString(SString &S);          //6.销毁串,将串S销毁(回收存储空间)
void Concat(SString &S, SString T1, SString T2);            //7.串连接,用S返回由T1和T2连接而成的新串
bool SubString(SString &Sub, SString S, int pos, int len);  //8.求子串,用Sub返回串S中的第pos个字符起长度为len的子串
int StrCompare(SString S, SString T);      //9.比较操作,若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
int Index(SString S, SString T);           //10.定位操作,若主串S中存在与串T相同的子串,则返回它在子串中第一次出现的位置,否则函数值为0
void InitString(SString &S);               //11.初始化串
void PrintString(SString S);               //12.遍历串


/*基本操作的实现*/
//1.赋值操作,把串S,赋值为chars
void StrAssign(SString &S, char chars[]){
    S.ch[0] = '#';  //0号位舍弃不用
    for(int i=1; i<MAXLEN && i<=strlen(chars); i++) {
        S.ch[i] = chars[i-1];
        S.length++;
    }
    /*
     int i = 0;
     while(chars[i]){
        T.ch[++T.length] = chars[i];
        i++;
    }
     */
}

//2.复制操作,由串T复制得到S
void StrCopy(SString &S, SString T){
    for(int i=1; i<=T.length; i++){
        S.ch[i] = T.ch[i];
    }
    S.length = T.length;
}

//3.判空操作,若S为空串返回true,否则返回false
bool StrEmpty(SString S){
    return S.length == 0;
}

//4.求串长,返回串S的个数
int StrLength(SString S){
    return S.length;
}

//5.清空操作,将S清为空串[逻辑上清空]
void ClearString(SString &S){
    S.length = 0;
}
//6.销毁串,将串S销毁(回收存储空间)
//bool DestroyString(SString &S){}  静态数组,未使用时自动回收空间

//7.串连接,用S返回由T1和T2连接而成的新串
void Concat(SString &S, SString T1, SString T2){
    S.length = 0;
    for(int i=1; i<MAXLEN && i<= T1.length+T2.length; i++){
        if(i <= T1.length){
            S.ch[i] = T1.ch[i];
        } else{
            S.ch[i] = T2.ch[i-T1.length];
        }
        S.length++;

        /*先将S1赋值给T,等价于 StrCopy(T, S1);*/
        /*for (int i = 1; i <= S1.length; i++)
            T.ch[i] = S1.ch[i];
        for (int i = 1; i <= S2.length; i++)
            T.ch[i + S1.length] = S2.ch[i];
        T.length = S1.length + S2.length;
        */
    }
}

//8.求子串,用Sub返回串S中的第pos个字符起长度为len的子串
bool SubString(SString &Sub, SString S, int pos, int len){
    if((pos + len-1) > S.length)//判断子串范围是否越界
        return false;
    for (int i=pos; i <= pos+len-1; i++){
        Sub.ch[i-pos+1] = S.ch[i];
    }
    Sub.length = len;
    return true;
}

//9.比较操作,若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
int StrCompare(SString S, SString T){
    for(int i=1; i<=S.length && i<=T.length; i++){
        if(S.ch[i] != T.ch[i])
            return S.ch[i] - T.ch[i];
    }
    //前面的都相等,就比较串长
    return S.length - T.length;
}

//10.定位操作,若主串S中存在与串T相同的子串,则返回它在子串中第一次出现的位置,否则函数值为0
int Index(SString S, SString T){
    int i=1, n=S.length, m=T.length;
    SString Sub; //用于暂存子串
    while(i < n-m+1){
        SubString(Sub, S, i, m);
        /*相当于从S的开头找遍 长度为m 的子串,再与T进行比较*/
        if(StrCompare(Sub, T) != 0) {
            i++;
        } else
            return i; //若相等则返回T在S中的位置
    }
    return 0; //S中不存在与T相等的子串
}

//11.初始化串
void InitString(SString &S){
    S.length = 0;
}

//12.遍历串
void PrintString(SString S){
    int i=1;
    while (i<=S.length)
        printf("%c ", S.ch[i++]);
    printf("\n");
}


int main(){
    //1.定义一个静态定长串
    SString S1;

    //2.初始化该串
    InitString(S1);

    //3.赋值操作
    printf("***开始赋值操作***\n");
    char chars[] = "hello,world";
    StrAssign(S1, chars);
    PrintString(S1);

    //4.复制操作
    printf("***开始复制操作***\n");
    SString S2;
    StrCopy(S2, S1);
    PrintString(S2);

    //5.连接操作
    printf("***开始连接操作***\n");
    SString S3;
    Concat(S3, S1, S2);
    PrintString(S3);

    //6.求子串操作
    printf("***开始求子串操作***\n");
    SString Sub;
    int pos = 3, len = 4;
    if(SubString(Sub, S1, pos, len)){
        printf("所得子串为:");
        PrintString(Sub);
    } else {
        printf("子串范围越界\n");
    }
    //7.比较操作
    printf("***开始比较操作***\n");
    if(StrCompare(S1,S2) == 0){
        printf("S1 = S2\n");
    } else if(StrCompare(S1,S2) > 0){
        printf("S1 > S2\n");
    } else{
        printf("S1 < S2\n");
    }

    //8.定位操作
    printf("***开始定位操作***\n");
    if(Index(S1,Sub) != 0){
        printf("子串Sub在S1中的位置为:%d\n", Index(S1,Sub));
    } else{
        printf("子串Sub不在S1中\n");
    }

    //9.一些其他函数的实现
    printf("S1的长度为:%d\n",StrLength(S1));
    ClearString(S1);
    printf("S1的长度为:%d\n",StrLength(S1));

    return 0;
}


动态数组

//
// @Author: Brisa
// @Date: 2021/9/4
// @Description: 串的顺序存储
//               动态数组实现(堆分配存储)
//               补充:相较于静态数组申请方式,1)只是在销毁串方面有差异,
//                                        2)再就是增加了一个扩大串长的函数,
//                                        3)以及声明了串后,都需要先InitString 初始化一下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAXLEN 255   //预定义最大串长为255

typedef struct{
    char *ch;  //按串长分配存储区,ch指向串的基地址
    int length;  //串的实际长度
}HString;

/*函数声明*/
void StrAssign(HString &S, char chars[]);  //1.赋值操作,把串S,赋值为chars
void StrCopy(HString &S, HString T);       //2.复制操作,由串T复制得到S
bool StrEmpty(HString S);                  //3.判空操作,若S为空串返回true,否则返回false
int StrLength(HString S);                  //4.求串长,返回串S的个数
void ClearString(HString &S);              //5.清空操作,将S清为空串
void DestroyString(HString &S);            //6.销毁串,将串S销毁(回收存储空间)
void Concat(HString &S, HString T1, HString T2);            //7.串连接,用S返回由T1和T2连接而成的新串
bool SubString(HString &Sub, HString S, int pos, int len);  //8.求子串,用Sub返回串S中的第pos个字符起长度为len的子串
int StrCompare(HString S, HString T);      //9.比较操作,若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
int Index(HString S, HString T);           //10.定位操作,若主串S中存在与串T相同的子串,则返回它在子串中第一次出现的位置,否则函数值为0
void InitString(HString &S);               //11.初始化串
void PrintString(HString S);               //12.遍历串
void IncreaseSize(HString& S, int len);    //13.增加串长

/*函数实现*/
//1.赋值操作,把串S,赋值为chars
void StrAssign(HString &S, char chars[]){
    int i = 0;
    while (chars[i])
    {
        S.ch[++S.length] = chars[i];
        i++;
    }
}

//2.复制操作,由串T复制得到S
void StrCopy(HString &S, HString T){
    for(int i=1; i<=T.length; i++){
        S.ch[i] = T.ch[i];
    }
    S.length = T.length;
}

//3.判空操作,若S为空串返回true,否则返回false
bool StrEmpty(HString S){
    return S.length == 0;
}

//4.求串长,返回串S的个数
int StrLength(HString S){
    return S.length;
}

//5.清空操作,将S清为空串(逻辑上清空)
void ClearString(HString &S){
    S.length = 0;
}

//6.销毁串,将串S销毁(回收存储空间)
void DestroyString(HString &S){
    free(S.ch);  //清除掉S.ch
    S.ch = NULL;
}

//7.串连接,用S返回由T1和T2连接而成的新串
void Concat(HString &S, HString T1, HString T2){
    /*先将S1赋值给S2,等价于 StrCopy(T, S1);*/
    for (int i = 1; i <= T1.length; i++)
        S.ch[i] = T1.ch[i];

    for (int i = 1; i <= T2.length; i++)
        S.ch[i + T1.length] = T2.ch[i];
    S.length = T1.length + T2.length;
}


//8.求子串,用Sub返回串S中的第pos个字符起长度为len的子串
bool SubString(HString &Sub, HString S, int pos, int len){
    if((pos + len-1) > S.length)//判断子串范围是否越界
        return false;
    for (int i=pos; i <= pos+len-1; i++){
        Sub.ch[i-pos+1] = S.ch[i];
    }
    Sub.length = len;
    return true;
}

//9.比较操作,若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
int StrCompare(HString S, HString T){
    for(int i=1; i<=S.length && i<=T.length; i++){
        if(S.ch[i] != T.ch[i])
            return S.ch[i] - T.ch[i];
    }
    //前面的都相等,就比较串长
    return S.length - T.length;
}

//10.定位操作,若主串S中存在与串T相同的子串,则返回它在子串中第一次出现的位置,否则函数值为0
int Index(HString S, HString T){
    int i=1, n=S.length, m=T.length;
    HString Sub; //用于暂存子串
    InitString(Sub);
    while(i < n-m+1){
        SubString(Sub, S, i, m);
        /*相当于从S的开头找遍 长度为m 的子串,再与T进行比较*/
        if(StrCompare(Sub, T) != 0) {
            i++;
        } else
            return i; //若相等则返回T在S中的位置
    }
    return 0; //S中不存在与T相等的子串
}

//11.初始化串
void InitString(HString &S){
    S.ch = (char *)malloc(sizeof(char) * MAXLEN);
    S.length = 0;
}

//12.遍历串
void PrintString(HString S){
    for (int i = 1; i <= S.length; i++)
        printf("%c ", S.ch[i]);
    printf("\n");
}

//13.增加动态数组的长度
void IncreaseSize(HString& S, int len){
    char *p= S.ch;
    S.ch = (char *)malloc(sizeof(char) * (MAXLEN + len));
    for(int i=1; i<= S.length; i++){  //将数据复制到新区域(时间开销大)
        S.ch[i] = p[i];
    }
    S.length += len;  //串长增加len
    free(p); // 释放掉原来的内存空间
}


int main(){
    //1.声明一个动态串
    HString S1;

    //2.初始化一个串
    InitString(S1);

    //3.赋值操作
    printf("***开始赋值操作***\n");
    char chars[] = "hello,world";
    StrAssign(S1, chars);
    PrintString(S1);

    //4.复制操作
    printf("***开始复制操作***\n");
    HString S2;
    InitString(S2);
    StrCopy(S2, S1);
    PrintString(S2);

    //5.连接操作
    printf("***开始连接操作***\n");
    HString S3;
    InitString(S3);
    Concat(S3, S1, S2);
    PrintString(S3);

    //6.求子串操作
    printf("***开始求子串操作***\n");
    HString Sub;
    InitString(Sub);
    int pos = 3, len = 4;
    if(SubString(Sub, S1, pos, len)){
        printf("所得子串为:");
        PrintString(Sub);
    } else {
        printf("子串范围越界\n");
    }
    //7.比较操作
    printf("***开始比较操作***\n");
    if(StrCompare(S1,S2) == 0){
        printf("S1 = S2\n");
    } else if(StrCompare(S1,S2) > 0){
        printf("S1 > S2\n");
    } else{
        printf("S1 < S2\n");
    }

    //8.定位操作
    printf("***开始定位操作***\n");
    if(Index(S1,Sub) != 0){
        printf("子串Sub在S1中的位置为:%d\n", Index(S1,Sub));
    } else{
        printf("子串Sub不在S1中\n");
    }

    //9.一些其他函数的实现
    printf("S1的长度为:%d\n",StrLength(S1));
    ClearString(S1);
    printf("S1的长度为:%d\n",StrLength(S1));

    return 0;
}

参考来源:
数据结构代码参考博客
《王道数据结构》

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值