數據結構(12.2)串之定長順序串

前言

終於考完試放假回家了,進度被拖慢了不少,只能假期慢慢補了。

定長順序串是串順序存儲結構的一種,順序存儲結構意味着它所佔的內存空間是一塊連續的,而定長意味着空間大小在串創建之初就確定了,無法動態分配內存,如果有超過的部分只能捨去。在這裏我們使用尾部加“ \0 ”的方法來表示串結束,因此實際要開闢的空間是 MAXSTRLEN + 1。

定長順序串的初始化

我們使用數組來保存串,因此直接定義一個字符數組作爲串。

#define u_char unsigned char
typedef u_char SString[MAXSTRLEN+1];

串的初始化就是將這個字符數組初始化爲空串,在數組首位添加" \0 "即可

void InitString(SString s){
    s[0] = '\0';
}

定長順序串的賦值

在這裏賦值的意思是,我們有一個char *類型的字符串,將它轉化爲我們自定義的SString類型,就是給SString進行賦值。

因此賦值包括三個步驟:

1.計算出char *類型的字符串的長度

2.判斷長度是否超出定義的最大長度,如果超出則需要截斷超出的部分

3.依次取出char *中的每一個字符,然後保存到SString數組中

void StrAssign(SString s,char *str){
    //1.求要賦值的字符串的長度
    int len = (int)strlen(str);
    
    //2.比較是否超出最大長度
    if (len > MAXSTRLEN) {
        //超出,只能賦值到最大長度的位置
        len = MAXSTRLEN;
    }
    
    //3.依次賦值
    for (int i = 0; i < len; i ++) {
        s[i] = str[i];
    }
    //標記字符串結束
    s[len] = '\0';
}

在最後不要忘記添加“ \0 ”表示字符串結束

定長順序串的比較

比較的意思是,將兩個字符串對應位置的字符的ASCII碼依次進行比較,假如一致則繼續比較,不一致則直接輸出結果。例如字符串abc和字符串acb,先將a與a比,一樣則b與c比,因爲c的ASCII碼比b大,認爲acb大於abc,輸出結果。只有每個字符都相等時,才意味着兩個字符串相等。

因爲是直接比較ASCII碼,我們也可以這樣設計:定義result等於0,然後依次取出字符直接相減,假如a字符大於b字符,則結果大於0;若小於則小於0,一致則等於0。在大於或小於0時直接退出循環,等於0時則繼續取下一個字符,直到兩個字符串都結束爲止。

int StrCompare(SString s,SString t){
    int result = 0;
    //判斷字符串是否結束
    while (*s != '\0' || *t != '\0') {
        result = *s - *t;
        if (result != 0) {
          //如果有結果則直接退出循環
            break;
        }
        s ++;
        t ++;
    }
    return result;
}

定長順序串的連接

連接是指將串s2接到串s1的尾部,用串t來保存。由於是定長順序串,需要考慮到串t能否裝得下的問題。

一共有三種情況:

1.s1和s2都裝得下,直接裝即可

2.只裝得下s1和s2的一部分,s2需要截斷

3.只裝得下s1(s1的長度等於MAXSTRLEN),只存s1即可

需要針對不同的情況進行不同處理。

void StrConcar(SString t,SString s1,SString s2){
    int len1 = StrLength(s1);
    int len2 = StrLength(s2);
    
    if (len1 + len2 <= MAXSTRLEN) {
        //裝得下兩個子串->直接裝入
        for (int i = 0; i < len1; i ++) {
            t[i] = s1[i];
        }
        for (int j = 0; j < len2; j ++) {
            t[len1+j] = s2[j];
        }
        t[len1+len2] = '\0';
    }else if(len1 < MAXSTRLEN){
        //只裝得下s1和部分s2->s2需要截斷
        for (int i = 0; i < len1; i ++) {
            t[i] = s1[i];
        }
        for (int j = 0; j < MAXSTRLEN - len1; j ++) {
            t[len1+j] = s2[j];
        }
        //最後一個位置設爲'\0'表示結束
        t[MAXSTRLEN] = '\0';
    }else{
        //只裝得下s1
        for (int i = 0; i < len1; i ++) {
            t[i] = s1[i];
        }
        t[MAXSTRLEN] = '\0';
    }
}

