zoukankan      html  css  js  c++  java
  • 【数据结构】之串(C语言描述)

      串(字符串)是编程中最常用的结构,但 C语言 中没有“字符串”这种变量,只能通过字符数组的形式表示字符串。

      C语言 为我们提供了一个 string.h 的头文件,通过这个头文件,我们可以实现对字符串的各种操作,如拷贝、比较等,具体用法请参考【C语言库函数】

      当然,我们对字符串的操作可能不仅仅局限于 string.h 这个头文件给我们提供的这些方法,因此,我们可以自己实现一个字符串的数据结构,通过在这里面编写一些实用的方法,实现我们的需求。

      以下是实用 C语言 编写的一个字符串的头文件 String.h,代码如下:

    /**
     * 串(顺序存储方式)
     * 注意:字符串都是以“”符号结尾的
     */
    #include <Constant.h>
    
    // 定义字符串的数据结构体
    typedef struct String {
        char* data;     // 字符串中的数据
        int currLength; // 字符串的当前长度
        int maxLength;  // 字符串的总长度
    } String;
    
    // 0.获取某个字符串的长度
    int getCharArrayLength(char* string) {
        int length = 0;
        while(string[length] != '') {
            length++;
        }
        return length;
    }
    
    // 1.初始化字符串(创建一个新的字符串,其中包含string中的所有字符)
    Status initString(String* S, char* string) {
        int i = 0;
        // 获取字符串的长度
        int length = getCharArrayLength(string);
        // 字符串赋值
        S->data = (char*)malloc(length * sizeof(char));
        if(S->data == NULL) {
            printf("initString => 空间分配失败,初始化字符串失败!
    ");
            return FAILURE;
        }
        S->currLength = length;
        S->maxLength = length;
        for(i = 0; i < length; i++) {
            S->data[i] = string[i];
        }
        return SUCCESS;
    }
    
    // 2.复制字符串(将字符串string中的所有字符复制到字符串S中)
    Status copyString(String* S, char* string) {
        int i;
        int length = getCharArrayLength(string);
        if(S->data == NULL) {
            printf("copyString => 字符串不存在,复制失败!
    ");
            return FAILURE;
        }
        if(length > S->maxLength) {
            S->data = (char*)realloc(S->data, length * sizeof(char));
            if(S->data == NULL) {
                printf("copyString => 重分配空间失败,复制字符串失败!
    ");
                return FAILURE;
            }
            S->maxLength = length;
        }
        S->currLength = length;
        for(i = 0; i < length; i++) {
            S->data[i] = string[i];
        }
        return SUCCESS;
    }
    
    // 3.判断字符串是否为空
    Status isStringEmpty(String* S) {
        if(S->data == NULL) {
            printf("isStringEmpty => 字符串不存在!
    ");
            exit(1);
        }
        if(S->currLength == 0) {
            return TRUE;
        }
        return FALSE;
    }
    
    // 4.比较两个字符串的大小(返回的是S1与S2比较的结果)
    // 当两个字符串的长度相等,且对应字符都相同时,称这两个字符串相等;否则,看第一个不相等的字符比较结果,字符较大的字符串较大
    Status compareString(String* S1, String* S2) {
        int i = 0;
        // 判空
        if(S1->data == NULL || S2->data == NULL) {
            printf("compareString => 其中一个字符串不存在!
    ");
            exit(1);
        }
        // 某一个字符串为空
        if(S1->currLength == 0) {
            if(S2->currLength == 0) {
                return EQUAL;
            } else {
                return SMALLER;
            }
        }
        if(S2->currLength == 0) {
            if(S1->currLength == 0) {
                return EQUAL;
            } else {
                return BIGGER;
            }
        }
        // 两个字符串都不为空时,逐个字符比较
        for(i = 0; ;i++) {
            if(i == S1->currLength && i == S2->currLength) {
                return EQUAL;
            }
            if(i >= S1->currLength) {
                return SMALLER;
            }
            if(i >= S2->currLength) {
                return BIGGER;
            }
            if(S1->data[i] > S2->data[i]) {
                return BIGGER;
            } else if(S1->data[i] < S2->data[i]) {
                return SMALLER;
            }
        }
    }
    
    // 5.获取字符串的长度
    int getStringLength(String* S) {
        if(S->data == NULL) {
            printf("getStringLength => 字符串不存在!
    ");
            exit(1);
        }
        return S->currLength;
    }
    
    // 6.清空字符串
    Status clearString(String* S) {
        if(S->data == NULL) {
            printf("clearString => 字符串不存在!
    ");
            return FAILURE;
        }
        S->currLength = 0;
        return SUCCESS;
    }
    
    // 7.将字符串S2连接到字符串S1后面并返回
    Status concatString(String* S1, String* S2) {
        if(S1->data == NULL || S2->data == NULL) {
            printf("concatString => 其中一个字符串不存在!
    ");
            return FAILURE;
        }
        int i;
        int len1 = getStringLength(S1);
        int len2 = getStringLength(S2);
        if(S1->maxLength < len1 + len2) {
            S1->data = (char*)realloc(S1->data, (len1 + len2) * sizeof(char));
            if(S1->data == NULL) {
                printf("concatString => 重分配空间失败,字符串拼接失败!
    ");
                return FAILURE;
            }
            S1->maxLength = len1 + len2;
        }
        for(i = 0; i < len2; i++) {
            S1->data[len1 + i] = S2->data[i];
        }
        S1->currLength = len1 + len2;
        return SUCCESS;
    }
    
    // 8.返回字符串S中从pos位置开始,长度为len的子串
    char* getSubString(String* S, int pos, int len) {
        char* result;
        int i;
        if(S->data == NULL) {
            printf("getSubString => 字符串不存在!
    ");
            exit(1);
        }
        if(pos < 0 || pos >= S->currLength) {
            printf("getSubString => pos参数超出范围!
    ");
            exit(1);
        }
        if(len > S->currLength - pos) {
            printf("getSubString => 子串长度超出范围!
    ");
            exit(1);
        }
        for(i = 0; i < len; i++) {
            *(result + i) = S->data[pos + i];
        }
        *(result + i) = '';
        return result;
    }
    
    // 9.返回字符串S中从pos位置开始的与子串string相等的第一个子串的位置
    int locateSubString(String* S, char* string, int pos) {
        int i, j;
        int length = getCharArrayLength(string);
        if(S->data == NULL) {
            printf("locateSubString => 字符串不存在!
    ");
            exit(1);
        }
        if(pos < 0 || pos >= S->currLength) {
            printf("locateSubString => pos参数超出范围!");
            exit(1);
        }
        if(length + pos > S->currLength) {
            printf("locateSubString => 子串长度超出范围!
    ");
            exit(1);
        }
        for(i = pos; i <= S->currLength - length; i++) {
            for(j = 0; j < length; j++) {
                if(S->data[i + j] != string[j]) {
                    break;
                }
            }
            if(j == length) {
                return i;
            }
        }
        return -1;
    }
    
    // 10.在字符串S的pos位置插入字符串string
    Status stringInsert(String* S, int pos, char* string) {
        int i;
        int length = getCharArrayLength(string);
        if(S->data == NULL) {
            printf("stringInsert => 字符串不存在,插入字符失败!
    ");
            return FAILURE;
        }
        if(pos < 0 || pos > S->currLength) {
            printf("stringInsert => pos参数超出范围,插入字符失败!
    ");
            return FAILURE;
        }
        if(S->currLength + length > S->maxLength) {
            S->data = (char*)realloc(S->data, (S->currLength + length) * sizeof(char));
            if(S->data == NULL) {
                printf("stringInsert => 重分配空间失败,插入字符失败!
    ");
                return FAILURE;
            }
            S->maxLength = S->currLength + length;
        }
        for(i = S->currLength - 1; i >= pos; i--) {
            S->data[i + length] = S->data[i];
        }
        for(i = 0; i < length; i++) {
            S->data[pos + i] = string[i];
        }
        S->currLength += length;
        return SUCCESS;
    }
    
    // 11.删除字符串S中从pos位置开始的len个字符
    Status stringDelete(String* S, int pos, int len) {
        int i;
        if(S->data == NULL) {
            printf("stringDelete => 字符串不存在,删除字符失败!
    ");
            return FAILURE;
        }
        if(pos < 0 || pos >= S->currLength) {
            printf("stringDelete => pos参数超出范围,删除字符失败!
    ");
            return FAILURE;
        }
        if(pos + len > S->currLength) {
            printf("stringDelete => 子串长度超出范围,删除字符失败!
    ");
            return FAILURE;
        }
        for(i = pos + len; i < S->currLength; i++) {
            S->data[i - len] = S->data[i];
        }
        S->currLength -= len;
        return SUCCESS;
    }
    
    // 12.用字符串newStr替换字符串S中出现的所有与子串oldStr相同的不重叠的子串
    Status replaceString(String* S, char* oldStr, char* newStr) {
        int index;
        int oldLen = getCharArrayLength(oldStr);
        int newLen = getCharArrayLength(newStr);
        if(S->data == NULL) {
            printf("replaceString => 字符串不存在,替换失败!
    ");
            return FAILURE;
        }
        index = locateSubString(S, oldStr, 0);
        while(index >= 0 && index + oldLen <= S->currLength) {
            stringDelete(S, index, oldLen);
            stringInsert(S, index, newStr);
            if(oldLen + index + newLen >= S->currLength) {
                break;
            }
            index = locateSubString(S, oldStr, index + newLen);
        }
        return SUCCESS;
    }
    
    // 13.遍历字符串
    void traverseString(String* S) {
        int i;
        if(S->data == NULL) {
            printf("traverseString => 字符串不存在,遍历失败!
    ");
            exit(1);
        }
        printf("遍历字符串:");
        for(i = 0; i < S->currLength; i++) {
            printf("%c", S->data[i]);
        }
        printf("
    ");
    }
    
    // 14.销毁字符串
    Status destroyString(String* S) {
        if(S->data == NULL) {
            printf("destroyString => 字符串不存在,不需要销毁!
    ");
            return FAILURE;
        }
        free(S->data);
        S->data = NULL;
        S->currLength = 0;
        S->maxLength = 0;
        return SUCCESS;
    }
    
    // 测试函数
    int testString() {
        // 声明变量
        String str1, str2;
        // 初始化字符串
        if(initString(&str1, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]") == SUCCESS) {
            printf("初始化字符串S1成功!
    ");
            traverseString(&str1); // 遍历
        }
        if(initString(&str2, "abc") == SUCCESS) {
            printf("初始化字符串S2成功!
    ");
            traverseString(&str2);
        }
        // 清空字符串
        if(clearString(&str2) == SUCCESS) {
            printf("清空字符串S2成功!
    ");
        }
        // 判断字符串是否为空
        printf("字符串S1是否为空?%s
    ", isStringEmpty(&str1) ? "" : "");
        printf("字符串S2是否为空?%s
    ", isStringEmpty(&str2) ? "" : "");
        // 字符串复制
        if(copyString(&str2, "abcdefg") == SUCCESS) {
            printf("字符串复制成功!
    ");
            traverseString(&str2);
        }
        // 字符串连接
        if(concatString(&str1, &str2) == SUCCESS) {
            printf("将字符串S2连接到S1后面成功!
    ");
            traverseString(&str1);
        }
        // 比较两个字符串的大小
        printf("S1比S2的关系?%d
    ", compareString(&str1, &str2));
        // 字符串的长度
        printf("字符串S1的长度:%d
    ", getStringLength(&str1));
        printf("字符串S2的长度:%d
    ", getStringLength(&str2));
        // 取字符串的子串
        printf("S1从58位置开始7个长度的子串是:%s
    ", getSubString(&str1, 0, 7));
        // 返回子串第一次出现的位置
        printf("字符串S1中从20位置起,ABCDE子串第一次出现的位置是%d
    ", locateSubString(&str1, "ABCD", 20));
        // 插入字符串
        if(stringInsert(&str1, 26, "||||||") == SUCCESS) {
            printf("在S1的26位置插入字符串||||||成功!
    ");
            traverseString(&str1);
        }
        // 删除字符串
        if(stringDelete(&str1, 26, 6) == SUCCESS) {
            printf("从S1的26位置删除6个字符成功!
    ");
            traverseString(&str1);
        }
        // 替换字符串
        if(replaceString(&str1, "abcdefg", "0123456789") == SUCCESS) {
            printf("成功将S1中的所有abcdefg替换为0123456789!
    ");
            traverseString(&str1);
        }
        // 销毁字符串
        if(destroyString(&str1) == SUCCESS) {
            printf("销毁字符串S1成功!
    ");
        }
        if(destroyString(&str2) == SUCCESS) {
            printf("销毁字符串S2成功!
    ");
        }
        return 0;
    }

      常量头文件 Constant.h 中的代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    
    #define TRUE 1
    #define FALSE 0
    
    #define SUCCESS 1
    #define FAILURE 0
    
    #define SMALLER -1
    #define EQUAL 0
    #define BIGGER 1
    
    typedef int Status;

      主函数所在的文件 main.c 中的代码如下:

    #include <String.h>
    
    int main() {
        testString();
        return 0;
    }

      运行结果如下:

    初始化字符串S1成功!
    遍历字符串:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]
    初始化字符串S2成功!
    遍历字符串:abc
    清空字符串S2成功!
    字符串S1是否为空?否
    字符串S2是否为空?是
    字符串复制成功!
    遍历字符串:abcdefg
    将字符串S2连接到S1后面成功!
    遍历字符串:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]abcdefg
    S1比S2的关系?1
    字符串S1的长度:65
    字符串S2的长度:7
    S1从58位置开始7个长度的子串是:abcdefg
    字符串S1中从20位置起,ABCDE子串第一次出现的位置是26
    在S1的26位置插入字符串||||||成功!
    遍历字符串:abcdefghijklmnopqrstuvwxyz||||||ABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]abcdefg
    从S1的26位置删除6个字符成功!
    遍历字符串:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]abcdefg
    成功将S1中的所有abcdefg替换为0123456789!
    遍历字符串:0123456789hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ()<>[]0123456789
    销毁字符串S1成功!
    销毁字符串S2成功!
    
    Process returned 0 (0x0)   execution time : 1.783 s
    Press any key to continue.
  • 相关阅读:
    yzoj P2344 斯卡布罗集市 题解
    yzoj P2350 逃离洞穴 题解
    yzoj P2349 取数 题解
    JXOI 2017 颜色 题解
    NOIP 2009 最优贸易 题解
    CH 4302 Interval GCD 题解
    CH4301 Can you answer on these queries III 题解
    Luogu2533[AHOI2012]信号塔
    Luogu3320[SDOI2015]寻宝游戏
    Luogu3187[HNOI2007]最小矩形覆盖
  • 原文地址:https://www.cnblogs.com/itgungnir/p/6690133.html
Copyright © 2011-2022 走看看