【數據結構】之串(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.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM