紫薇星上的数据结构(5)

我们在前面几个部分讲了线性表、栈和队列,这些都是线性结构,今天我们再来整理一下 串,串也是线性结构。


5.1串的定义

串就是一个或多个字符组成的有限序列,我们又将串称为字符串,例如:S = 'a1a2a3a4...an',在这个例子中串由n个字符组成,S就是串名,而后面的'a1a2a3a4...an'就是串值,而n就是串长,当n为0的时候就成为空串。

关于串有几点需要注意:

  • 我们举个例子:a = 'BEI JING',可以将这个串a称为主串,那么有 b = 'BEI'和 c = 'JING'这两个串就被称为a的子串,而 d = 'BEIJING'因为串中少了空格所以不是子串;
  • 我们一般在讨论链表时讨论的都是下标,但是在串中我们要讨论位置,下标为0时位置为1;
  • 两个串如果相等,那么每一个字符相互比较都是相等的;
  • 还有一种串叫空格串:e = ' ',这个串中只有一个字符,就是空格。

通过上面的说明我们可以发现:串其实也就是一个线性表,不过这个表中存储的都是字符,所以在串的序列中,各个字符也都是前驱与后继的。

5.2串的比较

我们来比较一下两个串是否相等:domain1 = 'www.baidu.com',domain2 = 'www.csdn.com',很明显的这两个字符串不相等,因为其中的字符不是每个都相同;那么我们就会有疑问,字符串之间可以比较大小吗?其实串的比较,比较的是串中字符的字符编码,字符编码就是字符在对应字符集中的序号。

什么是字符集呢?我们随便输入一个字符,在输入法中可以看到很多的字符,这些字符的集合就叫字符集,在计算机中最常用的字符集就是ASCII编码,刚开始ASCII编码是由7位二进制来表示的,但7位二进制最大值为128,随着时间的发展符号越来越多就不够用了,随意进行了扩展,扩展到8位二进制,256位就可以了。

ASCII编码对于英文够用了但是对中文就有些困难了,更何况还有满文、朝鲜文这些字符,由于我们说过每一个字符都是一个编码,所以在ASCII的基础上引入了Unicode编码,Unicode编码的特点是使用16位来表示一个字符,8位为一个字节,16位就是两个字节,所以就是使用两个字节来表示一个字符;这样做的好处就是可以表示2的16次方个字符,这么多个字符差不多就可以表示所有语言的所有字符了。

为了让ASCII编码和Unicode编码相兼容,所以Unicode编码的前256个与ASCII编码是一致的,所以Unicode编码也可以表示英文字符。所以一会我们只考虑英文字符,先不考虑中文字符。

接下来我们回到这两个串上:domain1 = 'www.baidu.com',domain2 = 'www.csdn.com',这两个字符串如何比较:

  • 首先比较长度 n :如果domain1 的长度 n1 比domain2的长度 n2 大并且domain2的一部分包含在domain1中(顺序与内容全部相同),那么就可以说domain1 > domain2;
  • 但是例子中并没有这种包含关系,应该怎么比较呢?这时我们就从第一个位置开始找,一直找到第K个位置,这里的K肯定是小于 n1,n2的,就像在domain1与domain2中我们可以看到 www. 之前的字符都是一样的,从第5个字符开始就不一样了所以K = 5,让后我们只要比较第K个字符的大小就可以了,在例子中domain1中的第K个字符是 b,domain2中的第K个字符是 c,由于 c > b,所以domain1 < domain2。

5.3串的顺序储存结构

其实这些操作在C中可以调用标准库函数#include <string.h>来实现,在这个库中有许多针对字符串的处理操作方法,例如:strcmp(char s1, char s2)就表示串的比较;strcpy(char to, char from)就表示串的复制;strlen(char s)就表示求串长;还有很多操作都可以在<string.h>中找到方法。

只不过数据结构就是来实现这些操作,而C将它们打包之后我们就可以直接拿来用,所以数据结构是更底层的东西,我们可以使用数据结构将这些方法都实现一遍。

