数据结构与算法学习笔记十一---串的定长存储和堆分配存储表示和实现(C语言)

目录

前言

1.串类型的定义       

2.队列的表示和实现

1.定长顺序存储表示

1.定义

2.串赋值

3.串拷贝

4.串空

5.串长

6.清空串

7.串拼接

8.截取子串

9.字符串替换

10.插入串

11.删除

12.销毁

13.完整代码

2.堆分配存储表示

1.定义

2.赋值

3.字符串长度

4.字符串比较

5.清空串

6.拼接串

7.截取串

9.完整代码


前言

        这篇博客主要讲串的用法。

1.串类型的定义       

        串(String)是由零个或者多个字符组成的有序序列。

        串中字符的数目n称为串的长度。

        零个字符的串称为空串,它的长度为零。

        串中任意连续的字符组成的子序列称为该串的子串。

        包含子串的串相应地称为主串。

        通常称字符在序列中的序号称为该字符在串中的位置。

2.队列的表示和实现

        队列可以分别使用顺存和链式两种存储方式实现。

1.定长顺序存储表示

       类似线性表的顺序存储结构,用一组地址连续的存储单元存储串值的字符序列。在串的定长顺序存储结构中,按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区,则可用定长数组如下描述。

1.定义

// - - - - - 串的定长顺序存储表示 - - - - -
#define MAXSTRLEN 255                       // 用户可在 255 以内定义最大串长
typedef unsigned char SString[MAXSTRLEN + 1];// 0号单元存放串的长度
typedef int Status;

2.串赋值

// 生成一个和chars相同的字符串
int strAssign(SString s, const char *chars) {
    unsigned long len = strlen(chars);
    if (len > MAXSTRLEN) {
        return 0;
    }
    s[0] = (unsigned long)len;
    for (int i = 0; i < len; i++) {
        s[i + 1] = chars[i];
    }
    for (unsigned long i = len + 1; i <= MAXSTRLEN; i++) {
        s[i] = '\0';
    }
    return 1;
}

3.串拷贝

//拷贝
void copyStr(SString s,const char * chars){
    unsigned long len = strlen(chars);
    if (len > MAXSTRLEN) {
        len = MAXSTRLEN;
    }
    s[0] = (unsigned long)len;//存储字符串的长度
    for (int i = 0; i< len; i++) {
        s[i+1] = chars[i];
    }
    for (unsigned long i = len + 1; i<= MAXSTRLEN; i++) {
        s[i] = '\0';
    }
}

4.串空

// 串空
Status strEmpty(SString str){
    return str[0] == 0;
}

5.串长

        队首和队尾相同的时候,队列为空。

// 字符串长度
int strLength(SString s) {
    return s[0];
}

6.清空串

// 清空
void clearString(SString str) {
    for (int i = 1; i <= str[0]; i++) {
        str[i] = '\0';
    }
    str[0] = 0;
}

7.串拼接

// 字符串拼接
void strConcat(SString str, SString str1, SString str2) {
    int len1 = strLength(str1);
    int len2 = strLength(str2);
    int i, j;
    if (len1 >= MAXSTRLEN) {
        for (i = 1; i <= MAXSTRLEN; i++) {
            str[i] = str1[i];
        }
        str[0] = MAXSTRLEN;
    } else {
        for (i = 1; i <= len1; i++) {
            str[i] = str1[i];
        }
        if (len1 + len2 <= MAXSTRLEN) {
            for (j = 1; j <= len2; j++) {
                str[len1 + j] = str2[j];
            }
            str[0] = len1 + len2;
        } else {
            for (j = 1; j <= MAXSTRLEN - len1; j++) {
                str[len1 + j] = str2[j];
            }
            str[0] = MAXSTRLEN;
        }
    }
}

8.截取子串

// 子串
void subString(SString sub, SString s, int pos, int len) {
    if (pos < 1 || pos > strLength(s) || len < 0 || pos + len - 1 > strLength(s)) {
        sub[0] = 0;  // 空串
    } else {
        sub[0] = len;
        for (int i = pos; i < pos + len; i++) {
            sub[i - pos + 1] = s[i];
        }
    }
}

