【数据结构】之串(C语言描述)

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

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

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

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

/**
 * 串(顺序存储方式)
 * 注意:字符串都是以“\0”符号结尾的
 */
#include <Constant.h>

// 定义字符串的数据结构体
typedef struct String {
    char* data;     // 字符串中的数据
    int currLength; // 字符串的当前长度
    int maxLength;  // 字符串的总长度
} String;

// 0.获取某个字符串的长度
int getCharArrayLength(char* string) {
    int length = 0;
    while(string[length] != '\0') {
        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 => 空间分配失败,初始化字符串失败!\n");
        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 => 字符串不存在,复制失败!\n");
        return FAILURE;
    }
    if(length > S->maxLength) {
        S->data = (char*)realloc(S->data, length * sizeof(char));
        if(S->data == NULL) {
            printf("copyString => 重分配空间失败,复制字符串失败!\n");
            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 => 字符串不存在!\n");
        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 => 其中一个字符串不存在!\n");
        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 => 字符串不存在!\n");
        exit(1);
    }
    return S->currLength;
}

// 6.清空字符串
Status clearString(String* S) {
    if(S->data == NULL) {
        printf("clearString => 字符串不存在!\n");
        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 => 其中一个字符串不存在!\n");
        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 => 重分配空间失败,字符串拼接失败!\n");
            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 => 字符串不存在!\n");
        exit(1);
    }
    if(pos < 0 || pos >= S->currLength) {
        printf("getSubString => pos参数超出范围!\n");
        exit(1);
    }
    if(len > S->currLength - pos) {
        printf("getSubString => 子串长度超出范围!\n");
        exit(1);
    }
    for(i = 0; i < len; i++) {
        *(result + i) = S->data[pos + i];
    }
    *(result + i) = '\0';
    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 => 字符串不存在!\n");
        exit(1);
    }
    if(pos < 0 || pos >= S->currLength) {
        printf("locateSubString => pos参数超出范围!");
        exit(1);
    }
    if(length + pos > S->currLength) {
        printf("locateSubString => 子串长度超出范围!\n");
        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 => 字符串不存在,插入字符失败!\n");
        return FAILURE;
    }
    if(pos < 0 || pos > S->currLength) {
        printf("stringInsert => pos参数超出范围,插入字符失败!\n");
        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 => 重分配空间失败,插入字符失败!\n");
            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 => 字符串不存在,删除字符失败!\n");
        return FAILURE;
    }
    if(pos < 0 || pos >= S->currLength) {
        printf("stringDelete => pos参数超出范围,删除字符失败!\n");
        return FAILURE;
    }
    if(pos + len > S->currLength) {
        printf("stringDelete => 子串长度超出范围,删除字符失败!\n");
        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 => 字符串不存在,替换失败!\n");
        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 => 字符串不存在,遍历失败!\n");
        exit(1);
    }
    printf("遍历字符串:");
    for(i = 0; i < S->currLength; i++) {
        printf("%c", S->data[i]);
    }
    printf("\n");
}

// 14.销毁字符串
Status destroyString(String* S) {
    if(S->data == NULL) {
        printf("destroyString => 字符串不存在,不需要销毁!\n");
        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成功!\n");
        traverseString(&str1); // 遍历
    }
    if(initString(&str2, "abc") == SUCCESS) {
        printf("初始化字符串S2成功!\n");
        traverseString(&str2);
    }
    // 清空字符串
    if(clearString(&str2) == SUCCESS) {
        printf("清空字符串S2成功!\n");
    }
    // 判断字符串是否为空
    printf("字符串S1是否为空?%s\n", isStringEmpty(&str1) ? "" : "");
    printf("字符串S2是否为空?%s\n", isStringEmpty(&str2) ? "" : "");
    // 字符串复制
    if(copyString(&str2, "abcdefg") == SUCCESS) {
        printf("字符串复制成功!\n");
        traverseString(&str2);
    }
    // 字符串连接
    if(concatString(&str1, &str2) == SUCCESS) {
        printf("将字符串S2连接到S1后面成功!\n");
        traverseString(&str1);
    }
    // 比较两个字符串的大小
    printf("S1比S2的关系?%d\n", compareString(&str1, &str2));
    // 字符串的长度
    printf("字符串S1的长度:%d\n", getStringLength(&str1));
    printf("字符串S2的长度:%d\n", getStringLength(&str2));
    // 取字符串的子串
    printf("S1从58位置开始7个长度的子串是:%s\n", getSubString(&str1, 0, 7));
    // 返回子串第一次出现的位置
    printf("字符串S1中从20位置起,ABCDE子串第一次出现的位置是%d\n", locateSubString(&str1, "ABCD", 20));
    // 插入字符串
    if(stringInsert(&str1, 26, "||||||") == SUCCESS) {
        printf("在S1的26位置插入字符串||||||成功!\n");
        traverseString(&str1);
    }
    // 删除字符串
    if(stringDelete(&str1, 26, 6) == SUCCESS) {
        printf("从S1的26位置删除6个字符成功!\n");
        traverseString(&str1);
    }
    // 替换字符串
    if(replaceString(&str1, "abcdefg", "0123456789") == SUCCESS) {
        printf("成功将S1中的所有abcdefg替换为0123456789!\n");
        traverseString(&str1);
    }
    // 销毁字符串
    if(destroyString(&str1) == SUCCESS) {
        printf("销毁字符串S1成功!\n");
    }
    if(destroyString(&str2) == SUCCESS) {
        printf("销毁字符串S2成功!\n");
    }
    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.

 

posted on 2017-04-10 17:47  ITGungnir  阅读(6332)  评论(0编辑  收藏  举报

导航