串的数据抽象类型

ADT String
Data
    D = { ai | ai ∈ CharacterS et, i = 1,2, ... ,n, n > 0}
Operation
    StrAssign(&T,chars)        //串赋值
    StrCompare(S,T)            //串比较
    StrLength(S)               //求串长
    Concat(&T,s1,s2)           //串连接
    SubString(&Sub,S,pos,len)  //求子串
    StrCopy(&T,S)              //串拷贝
    StrEmpty(S)                //串判空
    ClearString(&S)            //清空串
    Index(S,T,pos)             //子串的位置
    Replace(&S,T,V)            //串替换
    StrInsert(&S,pos,T)        //子串插入
    StrDelete(&S,pos,len)      //子串删除
    DestroyString(&S)          //串销毁
endADT

串赋值、串比较、求串长、串连接、求子串这五种基本操作构成串类型的最小操作子集。

串的顺序存储结构

之前说过串其实也就是一个线性表,不过这个表中存储的都是字符,可以看到结构应该是这样的:

很多语言在表示字符串的时候都默认使用字符数组来表示,比如C语言,因为数组就是一个顺序存储结构;不管字符串有多长,在字符串的最后会加一个‘\0’,表示空字符,这样我们不管是计算长度还是遍历字符数组只需要在‘\0’前面去操作就可以了。

所以串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的;数组中的长度是一定的,所以有一个最大长度MAX_SIZE,串的长度与‘\0’与空闲空间的长度总和就是MAX_SIZE,同时要注意‘\0’作为表示串的终结,计算串值长度时不计。

5.4串的操作

关于字符串的操作可以在一些语言中直接使用库函数来实现,但是在数据结构中都是要手动实现,因为我们用C来写代码,所以依然使用代码来实现一下,同时要注意在所有的测试中都使用英文字符,不要轻易使用中文字符,因为中文字符由两个字节组成,代码中还没有考虑这种情况。

首先我们建立StatusLib.h文件,这个文件用来实现相关的状态码以及宏函数的定义:

#ifndef STATUSLIB_H_INCLUDED
#define STATUSLIB_H_INCLUDED

#include <stdio.h>
#include <stdlib.h>

/**状态码*/
#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
#define EQ 0 //相等
#define GT 1 //大于
#define LF -1 //小于

#ifndef _STATUS_H_ //如果系统中已经有了下列状态码的定义,就不再定义
    #define OVERFLOW -2 //堆栈上溢,超过所能表示的最大正数
    #define UNDERFLOW -3 //堆栈下溢,超过所能表示的最小负数
#endif // _STATUS_H_

typedef int Status; //自定义一个状态码识别类型

#endif // STATUSLIB_H_INCLUDED

然后建立一个SeqString.h的文件,在这个文件中实现字符串的顺序存储结构的实现:

#ifndef SEQSTRING_H_INCLUDED
#define SEQSTRING_H_INCLUDED

#include "StatusLib.h"
#include <string.h>

/**这种方式比较容易实现,但缺点非常明显
#define MAX_SIZE 1024
typedef struct{
    char ch[MAX_SIZE + 1]; //定长实现字符串的顺序结构,缺点:浪费空间/
    int length;
}SString;
*/

/**串的堆式顺序存储结构*/
typedef struct{
    char *ch; //如果是非空串,就按照指定长度分配内存空间,否则ch就指向NULL
    int length; //串的当前长度
}HString;

//初始化堆字符串
void InitString_HeapString(HString *str);

//为串str赋值,值为字符串常量chars
Status StrAssign_HeapString(HString *str, char *chars);

//打印字符串
void PrintHeapString(HString *str);

#endif // SEQSTRING_H_INCLUDED

之所以使用指针实现顺序存储结构,是因为指针可以自由地分配空间,我们在需要的时候可以随时分配,使用过后也可以随时free(),这样就不会造成空间资源的浪费。

然后就是熟悉的SeqString.c文件,来进行我们已经定义好的操作:

#include "SeqString.h"

//初始化堆字符串
void InitString_HeapString(HString *str){
    str->ch = NULL;
    str->length = 0;
}

//为串str赋值,值为字符串常量chars
Status StrAssign_HeapString(HString *str, char *chars){
    int len = strlen(chars);
    if(!len){ //如果赋值的字符串为空
            return ERROR; //返回错误码
    }
    //赋值的字符串不为空
    InitString_HeapString(str); //初始化堆字符
    str->ch = (char*)malloc(len * sizeof(char)); //分配空间
    if(!str->ch){ //分配失败
        exit(OVERFLOW); //内存溢出
    }
    //如果分配空间成功
    for(int i = 0; i < len; i++){ //使用for循环赋值
        str->ch[i] = chars[i];
    }
    str->length = len;
    return OK;
}

//打印字符串
void PrintHeapString(HString *str){
    if(str->length == 0 || !str->ch){
        printf("堆字符串为空!\n");
        return;
    }
    for(int i = 0; i < str->length; i++){
        printf("%c",str->ch[i]);
    }
}

我们在main.c中实现一下,看一下是否能够成功:

#include <stdio.h>
#include <stdlib.h>
#include "SeqString.h"

void TestSeqString();

int main(){
    //printf("Hello world!\n");
    TestSeqString();
    return 0;
}

void TestSeqString(){
    HString str;
    StrAssign_HeapString(&str, "abcdefg");
    PrintHeapString(&str);
}

可以看到编译通过,运行结果如下:

abcdefg
Process returned 0 (0x0)   execution time : 0.045 s
Press any key to continue.

这里有几个点说一下, HString str; 这条语句我们在之前的栈中一般是写为HString *str = (HString*)malloc(HString); ,这样也可以进行内存分配,不过是堆内存分配,而在StrAssign_HeapString方法中进行的是栈内存分配,分配完会销毁,所以如果这样写了在最后面就要记得加上一句 free(str); ,同时记得去掉&str前面的&,不然就会报错

这里我们仍然使用 HString str; 的赋值方式,对另一种赋值方式感兴趣的同学可以自己试一下。

串的复制

先在中SeqString.h添加操作:

//将串srcStr的内容复制到串destStr中
Status StrCopy_HeapString(HString *destStr, HString *srcStr);

//判断字符串是否为空
Status IsEmpty_HeapString(HString *str);

然后在SeqString.c中添加操作:

//将串srcStr的内容复制到串destStr中
Status StrCopy_HeapString(HString *destStr, HString *srcStr){
    InitString_HeapString(destStr);
    if(IsEmpty_HeapString(srcStr)){
        printf("要复制的字符串不能为空!\n");
        return ERROR;
    }
    destStr->ch = (char*)malloc(sizeof(char));
    if(!destStr->ch){
        exit(OVERFLOW);
    }
    for(int i = 0; i < srcStr->length; i++){
        destStr->ch[i] = srcStr->ch[i];
    }
    destStr->length = srcStr->length;
    return OK;
}

//判断字符串是否为空
Status IsEmpty_HeapString(HString *str){
    if(str->length == 0 || !str->ch){
        return TRUE;
    }
    return FALSE;
}

再复制的时候我们首先判断被复制的字符串是否为空,然后我们就为其分配空间并使用for循环赋值,在main.c中实现一下:

#include <stdio.h>
#include <stdlib.h>
#include "SeqString.h"

void TestSeqString();

int main(){
    //printf("Hello world!\n");
    TestSeqString();
    return 0;
}

void TestSeqString(){
    HString str1, str2;
    StrAssign_HeapString(&str1, "abcdefg");
    PrintHeapString(&str1);
    StrCopy_HeapString(&str2, &str1);
    printf("\n赋值后的str2:\n");
    PrintHeapString(&str2);
}

编译通过,运行结果如下:

abcdefg
赋值后的str2:
abcdefg
Process returned 0 (0x0)   execution time : 0.021 s
Press any key to continue.

串的比较

接下来我们来看一下字符串的比较,刚才已经说过如何比较了,现在我们在SeqString.h添加操作:

//比较字符串的大小
Status StrCompare_HeapString(HString *str1, HString *str2);

然后在SeqString.c中添加操作:

//比较字符串的大小
Status StrCompare_HeapString(HString *str1, HString *str2){
    for(int i; i < str1->length && i < str2->length; i++){
        //遇到不同的字符就直接比较ASCII码
        if(str1->ch[i] != str2->ch[i]){
            /*因为str1 == str2, return EQ 0;
            str1 > str2, return GT 1;str1 < str2, return LF -1;
            这就相当于等于返回零,大于返回正,小于返回负*/
            return  str1->ch[i] - str2->ch[i];
        }
    }
    //如果字符串都相等,比较长度
    return str1->length - str2->length;
}

这里的比较思路写在注释中了,大家可以看一下非常有趣,然后在main.c中实现一下:

void TestSeqString(){
    HString str1, str2, str3;
    StrAssign_HeapString(&str1, "abcdefg");
    PrintHeapString(&str1);
    StrCopy_HeapString(&str2, &str1);
    printf("\n赋值后的str2:\n");
    PrintHeapString(&str2);
    StrAssign_HeapString(&str3, "abcdefghijklmn");
    printf("\n比较str1与str2:%d\n", StrCompare_HeapString(&str1, &str2));
    printf("比较str1与str3:%d\n", StrCompare_HeapString(&str1, &str3));
}

我们可以看到编译通过,运行结果如下:

abcdefg
赋值后的str2:
abcdefg
比较str1与str2:0
比较str1与str3:-7

Process returned 0 (0x0)   execution time : 0.020 s
Press any key to continue.

这里由于之前的思路所以直接放回了数值,我们还可以添加一些细节让结果变得更加美观,这里就不多说了。

串的连接

现在我们在SeqString.h添加操作:

//字符串的连接
Status Concat_HeapString(HString *destStr, HString *str1, HString *str2)

然后在SeqString.c中添加操作:

//字符串的连接
Status Concat_HeapString(HString *destStr, HString *str1, HString *str2){
    InitString_HeapString(destStr);
    destStr->length = str1->length + str2->length;
    destStr->ch = (char*)malloc(sizeof(char) * destStr->length);
    if(!destStr->ch){
        exit(OVERFLOW);
    }
    //复制第一个字符串
    for(int i = 0; i < str1->length; i++){
        destStr->ch[i] = str1->ch[i];
    }
    //赋值第二个串
    for(int i = 0; i < str2->length; i++){
        destStr->ch[str1->length + i] = str2->ch[i];
    }
    return OK;
}

这里只需要注意一下给第三个字符串初始化的时候长度应该是第一个和第二个字符串的总和,以及在将第一个字符串的内容连接到第三个字符串之后,连接第二个字符串应该从第一个字符串的长度处开始。我们在main.c中实现一下:

void TestSeqString(){
    HString str1, str2, str3, str4;
    StrAssign_HeapString(&str1, "abcdefg");
    PrintHeapString(&str1);
    StrCopy_HeapString(&str2, &str1);
    printf("\n赋值后的str2:\n");
    PrintHeapString(&str2);
    StrAssign_HeapString(&str3, "abcdefghijklmn");
    printf("\n比较str1与str2:%d\n", StrCompare_HeapString(&str1, &str2));
    printf("比较str1与str3:%d\n", StrCompare_HeapString(&str1, &str3));
    printf("将str1与str3连接起来:\n");
    Concat_HeapString(&str4, &str1, &str3);
    PrintHeapString(&str4);
}

编译通过,运行结果如下:

abcdefg
赋值后的str2:
abcdefg
比较str1与str2:0
比较str1与str3:-7
将str1与str3连接起来:
abcdefgabcdefghijklmn
Process returned 0 (0x0)   execution time : 0.027 s
Press any key to continue.

串的截取

我们在SeqString.h添加操作:

//截取子字符串,从pos处截取len长度的str放入destStr返回
Status SubString(HString *destStr, HString *str, int pos, int len);

然后在SeqString.c中添加操作:

//截取子字符串,从pos处截取len长度的str放入destStr返回
Status SubString(HString *destStr, HString *str, int pos, int len){
    InitString_HeapString(destStr);
    if(IsEmpty_HeapString(str)){
        printf("要截取的字符串不能为空!\n");
        return ERROR;
    }
    if(pos < 1 || pos > str->length || len < 0 || pos + len - 1 > str->length){
        return ERROR;
    }
    destStr->ch = (char*)malloc(sizeof(char));
    if(!destStr->ch){
            exit(OVERFLOW);
    }
    for(int i = 0; i < len; i++){
        destStr->ch[i] = str->ch[pos - 1 + i];
    }
    destStr->length = len;
    return OK;
}

截取非常简单,就是通过for循环赋值,只不过赋值的对象长度由值的长度确定。我们在main.c中实现一下:

void TestSeqString(){
    HString str1, str2, str3, str4, str5;
    StrAssign_HeapString(&str1, "abcdefg");
    PrintHeapString(&str1);
    StrCopy_HeapString(&str2, &str1);
    printf("\n赋值后的str2:\n");
    PrintHeapString(&str2);
    StrAssign_HeapString(&str3, "abcdefghijklmn");
    printf("\n比较str1与str2:%d\n", StrCompare_HeapString(&str1, &str2));
    printf("比较str1与str3:%d\n", StrCompare_HeapString(&str1, &str3));
    printf("将str1与str3连接起来:\n");
    Concat_HeapString(&str4, &str1, &str3);
    PrintHeapString(&str4);
    printf("\n截取str4中的子字符串str1:\n");
    SubString(&str5, &str4, 1, str1.length);
    PrintHeapString(&str5);
}

这里将str4中的子字符串str1截取出来放在str5中,编译通过,运行结果如下:

abcdefg
赋值后的str2:
abcdefg
比较str1与str2:0
比较str1与str3:-7
将str1与str3连接起来:
abcdefgabcdefghijklmn
截取str4中的子字符串str1:
abcdefg
Process returned 0 (0x0)   execution time : 0.034 s
Press any key to continue.

子串的查找

我们在SeqString.h添加操作:

//返回子字符串childString在父字符串parentString的位置,从父字符串pos处开始寻找
int Index_HeapString(HString *parentString, HString *childString, int pos);

然后在SeqString.c中添加操作:

//返回子字符串childString在父字符串parentString的位置,从父字符串pos处开始寻找
int Index_HeapString(HString *parentString, HString *childString, int pos){
    if(pos < 0){//pos为0就表示没有寻找的地方
        return FALSE; //因为位置是从1开始的
    }
    HString *subStr = (HString*)malloc(sizeof(HString));
    InitString_HeapString(subStr);
    //int i = pos; //将起始位置记录下来
    while(pos + childString->length - 1 <= parentString->length){
        //截取子串
        SubString_HeapString(subStr, &parentString, pos, childString->length);
        if(StrCompare_HeapString(subStr, &childString) != EQ){
            pos++;
        }else{
            return pos + 1;
        }
    }
    free(subStr); //一定要记得free
    return LF;
}

查找的时候思路是这样的:

  • 不管从哪开始,截取要查找子串长度的字符串;
  • 然后与要查找子串进行比较;
  • 相同返回位置,不同位置+1重新截取。

这样做有个好处就是我们可以不用自己去想从哪开始,用户会输入,但是也有不好的一点就是,如果要查找的子串位置在开始查找的位置之前,那么就查找不到。在main.c中实现一下:

void TestSeqString(){
    HString str1, str2, str3, str4, str5;
    StrAssign_HeapString(&str1, "abcdefg");
    PrintHeapString(&str1);
    StrCopy_HeapString(&str2, &str1);
    printf("\n赋值后的str2:\n");
    PrintHeapString(&str2);
    StrAssign_HeapString(&str3, "abcdefghijklmn");
    printf("\n比较str1与str2:%d\n", StrCompare_HeapString(&str1, &str2));
    printf("比较str1与str3:%d\n", StrCompare_HeapString(&str1, &str3));
    printf("将str1与str3连接起来:\n");
    Concat_HeapString(&str4, &str1, &str3);
    PrintHeapString(&str4);
    printf("\n截取str4中的子字符串str1:\n");
    SubString_HeapString(&str5, &str4, 1, str1.length);
    PrintHeapString(&str5);
    printf("\n寻找str4中的子字符串str1的位置:%d\n", Index_HeapString(&str4, &str1, 2));
}

编译通过,运行结果如下:

abcdefg
赋值后的str2:
abcdefg
比较str1与str2:0
比较str1与str3:-7
将str1与str3连接起来:
abcdefgabcdefghijklmn
截取str4中的子字符串str1:
abcdefg
寻找str4中的子字符串str1的位置:8

Process returned 0 (0x0)   execution time : 0.030 s
Press any key to continue.

这里查找到7的原因是str4的内容为abcdefgabcdefghijklmn,其中str1的内容abcdefg出现了两次,分别在位置1和位置8处,如果想要下标,就将 return pos + 1; 变为 return pos;

串的删除

我们在SeqString.h添加操作:

//从pos处删除长度len
Status StrDelete_HeapString(HString *str, int pos, int len);

然后在SeqString.c中添加操作:

//从pos处删除长度len
Status StrDelete_HeapString(HString *str, int pos, int len){
    if(IsEmpty_HeapString(str)){
        printf("要删除的字符串不能为空!\n");
        return ERROR;
    }
    if(pos < 1 || pos + len - 1 > str->length || len < 0){
        return ERROR;
    }
    for(int i = pos - 1; i + len < str->length; i++){
        str->ch[i] = str->ch[i + len];
    }
    str->length -= len;
    str->ch = (char*)realloc(str->ch, str->length * sizeof(char));
    return OK;
}

这里注意删的是位置,要从1开始,在main.c中实现一下:

void TestSeqString(){
    HString str1, str2, str3, str4, str5;
    StrAssign_HeapString(&str1, "abcdefg");
    PrintHeapString(&str1);
    StrCopy_HeapString(&str2, &str1);
    printf("\n赋值后的str2:\n");
    PrintHeapString(&str2);
    StrAssign_HeapString(&str3, "abcdefghijklmn");
    printf("\n比较str1与str2:%d\n", StrCompare_HeapString(&str1, &str2));
    printf("比较str1与str3:%d\n", StrCompare_HeapString(&str1, &str3));
    printf("将str1与str3连接起来:\n");
    Concat_HeapString(&str4, &str1, &str3);
    PrintHeapString(&str4);
    printf("\n截取str4中的子字符串str1:\n");
    SubString_HeapString(&str5, &str4, 1, str1.length);
    PrintHeapString(&str5);
    printf("\n寻找str4中的子字符串str1的位置:%d\n", Index_HeapString(&str4, &str1, 2));
    printf("删除str3中的str1:\n");
    StrDelete_HeapString(&str3, 1, str1.length);
    PrintHeapString(&str3);
}

编译通过,运行结果如下:

abcdefg
赋值后的str2:
abcdefg
比较str1与str2:0
比较str1与str3:-7
将str1与str3连接起来:
abcdefgabcdefghijklmn
截取str4中的子字符串str1:
abcdefg
寻找str4中的子字符串str1的位置:8
删除str3中的str1:
hijklmn
Process returned 0 (0x0)   execution time : 0.034 s
Press any key to continue.

串的插入

我们在SeqString.h添加操作:

//在pos位置插入串insertStr
Status StrInsert_HeapString(HString *str, int pos, HString *insertStr);

然后在SeqString.c中添加操作:

//在pos位置插入串insertStr
Status StrInsert_HeapString(HString *str, int pos, HString *insertStr){
    if(pos < 1 || pos > str->length + 1){
        return ERROR;
    }
    if(IsEmpty_HeapString(str)){
        return ERROR;
    }
    str->ch = (char*)realloc(str->ch, (str->length + insertStr->length) * sizeof(char));
    if(!str->ch){
        exit(OVERFLOW);
    }
    for(int i = str->length - 1; i >= pos - 1; i--){ //为插入腾位置
        str->ch[i + insertStr->length] = str->ch[i];
    }
    //插入每个字符
    for(int i = 0; i < insertStr->length; i++){
        str->ch[pos - 1 + i] = insertStr->ch[i];
    }
    str->length += insertStr->length;
    return OK;
}

插入主要是先为插入字符串腾出位置,所以要将被插入字符串中的字符移动,在main.c中实现一下:

void TestSeqString(){
    HString str1, str2, str3, str4, str5;
    StrAssign_HeapString(&str1, "abcdefg");
    PrintHeapString(&str1);
    StrCopy_HeapString(&str2, &str1);
    printf("\n赋值后的str2:\n");
    PrintHeapString(&str2);
    StrAssign_HeapString(&str3, "abcdefghijklmn");
    printf("\n比较str1与str2:%d\n", StrCompare_HeapString(&str1, &str2));
    printf("比较str1与str3:%d\n", StrCompare_HeapString(&str1, &str3));
    printf("将str1与str3连接起来:\n");
    Concat_HeapString(&str4, &str1, &str3);
    PrintHeapString(&str4);
    printf("\n截取str4中的子字符串str1:\n");
    SubString_HeapString(&str5, &str4, 1, str1.length);
    PrintHeapString(&str5);
    printf("\n寻找str4中的子字符串str1的位置:%d\n", Index_HeapString(&str4, &str1, 2));
    printf("删除str3中的str1:\n");
    StrDelete_HeapString(&str3, 1, str1.length);
    PrintHeapString(&str3);
    printf("\n再把str1插入回来:\n");
    StrInsert_HeapString(&str3, 1, &str1);
    PrintHeapString(&str3);
}

编译通过,运行结果如下:

abcdefg
赋值后的str2:
abcdefg
比较str1与str2:0
比较str1与str3:-7
将str1与str3连接起来:
abcdefgabcdefghijklmn
截取str4中的子字符串str1:
abcdefg
寻找str4中的子字符串str1的位置:8
删除str3中的str1:
hijklmn
再把str1插入回来:
abcdefghijklmn
Process returned 0 (0x0)   execution time : 0.035 s
Press any key to continue.

串的替换

我们在SeqString.h添加操作:

//将串str中的oldStr替换为newStr
Status Replace_HeapString(HString *str, HString *oldStr, HString *newStr);

然后在SeqString.c中添加操作:

//将串str中的oldStr替换为newStr
Status Replace_HeapString(HString *str, HString *oldStr, HString *newStr){
    if(IsEmpty_HeapString(str)){
        return ERROR;
    }
    int pos = Index_HeapString(str, oldStr, 0);
    while(pos != -1){
        StrDelete_HeapString(str, pos, oldStr->length);
        StrInsert_HeapString(str, pos, newStr);
        pos += newStr->length;
        pos = Index_HeapString(str, oldStr, pos - 1);
    }
    return OK;
}

串的替换主要是使用查找、删除、插入这三种方法实现的。在main.c中实现一下:

void TestSeqString(){
    HString str1, str2, str3, str4, str5, str6;
    StrAssign_HeapString(&str1, "abcdefg");
    StrAssign_HeapString(&str6, "aaaaaaa");
    PrintHeapString(&str1);
    StrCopy_HeapString(&str2, &str1);
    printf("\n赋值后的str2:\n");
    PrintHeapString(&str2);
    StrAssign_HeapString(&str3, "abcdefghijklmn");
    printf("\n比较str1与str2:%d\n", StrCompare_HeapString(&str1, &str2));
    printf("比较str1与str3:%d\n", StrCompare_HeapString(&str1, &str3));
    printf("将str1与str3连接起来:\n");
    Concat_HeapString(&str4, &str1, &str3);
    PrintHeapString(&str4);
    printf("\n截取str4中的子字符串str1:\n");
    SubString_HeapString(&str5, &str4, 1, str1.length);
    PrintHeapString(&str5);
    printf("\n寻找str4中的子字符串str1的位置:%d\n", Index_HeapString(&str4, &str1, 2));
    printf("删除str3中的str1:\n");
    StrDelete_HeapString(&str3, 1, str1.length);
    PrintHeapString(&str3);
    printf("\n再把str1插入回来:\n");
    StrInsert_HeapString(&str3, 1, &str1);
    PrintHeapString(&str3);
    printf("\n把str4中的str1替换为str6:\n");
    Replace_HeapString(&str4, &str1, &str6);
    PrintHeapString(&str4);
}