9.字符串替换

// 替换字符串中的子串
void replace(SString s, SString sub, SString replacement) {
    int len = strLength(s);
    int subLen = strLength(sub);
    int repLen = strLength(replacement);
    int pos = 1;
    int index = 0;
    while (pos <= len - subLen + 1) {
        SString temp;
        initString(temp);
        subString(temp, s, pos, subLen);
        if (strcmp(temp + 1, sub + 1) == 0) {
            // Replace the substring
            for (int i = pos; i <= pos + repLen - 1; i++) {
                if (index >= MAXSTRLEN) {
                    return;  // Avoid buffer overflow
                }
                s[i] = replacement[++index];
            }
            // Shift the remaining characters
            for (int i = pos + repLen; i <= len; i++) {
                s[i] = s[i + subLen - repLen];
            }
            len = len - subLen + repLen;
        } else {
            pos++;
        }
    }
    s[0] = len;
}

10.插入串

// 在指定位置插入字符串
void strInsert(SString s, int pos, SString insertStr) {
    int len = strLength(s);
    int insertLen = strLength(insertStr);
    if (pos < 1 || pos > len + 1 || len + insertLen > MAXSTRLEN) {
        return;  // 插入位置不合法或插入后长度超过最大长度,直接返回
    }
    // 将插入位置后的字符向后移动
    for (int i = len; i >= pos; i--) {
        s[i + insertLen] = s[i];
    }
    // 将待插入字符串插入
    for (int i = 1; i <= insertLen; i++) {
        s[pos + i - 1] = insertStr[i];
    }
    // 更新串的长度
    s[0] = len + insertLen;
}

11.删除

// 从指定位置删除指定长度的子串
void strDelete(SString s, int pos, int len) {
    int length = strLength(s);
    if (pos < 1 || pos > length || len < 0 || pos + len > length + 1) {
        return;  // 删除位置不合法,直接返回
    }
    // 删除指定位置及后面的len个字符
    for (int i = pos + len; i <= length; i++) {
        s[i - len] = s[i];
    }
    s[0] -= len;  // 更新串的长度
}

12.销毁

// 销毁字符串
void destroyString(SString str) {
    // 释放动态分配的内存
    free(str);
}

13.完整代码

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

#define MAXSTRLEN 10  // 用户可在 10 以内定义最大串长
typedef unsigned char SString[MAXSTRLEN + 1];  // 0号单元存放串的长度
typedef int Status;
void initString(SString str){
    str[0] = 0;
}
// 字符串长度
int strLength(SString s) {
    return s[0];
}
// 生成一个和chars相同的字符串
int strAssign(SString s, const char *chars) {
    unsigned long len = strlen(chars);
    if (len > MAXSTRLEN) {
        return 0;
    }
    s[0] = (unsigned long)len;
    for (int i = 0; i < len; i++) {
        s[i + 1] = chars[i];
    }
    for (unsigned long i = len + 1; i <= MAXSTRLEN; i++) {
        s[i] = '\0';
    }
    return 1;
}
// 在指定位置插入字符串
void strInsert(SString s, int pos, SString insertStr) {
    int len = strLength(s);
    int insertLen = strLength(insertStr);
    if (pos < 1 || pos > len + 1 || len + insertLen > MAXSTRLEN) {
        return;  // 插入位置不合法或插入后长度超过最大长度,直接返回
    }
    // 将插入位置后的字符向后移动
    for (int i = len; i >= pos; i--) {
        s[i + insertLen] = s[i];
    }
    // 将待插入字符串插入
    for (int i = 1; i <= insertLen; i++) {
        s[pos + i - 1] = insertStr[i];
    }
    // 更新串的长度
    s[0] = len + insertLen;
}
// 从指定位置删除指定长度的子串
void strDelete(SString s, int pos, int len) {
    int length = strLength(s);
    if (pos < 1 || pos > length || len < 0 || pos + len > length + 1) {
        return;  // 删除位置不合法,直接返回
    }
    // 删除指定位置及后面的len个字符
    for (int i = pos + len; i <= length; i++) {
        s[i - len] = s[i];
    }
    s[0] -= len;  // 更新串的长度
}