當然還有另一種寫法:先將s1存入t中,然後判斷t剩餘空間的情況,如果能存下s2則直接存入,否則將s2截斷後存入。

定長順序串的插入與刪除

定長順序串的插入指的是,將串t從pos的位置插入到串s中。這同樣要考慮s串能否裝得下的問題,假如裝不下則需要截斷串t,然後從pos位置起的字符往後挪t_len(實際能插入的長度)位,再將t插入。

img_1

刪除指的是,在串s中從pos的位置開始刪除長度爲len的子串。首先需要判斷是否越界的問題,然後直接從pos位置起將len長度後的字符直接往前挪即可。

img_2

定長順序串的定位

定位指的是,在串s中從pos位置起尋找子串t,如果找到則返回其第一個字符在s串的位置。這個方法返回的是第一個子串t的位置,假如後續還有其他子串t是無法找到的。

這其中涉及到字符串的匹配算法,比較複雜,爲了實現的方便我們直接使用BF算法:從pos位置起遍歷串s,與串t的首個字符開始比較,假如一致則串s和串t都移到下一位,繼續比較下一個字符。當有不一致時,串t需要回溯到起始位置,而串s要回溯到與串t開始相等的位置,並且移到下一位,繼續和串t的首個字符比較。

int StrIndex(SString s,SString t,int pos){
    //標記s串的位置
    int i = pos;
    //標記t串的位置
    int j = 0;
    
    while (s[i]!='\0' && t[j]!='\0') {
        //判斷兩個字符是否相等
        if (s[i] == t[j]) {
            //相等,找到下一個位置
            i ++;
            j ++;
        }else{
            //不相等,s串回溯到與t串開始相等的位置,並且挪到下一位
            i = i-j+1;
            //t串回溯到起始位置
            j = 0;
        }
    }
    
    if (t[j] == '\0') {
        return i-j;
    }
    return -1;
}

定長順序串的替換

替換指的是使用串v替換在串s中出現的所有子串t。

因爲在之前已經實現過定位、插入和刪除的方法,在這裏我們直接調用即可。思路是:首先調用定位方法,找到子串t在串s中的位置pos,然後調用刪除方法刪除從pos位置起長度爲t_len的字符串,最後調用插入方法從pos位置起插入串v。

需要注意的是,因爲子串可能不止出現一次,因此需要循環調用定位的方法,當定位失敗(不存在子串)或者位置已經超出串s的長度時才能退出循環。

void StrReplace(SString s,SString t,SString v){
    int s_len = StrLength(s);
    int t_len = StrLength(t);
    int v_len = StrLength(v);
    
    int index = -1;
    int pos = 0;
    
    while (pos < s_len) {
        //開始匹配
        index = StrIndex(s, t, pos);
        if (index == -1) {
            //不存在子串
            return;
        }
        //存在
        //1.先刪除t串
        StrDelete(s, index, t_len);
        //2.插入v串
        StrInsert(s, index, v);
        
        pos = index + v_len;
    }
}

全部代碼

SString.h

#ifndef SString_h
#define SString_h

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

#define MAXSTRLEN 20
#define u_char unsigned char

typedef u_char SString[MAXSTRLEN+1];

//初始化
void InitString(SString s);
//賦值
void StrAssign(SString s,char *str);
//展示
void PrintString(SString s);
//拷貝(將t串拷貝到s串來
void StrCopy(SString s,SString t);
//判空:0->非空 !0->空
int StrEmpty(SString s);
//比較(若s>t 返回值>0 s==t 返回值==0 s<t 返回值<0
//依次取出對應位置的字符,以ASCII碼值進行比較
int StrCompare(SString s,SString t);
//求長度
int StrLength(SString s);
//鏈接
void StrConcar(SString t,SString s1,SString s2);
void StrConcar2(SString t,SString s1,SString s2);
//求子串(在s串中從pos位置開始求長度爲len的子串,並保存到sub串中
void SubString(SString s,SString sub,int pos,int len);
//插入(將t串從pos位置起插入到s串中
void StrInsert(SString s,int pos,SString t);
//刪除(在s串中從pos位置開始刪除長度爲len的子串
void StrDelete(SString s,int pos,int len);
//清除
void StrClear(SString s);
//定位(在s串中尋找子串t,如果找到則返回第一個字符在s串的位置,用pos返回
int StrIndex(SString s,SString t,int pos);
//替換(用v替換在s中出現的所有子串t
void StrReplace(SString s,SString t,SString v);

#endif /* SString_h */

SString.c

#include "SString.h"
//初始化->初始化爲空串
void InitString(SString s){
    s[0] = '\0';
}

//賦值
void StrAssign(SString s,char *str){
    //求要賦值的字符串的長度
    int len = (int)strlen(str);
    
    //比較是否超出最大長度
    if (len > MAXSTRLEN) {
        //超出,只能賦值到最大長度的位置
        len = MAXSTRLEN;
    }
    
    //依次賦值
    for (int i = 0; i < len; i ++) {
        s[i] = str[i];
    }
    //標記字符串結束
    s[len] = '\0';
}
//展示
void PrintString(SString s){
    printf("%s\n",s);
}
//拷貝(將t串拷貝到s串來
void StrCopy(SString s,SString t){
    //獲取t串長度
    int len = StrLength(t);
    for (int i = 0; i < len; i ++) {
        s[i] = t[i];
    }
    s[len] = '\0';
}
//判空:0->非空 !0->空
int StrEmpty(SString s){
    return s[0] == '\0';
}
//比較(若s>t 返回值>0 s==t 返回值==0 s<t 返回值<0 以ASCII碼值進行比較
int StrCompare(SString s,SString t){
    int result = 0;
    while (*s != '\0' || *t != '\0') {
        result = *s - *t;
        if (result != 0) {
            break;
        }
        s ++;
        t ++;
    }
    return result;
}
//求長度
int StrLength(SString s){
    int len = 0;
    while (*s != '\0') {
        len ++;
        s ++;
    }
    return len;
}
//鏈接
void StrConcar(SString t,SString s1,SString s2){
    int len1 = StrLength(s1);
    int len2 = StrLength(s2);
    
    if (len1 + len2 <= MAXSTRLEN) {
        //裝得下兩個子串->直接裝入
        for (int i = 0; i < len1; i ++) {
            t[i] = s1[i];
        }
        for (int j = 0; j < len2; j ++) {
            t[len1+j] = s2[j];
        }
        t[len1+len2] = '\0';
    }else if(len1 < MAXSTRLEN){
        //只裝得下s1和部分s2->s2需要截斷
        for (int i = 0; i < len1; i ++) {
            t[i] = s1[i];
        }
        for (int j = 0; j < MAXSTRLEN - len1; j ++) {
            t[len1+j] = s2[j];
        }
        //最後一個位置設爲'\0'表示結束
        t[MAXSTRLEN] = '\0';
    }else{
        //只裝得下s1
        for (int i = 0; i < len1; i ++) {
            t[i] = s1[i];
        }
        t[MAXSTRLEN] = '\0';
    }

}
void StrConcar2(SString t,SString s1,SString s2){
    int len1 = StrLength(s1);
    int len2 = StrLength(s2);
    
    //先將s1裝入
    for (int i = 0; i < len1; i ++) {
        t[i] = s1[i];
    }
    
    //判斷t剩餘的空間情況
    if (MAXSTRLEN-len1 > 0) {
        //還未滿
        //判斷是否能把整個s2裝下
        if (len1+len2 <= MAXSTRLEN) {
            //是
            for (int j = 0; j < len2; j ++) {
                t[len1+j] = s2[j];
            }
            t[len1+len2] = '\0';
        }else{
            //否,s2需要截斷
            for (int j = 0; j < MAXSTRLEN - len1; j ++) {
                t[len1+j] = s2[j];
            }
            //最後一個位置設爲'\0'表示結束
            t[MAXSTRLEN] = '\0';
        }
    }
}
//求子串(在s串中從pos位置開始求長度爲len的子串,並保存到sub串中
void SubString(SString s,SString sub,int pos,int len){
    //判斷位置是否合法
    int s_len = StrLength(s);
    if (pos<0 || pos>= s_len || len<0 || len>s_len || pos+len>s_len) {
        printf("要截取的位置或長度不合法\n");
        return;
    }
    
    for (int i = 0; i < len; i ++) {
        sub[i] = s[pos+i];
    }
    sub[len] = '\0';
    
}
//插入(將t串從pos位置起插入到s串中
void StrInsert(SString s,int pos,SString t){
    int s_len = StrLength(s);
    int t_len = StrLength(t);
    
    //長度不足->只能插入t串的一部分
    if (s_len+t_len > MAXSTRLEN) {
        t_len = MAXSTRLEN-s_len;
    }
    //將原來pos位置的字符挪到pos+t_len上
    for (int i = s_len-1; i>=pos; i --) {
        s[i+t_len] = s[i];
    }
    //將t串插入到pos位置上
    int j = pos;
    for (int i = 0; i < t_len; i++) {
        s[j+i] = t[i];
    }
    s[s_len+t_len] = '\0';    
}
//刪除(在s串中從pos位置開始刪除長度爲len的子串
void StrDelete(SString s,int pos,int len){
    int s_len = StrLength(s);
    if (pos < 0 || pos > s_len || len < 0 || len > s_len) {
        printf("要刪除的位置或長度非法\n");
        return;
    }
    for (int i = pos; i < s_len; i ++) {
        s[i] = s[i+len];
    }
    s[s_len - len] = '\0';
}
//清除
void StrClear(SString s){
    s[0] = '\0';
}

