串存储结构

串:由零个或多个字符组成的有限序列,又名字符串。

实现代码如下:

// 串存储结构
#include <stdio.h>
#include <string.h>

#define OK 1      // 执行成功
#define ERROR 0   // 执行失败
#define TRUE 1    // 返回值为真
#define FALSE 0   // 返回值为假

#define MAXSIZE 20 // 存储空间初始分配大小

typedef int Status; // 函数返回结果类型

// 串的存储结构,0下标位置用来存放字符串长度
typedef char String[MAXSIZE + 1];

/**
 * 生成一个值等于字符串chars的字符串T
 * @param T 新生成的字符串
 * @param chars 原字符串
 * @return 执行状态
 */
Status StrAssign(String T, char *chars) {
    int i; // 用于遍历元素

    // 字符串chars的长度大于字符串T的分配空间,生成失败
    if (strlen(chars) > MAXSIZE) {
        return ERROR;
    } else {
        // 计算字符串chars的长度,存到T的0下标位置
        T[0] = strlen(chars);

        for (i = 1; i <= T[0]; ++i) {
            // 将字符串chars的所有内容存到字符串T中
            T[i] = *(chars + i - 1); //(T从1下标开始存,chars从0下标开始取值,所以要减1)
        }
        return OK;
    }
}

/**
 * 将串S的所有内容复制到串T中
 * @param T 新生成的串
 * @param S 被复制的串
 * @return 执行状态
 */
Status StrCopy(String T, String S) {
    int i; // 用于遍历元素

    // 遍历S的所有涌入
    for (i = 0; i <= S[0]; ++i) {
        T[i] = S[i];
    }
    return OK;
}

/**
 * 判断串是否为空
 * @param S 串
 * @return 是否为空串
 */
Status StrEmpty(String S) {
    // 下标为0的位置存储串的长度,若等于0,串为空
    if (S[0] == 0) {
        return TRUE;
    } else {
        return FALSE;
    }
}

/**
 * 比较串S和T的大小
 * 若S>T,返回值>0;若S=T,返回值为0;若S<T,返回值<0
 * @param S 串
 * @param T 串
 * @return 串S是否比串T大
 */
int StrCompare(String S, String T) {
    int i; // 用于遍历元素

    // 遍历串的内容
    for (i = 0; i <= S[0] && i <= T[0]; i++) {
        // 碰到对应位置字符不相等
        if (S[i] != T[i]) {
            // 使用对应位置
            return S[i] - T[i];
        }
    }
    // 使用两个串的长度相减
    return S[0] - T[0];
}

/**
 * 返回串的元素个数
 * @param S 串
 * @return 串的元素个数
 */
int StrLength(String S) {
    return S[0];
}

/**
 * 将串的内容清空
 * @param S 串
 * @return 执行状态
 */
Status ClearString(String S) {
    S[0] = 0; // 令串的长度为0
    return OK;
}

/**
 * 连接S1和S2成新的串T
 * 如果未截断返回TRUE,截断则返回FALSE
 * @param T 连接成的新串
 * @param S1 串
 * @param S2 串
 * @return 是否对连接成的字符串截断
 */
Status Concat(String T, String S1, String S2) {
    int i; // 用于遍历元素

    // 串T的大小可以装下串S1和串S2的内容
    if (S1[0] + S2[0] <= MAXSIZE) {
        // 复制S1的所有内容到T中
        for (i = 1; i <= S1[0]; i++) {
            T[i] = S1[i];
        }
        // 复制S2的所有内容到T中
        for (i = 1; i <= S2[0]; i++) {
            T[S1[0] + i] = S2[i]; // S2的内容在S1的内容之后
        }
        // 串T的长度等于S1和S2的长度之和
        T[0] = S1[0] + S2[0];
        return TRUE; // 表示S2字符串未被截断
    }
    // 串T的大小不能装下串S1和串S2的内容,将截断S2
    else {
        // 复制S1的所有内容到T中
        for (i = 1; i <= S1[0]; ++i) {
            T[i] = S1[i];
        }
        // 当未超过T的最大长度时,复制S2的内容到T中
        for (i = 1; i <= MAXSIZE - S1[0]; i++) {
            T[S1[0] + i] = S2[i]; // S2的内容在S1的内容之后
        }
        // T的长度等于限定的最大长度
        T[0] = MAXSIZE;
        return FALSE; // 表示字符串S2被截断
    }
}