// 字符串拼接
void strConcat(SString str, SString str1, SString str2) {
    int len1 = strLength(str1);
    int len2 = strLength(str2);
    int i, j;
    if (len1 >= MAXSTRLEN) {
        for (i = 1; i <= MAXSTRLEN; i++) {
            str[i] = str1[i];
        }
        str[0] = MAXSTRLEN;
    } else {
        for (i = 1; i <= len1; i++) {
            str[i] = str1[i];
        }
        if (len1 + len2 <= MAXSTRLEN) {
            for (j = 1; j <= len2; j++) {
                str[len1 + j] = str2[j];
            }
            str[0] = len1 + len2;
        } else {
            for (j = 1; j <= MAXSTRLEN - len1; j++) {
                str[len1 + j] = str2[j];
            }
            str[0] = MAXSTRLEN;
        }
    }
}
// 子串
void subForString(SString sub, SString s, int pos, int len) {
    if (pos < 1 || pos > strLength(s) || len < 0 || pos + len - 1 > strLength(s)) {
        sub[0] = 0;  // 空串
    } else {
        sub[0] = len;
        for (int i = pos; i < pos + len; i++) {
            sub[i - pos + 1] = s[i];
        }
    }
}

//拷贝
void copyStr(SString s,const char * chars){
    unsigned long len = strlen(chars);
    if (len > MAXSTRLEN) {
        len = MAXSTRLEN;
    }
    s[0] = (unsigned long)len;//存储字符串的长度
    for (int i = 0; i< len; i++) {
        s[i+1] = chars[i];
    }
    for (unsigned long i = len + 1; i<= MAXSTRLEN; i++) {
        s[i] = '\0';
    }
}
// 串空
Status strEmpty(SString str){
    return str[0] == 0;
}
// 销毁字符串
void destroyString(SString str) {
    // 释放动态分配的内存
    free(str);
}
// 清空
void clearString(SString str) {
    for (int i = 1; i <= str[0]; i++) {
        str[i] = '\0';
    }
    str[0] = 0;
}
// 打印str
void printStr(SString str){
    int len = str[0];
    for (int i = 1; i<= len; i++) {
        printf("%c",str[i]);
    }
}
// 替换字符串中的子串
void replace(SString s, SString sub, SString replacement) {
    int len = strLength(s);
    int subLen = strLength(sub);
    int repLen = strLength(replacement);
    int pos = 1;
    int index = 0;
    while (pos <= len - subLen + 1) {
        SString temp;
        initString(temp);
        subForString(temp, s, pos, subLen);
        if (strcmp(temp + 1, sub + 1) == 0) {
            // Replace the substring
            for (int i = pos; i <= pos + repLen - 1; i++) {
                if (index >= MAXSTRLEN) {
                    return;  // Avoid buffer overflow
                }
                s[i] = replacement[++index];
            }
            // Shift the remaining characters
            for (int i = pos + repLen; i <= len; i++) {
                s[i] = s[i + subLen - repLen];
            }
            len = len - subLen + repLen;
        } else {
            pos++;
        }
    }
    s[0] = len;
}
// 测试函数
void testString(void) {
    SString str, subStr, replacement, insertStr;
    printf("\n**********\t字符串是否为空操作\t**********\n");
    if (strEmpty(str)) {
        printf("字符串为空\n");
    }
    printf("字符串长度:%d\n", strLength(str));
    printf("**********\t字符串赋值操作\t**********\n");
    if (strAssign(str, "ABCDEFGHIJKL")) {
        printf("赋值成功\n");
    } else {
        printf("赋值错误\n");
    }

    if (strAssign(str, "ABCDEFGHIJ")) {
        printf("赋值成功,str:");
        printStr(str);
        printf("\n");
    } else {
        printf("赋值错误\n");
    }
    printf("\n**********\t字符串拷贝操作\t**********\n");
    SString copStr;
    copyStr(copStr, "ABCDEFGHIJK");
    printf("拷贝之后的字符串:");
    printStr(copStr);
    printf("\n");
    printf("\n**********\t字符串是否为空操作\t**********\n");
    if (!strEmpty(copStr)) {
        printf("字符串不为空\n");
    }
    printf("字符串长度:%d\n", strLength(copStr));
    printf("\n**********\t字符串清空操作\t**********\n");
    clearString(copStr);
    printf("清空之后的字符串:");
    printStr(copStr);
    printf("\n");
    printf("\n**********\t字符串拼接操作\t**********\n");

    strAssign(str, "ABCDEFG");
    strAssign(subStr, "HIJK");
    strConcat(str, str, subStr);
    printf("拼接之后的字符串:");
    printStr(str);
    printf("\n");
    printf("\n**********\t字符串截取操作\t**********\n");
    SString subString;
    subForString(subString, str, 5, 5);
    printf("截取之后的字符串:");
    printStr(subString);
    printf("\n");
    printf("\n**********\t字符串替换操作\t**********\n");
    strAssign(str, "Hello, world!");
    strAssign(subStr, "world");
    strAssign(replacement, "everyone");
    replace(str, subStr, replacement);
    printf("替换之后的字符串:");
    printStr(str);
    printf("\n");
    printf("\n**********\t字符串插入操作\t**********\n");
    strAssign(insertStr, "my ");
    strInsert(str, 7, insertStr);
    printf("插入之后的字符串:");
    printStr(str);
    printf("\n");
    printf("\n**********\t字符串删除操作\t**********\n");
    strDelete(str, 6, 10);
    printf("删除之后的字符串:");
    printStr(str);
    printf("\n");
    printf("\n**********\t销毁字符串操作\t**********\n");
    destroyString(str);
    destroyString(subStr);
    destroyString(replacement);
    destroyString(insertStr);
}