编译通过,运行结果如下:

abcdefg
赋值后的str2:
abcdefg
比较str1与str2:0
比较str1与str3:-7
将str1与str3连接起来:
abcdefgabcdefghijklmn
截取str4中的子字符串str1:
abcdefg
寻找str4中的子字符串str1的位置:8
删除str3中的str1:
hijklmn
再把str1插入回来:
abcdefghijklmn
把str4中的str1替换为str6:
aaaaaaaaaaaaaahijklmn

Process returned 0 (0x0)   execution time : 0.040 s
Press any key to continue.

串的清空

我们在SeqString.h添加操作:

//清空字符串
Status ClearString_HeapString(HString *str);

然后在SeqString.c中添加操作:

//清空字符串
Status ClearString_HeapString(HString *str){
    if(str->ch){
        free(str->ch);
        str->ch = NULL;
    }
    str->length = 0;
    return OK;
}

在main.c中实现一下:

void TestSeqString(){
    HString str1, str2, str3, str4, str5, str6;
    StrAssign_HeapString(&str1, "abcdefg");
    StrAssign_HeapString(&str6, "aaaaaaa");
    PrintHeapString(&str1);
    StrCopy_HeapString(&str2, &str1);
    printf("\n赋值后的str2:\n");
    PrintHeapString(&str2);
    StrAssign_HeapString(&str3, "abcdefghijklmn");
    printf("\n比较str1与str2:%d\n", StrCompare_HeapString(&str1, &str2));
    printf("比较str1与str3:%d\n", StrCompare_HeapString(&str1, &str3));
    printf("将str1与str3连接起来:\n");
    Concat_HeapString(&str4, &str1, &str3);
    PrintHeapString(&str4);
    printf("\n截取str4中的子字符串str1:\n");
    SubString_HeapString(&str5, &str4, 1, str1.length);
    PrintHeapString(&str5);
    printf("\n寻找str4中的子字符串str1的位置:%d\n", Index_HeapString(&str4, &str1, 2));
    printf("删除str3中的str1:\n");
    StrDelete_HeapString(&str3, 1, str1.length);
    PrintHeapString(&str3);
    printf("\n再把str1插入回来:\n");
    StrInsert_HeapString(&str3, 1, &str1);
    PrintHeapString(&str3);
    printf("\n把str4中的str1替换为str6:\n");
    Replace_HeapString(&str4, &str1, &str6);
    PrintHeapString(&str4);
    printf("\n把str4清空:\n");
    ClearString_HeapString(&str4);
    PrintHeapString(&str4);
}

编译通过,运行结果如下:

abcdefg
赋值后的str2:
abcdefg
比较str1与str2:0
比较str1与str3:-7
将str1与str3连接起来:
abcdefgabcdefghijklmn
截取str4中的子字符串str1:
abcdefg
寻找str4中的子字符串str1的位置:8
删除str3中的str1:
hijklmn
再把str1插入回来:
abcdefghijklmn
把str4中的str1替换为str6:
aaaaaaaaaaaaaahijklmn
把str4清空:
堆字符串为空!

Process returned 0 (0x0)   execution time : 0.040 s
Press any key to continue.

 


串的操作大概就这么多,这些代码还有改进的余地,大家下去之后可以自行发挥,下次将整理链串的知识点,我们下次见👋

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值