/**
 * 用串Sub返回串S第pos个字符起长度为len的字符
 * @param Sub 截取的子串
 * @param S 原串
 * @param pos 开始截取位置
 * @param len 截取长度
 * @return 执行状态
 */
Status SubString(String Sub, String S, int pos, int len) {
    int i; // 用于遍历元素

    // 截取的开始位置或长度不合理,截取失败
    if (pos < 1 || pos > S[0] || len < 0 || len > S[0] - pos + 1) {
        return ERROR;
    }

    // 截取串S中从pos位置开始,长度为len的内容到串Sub中
    for (i = 1; i <= len; ++i) {
        Sub[i] = S[pos + i - 1];
    }
    // 将串Sub的长度设置为len
    Sub[0] = len;
    return OK;
}

/**
 * 定位子串T在串S第pos个字符之后的位置,若不存在则返回0
 * (此方法叫:朴素模式的匹配算法)
 * @param S 原字符串
 * @param T 子串
 * @param pos 在S中开始定位的位置
 * @return 子串T在串S第pos个字符之后的位置,若不存在则返回0
 */
int Index(String S, String T, int pos) {
    int i = pos; // i等于串S开始定位的下标
    int j = 1; // j用于记录子串T中当前下标的位置

    // i小于串S的长度,并且j小于串T的长度
    while (i <= S[0] && j <= T[0]) {
        // 若对应位置的字符相等,i和j都加1
        if (S[i] == T[j]) {
            i++;
            j++;
        } else { // 若对应位置的字符不相等
            i = i - j + 2; // i退回上次匹配首位的下一位
            j = 1; // j退回子串T的首位
        }
    }

    // 串T的所有元素都与S的某个子串相等
    if (j > T[0]) {
        return i - T[0]; // i位置减去串T的长度,得到子串的起始位置
    } else { // 未定位到串T
        return 0; 
    }
}

/**
 * 在串S的第pos个位置插入串T的值
 * 返回TRUE表示完全将T的内容插入S中,FALSE表示不能完全将T的内容插入S中
 * @param S 串S
 * @param pos 下标
 * @param T 串T
 * @return 执行状态
 */
Status StrInsert(String S, int pos, String T) {
    int i; // 用于遍历元素

    // 插入位置不合理,插入错误
    if (pos < 1 || pos > S[0] + 1) {
        return ERROR;
    }

    // 串T有足够的位置完全插入串S中
    if (S[0] + T[0] <= MAXSIZE) {
        // 串S从i位置开始,所有元素向后移动串T的长度
        for (i = S[0]; i >= pos; i--) {
            S[i + T[0]] = S[i];
        }
        // 从第i个位置插入串T的值
        for (i = pos; i < pos + T[0]; i++) {
            S[i] = T[i - pos + 1];
        }
        // 设置S的长度为原来S的长度与T长度之和
        S[0] = S[0] + T[0];
        return TRUE; // 返回TRUE表示完全将T的内容插入S中
    } else {  // 串T没有有足够的位置完全插入串S中,只能部分插入
        // 将S的pos位置开始的元素向后移动T个位置
        for (i = MAXSIZE; i <= pos; i--) {
            S[i] = S[i - T[0]];
        }
        // 从第i个位置插入串T的值
        for (i = pos; i < pos + T[0]; i++) {
            S[i] = T[i - pos + 1];
        }
        S[0] = MAXSIZE; // S的长度为最大初始值
        return FALSE; // 返回FALSE表示不能完全将T的内容插入S中
    }
}

/**
 * 从串S的第pos个位置开始,删除len个长度的内容
 * @param S 串S
 * @param pos 开始删除的下标
 * @param len 删除的长度
 * @return 执行状态
 */
Status StrDelete(String S, int pos, int len) {
    int i; // 用于遍历元素

    // 删除位置不合理,删除失败
    if (pos < 1 || pos > S[0] - len + 1 || len < 0) {
        return ERROR;
    }

    // 将被删除位置的值用后面的值覆盖
    for (i = pos + len; i <= S[0]; i++) {
        S[i - len] = S[i];
    }

    S[0] -= len; // S的长度减去len
    return OK;
}

/**
 * 串S中所有等于串T的内容全都用串V进行替换
 * @param S 串S
 * @param T 串T 被替换
 * @param V 串V 替换的新内容
 * @return 执行状态
 */