int main(int argc, const char *argv[]) {
    testString();
    return 0;
}

2.堆分配存储表示

        用一组地址连续的存储单元存放串值字符序列,但是它们的存储空间是在程序执行过程中动态分配的。C语言中,存放一个称为“堆”的自由存储区,并且这些存储区域由动态分配函数malloc()和free()管理。

1.定义

// - - - - - 串的分配存储表示 - - - - -
typedef int Status;
typedef struct {
    char *ch;   // 若是非空串,则按串长分配存储区;否则,ch为NULL
    int length; // 串长度
} HString;

2.赋值

// 生成一个和chars相同的字符串
Status strAssign(HString *s, const char *chars) {
    int len = strlen(chars);
    if (len == 0) {
        s->ch = NULL;
        s->length = 0;
    } else {
        s->ch = (char *)malloc((len + 1) * sizeof(char));
        if (!s->ch) {
            return 0; // 内存分配失败
        }
        strcpy(s->ch, chars);
        s->length = len;
    }
    return 1;
}

3.字符串长度

// 字符串长度
int strLength(HString str) {
    return str.length;
}

4.字符串比较

// 字符串比较
int strCompare(HString s, HString t) {
    int len_s = strLength(s);
    int len_t = strLength(t);
    int min_len = len_s < len_t ? len_s : len_t;
    for (int i = 0; i < min_len; i++) {
        if (s.ch[i] != t.ch[i]) {
            return s.ch[i] - t.ch[i];
        }
    }
    return len_s - len_t;
}

5.清空串

// 清空字符串
Status clearString(HString str) {
    if (str.ch) {
        free(str.ch);
        str.ch = NULL;
        str.length = 0;
    }
    return 1;
}

6.拼接串

// 拼接字符串
Status concat(HString result, HString str1, HString str2) {
    int len1 = strLength(str1);
    int len2 = strLength(str2);
    result.ch = (char *)malloc((len1 + len2 + 1) * sizeof(char));
    if (!result.ch) {
        return 0; // 内存分配失败
    }
    strcpy(result.ch, str1.ch);
    strcat(result.ch, str2.ch);
    result.length = len1 + len2;
    return 1;
}