//定位(在s串中從pos位置起尋找子串t,如果找到則返回第一個字符在s串的位置
int StrIndex(SString s,SString t,int pos){
    //標記s串的位置
    int i = pos;
    //標記t串的位置
    int j = 0;
    
    while (s[i]!='\0' && t[j]!='\0') {
        //判斷兩個字符是否相等
        if (s[i] == t[j]) {
            //相等,找到下一個位置
            i ++;
            j ++;
        }else{
            //不相等,s串回溯到與t串開始相等的位置,並且挪到下一位
            i = i-j+1;
            //t串回溯到起始位置
            j = 0;
        }
    }
    
    if (t[j] == '\0') {
        return i-j;
    }
    return -1;
}

//替換(用v替換在s中出現的所有子串t
void StrReplace(SString s,SString t,SString v){
    int s_len = StrLength(s);
    int t_len = StrLength(t);
    int v_len = StrLength(v);
    
    int index = -1;
    int pos = 0;
    
    while (pos < s_len) {
        //開始匹配
        index = StrIndex(s, t, pos);
        if (index == -1) {
            //不存在子串
            return;
        }
        //存在
        //1.先刪除t串
        StrDelete(s, index, t_len);
        //2.插入v串
        StrInsert(s, index, v);
        
        pos = index + v_len;
    }
}

Main.c

#include "SString.h"

int main(int argc, const char * argv[]) {
    
    SString s;
    InitString(s);
    SString t;
    InitString(t);
    
    //賦值
    char *str = "abcd";
    StrAssign(s, str);
    char *str2 = "xyz";
    StrAssign(t, str2);
    
    //比較
    int result = StrCompare(s,t);
    printf("compare:%d\n",result);
    
    //拷貝
    //StrCopy(t,s);
    //PrintString(t);
    
    //連接
    SString y;
    InitString(y);
    StrConcar2(y,s,t);
    PrintString(y);
    
    //求子串
    SString sub;
    InitString(sub);
    SubString(y, sub, 2, 3);
    PrintString(sub);
    
    //插入
    StrInsert(s, 1, t);
    PrintString(s);
    
    //刪除
    StrDelete(s, 1, 2);
    PrintString(s);
    
    //定位
    SString s1;
    InitString(s1);
    StrAssign(s1, "ababcababcab");
    
    SString s2;
    InitString(s2);
    StrAssign(s2, "abc");
    
    result = StrIndex(s1, s2, 0);
    printf("index:%d\n",result);
    
    //替換
    SString s3;
    InitString(s3);
    StrAssign(s3, "xy");
    
    StrReplace(s1, s2, s3);
    PrintString(s1);
    
    return 0;
}
發佈了36 篇原創文章 · 獲贊 18 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章