Status Replace(String S, String T, String V) {
    int i = 1; // 从串S的第一个字符起查找串T

    // 串T是空串,替换失败
    if (StrEmpty(T)) {
        return ERROR;
    }

    do {
        i = Index(S, T, i); // 定位子串T在串S第pos个字符之后的位置
        // 串T在串S中存在
        if (i) {
            StrDelete(S, i, StrLength(T)); // 在串S中删除串T
            StrInsert(S, i, V); // 在原串T的位置删除串V
            i += StrLength(V); // 在插入的串V的后面继续查找串T
        }
    } while (i); // 当串S中还有串T的存在
    return OK;
}

/**
 * 打印串的内容
 * @param T 串T
 */
void StrPrint(String T) {
    int i; // 用于遍历元素
    // 打印字符串中所有元素的值
    for (i = 1; i <= T[0]; i++) {
        printf("%c", T[i]);
    }
    printf("\n");
}

int main() {
    String t, s1, s2; // 串
    Status status; // 执行状态
    int index; // 起始坐标

    status = StrEmpty(t); // 判断字符串t是否为空

    printf("串t是否为空:%s\n", status == TRUE ? "是" : "否");

    /*** 将字符串S赋值为abcd ***/
    status = StrAssign(t, "ab");

    printf("串t的值为:");
    StrPrint(t); // 打印串t
    printf("串t的长度为:%d\n", StrLength(t)); // 获取串的长度
    
    /*** 将字符串S赋值为abcd ***/
    status = StrAssign(s1, "abcd"); // 将字符串S赋值为abcd
    
    printf("将字符串S赋值为abcd后,串s1的值为:");
    StrPrint(s1); // 打印串s1
    printf("串s1的长度为:%d\n", StrLength(s1)); // 获取串的长度

    /*** 复制串s1的内容到s2中 ***/
    StrCopy(s2, s1); // 复制串s1的内容到s2中
    printf("复制串s1的内容到s2后,串s2的值为:");
    StrPrint(s2); // 打印串s2
    printf("串s2的长度为:%d\n", StrLength(s1)); // 获取串的长度

    /*** 比较t和s1的大小 ***/
    status = StrCompare(t, s1);

    if (status > 0) {
        printf("t大于s1\n");
    } else if (status == 0) {
        printf("t等于s1\n");
    } else {
        printf("t小于s2\n");
    }

    /*** 清空字符串s2中的内容 ***/
    status = ClearString(s2);
    printf("s2是否为空串:%s\n", StrEmpty(s2) == TRUE ? "是" : "否");

    /*** 将s1和s2连接后的值,赋值给串t ***/
    status = StrAssign(s2, "efg"); // 重新赋值串s2等于efg

    status = Concat(t, s1, s2); // 连接s1和s2的值,赋值给串t
    printf("连接s1和s2的值到t后,串t的值为:");
    StrPrint(t); // 打印串t

    /*** 截取串t的部分内容到串s2 ***/
    status = SubString(s2, t, 2, 3); // 从串t的2下标位置截取3个字符,赋值给s2

    printf("截取串t的部分内容后,串s2的值为:");
    StrPrint(s2); // 打印串

    /*** 定位子串s2在串t中的起始位置 ***/
    index = Index(t, s2, 0); // 定位子串s2在串t中的起始位置(从0下标开始统计)
    printf("串s2在t的位置为:%d\n", index);

    /*** 在串t下标为4的位置插入串s1 ***/
    status = StrInsert(t, 4, s1); // 在串t下标为4的位置插入串s1
    printf("下标为4的位置插入s1后,串t的值为:");
    StrPrint(t); // 打印串

    /*** 在串t下标为4的位置删除4个字符 ***/
    status = StrDelete(t, 4, 4); // 在串t下标为4的位置删除4个字符

    printf("下标为4的位置删除三个字符后,串t的值为:");
    StrPrint(t); // 打印串

    /*** 替换串t中的abcd成123 ***/
    status = StrAssign(s2, "123"); // 重新赋值串s2等于123
    status = StrAssign(t, "abcdggggabcdggggabcd"); // 重新赋值给串t

    status = Replace(t, s1, s2); // 在串t中,用s2的值替换调s1的值

    printf("替换内容后,串t的值为:");
    StrPrint(t); // 打印串
}
运行结果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容