7.截取串

// 截取字符串
HString subString(HString s, int pos, int len) {
    HString sub;
    if (pos < 1 || pos > s.length || len < 0 || pos + len - 1 > s.length) {
        sub.ch = NULL;
        sub.length = 0;
        return sub; // 返回空串
    }
    sub.ch = (char *)malloc((len + 1) * sizeof(char));
    if (!sub.ch) {
        sub.length = 0;
        return sub; // 内存分配失败,返回空串
    }
    strncpy(sub.ch, s.ch + pos - 1, len);
    sub.ch[len] = '\0'; // 添加字符串结束符
    sub.length = len;
    return sub;
}

9.完整代码

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

// - - - - - 串的分配存储表示 - - - - -
typedef int Status;
typedef struct {
    char *ch;   // 若是非空串,则按串长分配存储区;否则,ch为NULL
    int length; // 串长度
} HString;

// 生成一个和chars相同的字符串
Status strAssign(HString *s, const char *chars) {
    int len = strlen(chars);
    if (len == 0) {
        s->ch = NULL;
        s->length = 0;
    } else {
        s->ch = (char *)malloc((len + 1) * sizeof(char));
        if (!s->ch) {
            return 0; // 内存分配失败
        }
        strcpy(s->ch, chars);
        s->length = len;
    }
    return 1;
}

// 字符串长度
int strLength(HString str) {
    return str.length;
}

// 字符串比较
int strCompare(HString s, HString t) {
    int len_s = strLength(s);
    int len_t = strLength(t);
    int min_len = len_s < len_t ? len_s : len_t;
    for (int i = 0; i < min_len; i++) {
        if (s.ch[i] != t.ch[i]) {
            return s.ch[i] - t.ch[i];
        }
    }
    return len_s - len_t;
}

// 清空字符串
Status clearString(HString str) {
    if (str.ch) {
        free(str.ch);
        str.ch = NULL;
        str.length = 0;
    }
    return 1;
}

// 拼接字符串
Status concat(HString result, HString str1, HString str2) {
    int len1 = strLength(str1);
    int len2 = strLength(str2);
    result.ch = (char *)malloc((len1 + len2 + 1) * sizeof(char));
    if (!result.ch) {
        return 0; // 内存分配失败
    }
    strcpy(result.ch, str1.ch);
    strcat(result.ch, str2.ch);
    result.length = len1 + len2;
    return 1;
}

// 截取字符串
HString subString(HString s, int pos, int len) {
    HString sub;
    if (pos < 1 || pos > s.length || len < 0 || pos + len - 1 > s.length) {
        sub.ch = NULL;
        sub.length = 0;
        return sub; // 返回空串
    }
    sub.ch = (char *)malloc((len + 1) * sizeof(char));
    if (!sub.ch) {
        sub.length = 0;
        return sub; // 内存分配失败,返回空串
    }
    strncpy(sub.ch, s.ch + pos - 1, len);
    sub.ch[len] = '\0'; // 添加字符串结束符
    sub.length = len;
    return sub;
}

// 测试函数
void testString(void) {
    HString str1, str2, result;
    strAssign(&str1, "Hello");
    strAssign(&str2, "World");
    
    // 测试字符串赋值和长度
    printf("str1: %s, length: %d\n", str1.ch, strLength(str1));
    printf("str2: %s, length: %d\n", str2.ch, strLength(str2));

    // 测试字符串比较
    printf("Compare str1 and str2: %d\n", strCompare(str1, str2));

    // 测试字符串拼接
    concat(result, str1, str2);
    printf("Concatenated string: %s, length: %d\n", result.ch, strLength(result));

    // 测试字符串截取
    HString sub = subString(result, 3, 5);
    printf("Substring from position 3 with length 5: %s, length: %d\n", sub.ch, strLength(sub));

    // 清空字符串
    clearString(str1);
    printf("After clearing str1, length: %d\n", strLength(str1));
}

int main(int argc, const char *argv[]) {
    testString();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫柱子哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值