【データ構造学習記録10】-文字列

1.簡単な紹介

1はじめに

「文字列データを扱う場合、整数や浮動小数点数を扱うよりもはるかに複雑であり、アプリケーションの種類によって、使用される文字列の特性が異なります。したがって、文字列データを効果的に実装する必要があります。 。それに対処するには、特定の状況に応じて適切なストレージ構造を使用する必要があります。」これがこの章の意味だと思います。

2.自然の定義

ゼロまたは複数の文字から成る有限のシーケンスであり、一般的に記録
S = 0 1つの2 ··· Nを(N> = 0)は
s、単一引用符で囲まれた文字列は、文字列の名前であります文字列の値;文字またはその他の文字を使用できます。文字列の文字数は、文字列nの長さ呼ばれます。ゼロ文字の文字列はと呼ばれ空串ます。
文字列では、任意の数の連続する文字で構成される単語のシーケンスは子串文字列と呼ばれ主串部分文字列を含む文字列はそれに応じて呼び出されます。通常、シーケンス内の文字のシーケンス番号は文字列内の文字列と呼ばれます位置
例:
s = 'kanna'
b = 'anna'
c = 'kan'
この場合、文字列bとcはaの部分文字列であり、s、b、cの長さはそれぞれ5、4、3です。sのbの位置は2で、sのcの位置は1です。

2.実現する

1.簡単な説明文字列

基本的な增删改查関数に加えて、いくつかの関数を考える必要があります。文字列の長さ、指定された位置と長さの文字列を返す、文字列を検索する...

2.文字列の構造

この本には、文字列を表すために配列を使用する別の構造がありますが、それは堆分配(malloc)私たちのもの似ているので、後者に焦点を当てます。
文字列構造には、次の2つの部分を使用します用于储存文本的基址区 长度
ここに画像の説明を挿入

3.文字列の初期化

文字列は、C言語スタイルの文字列配列または文字列リテラル値で初期化できます。C言語スタイルの文字列には注目すべき機能\0があります。つまり、文字列の最後に文字列の終わりを示す機能があります。次に、便利な方法を使用して文字列の長さを取得し、1つずつ割り当ててなりすまし文字列を初期化します。

4.文字列の「追加」

もちろん、文字列を追加することは、文字列1を変更せずに、文字列2の内容を文字列1の後ろに接続し、文字列1の長さを文字列2の長さに追加することと同じです。
ここに画像の説明を挿入

5.文字列の比較

最初に2つの弦の長さを比較します。長さが異なる場合は、2つの弦が異なっている必要があります。2つの文字列の長さが同じである場合は、最初の文字、2番目の文字の比較を開始します...最初の文字が同じでなくなるまで、最後に異なる文字がない場合は等しくありません、2つの文字列が同じであることを意味します。

6.文字列の破壊

文字列は動的に生成されるため、直接freeドロップするだけです。

7.文字列を返す

それでも移動し指针、順番に割り当てられた文字列を返します。

8.文字列を検索します

文字列を見つける方法はたくさんありますが、これが時間計算量n*mレベルの検索アルゴリズムです。最適化については、次のセクションの内容です。ここでの基本的なアルゴリズムは次のとおりです。
選択ポインタaと一致ポインタbの2つのポインタがあります。
ポインタを選択して最初に1つの位置を移動し、次に一致するポインタが移動を開始します。一致するポインタが文字列の長さを移動し、それらがすべて同じである場合、選択したポインタaの位置は文字列が移動する位置です。開始します。一致するポインタが文字列の長さより前の位置に移動した場合は、一致が失敗したことを意味し、ポインタa ++、b = aを選択して、bポインタを再度移動します。
ここに画像の説明を挿入

3.コード

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

#define     OK          1
#define     ERROR       0

typedef struct sstring{
    
    
    char *ch;
    int len;
}sstring;

sstring* StringInit(char* str);
int StringShow(sstring *str);
int StringConcat(sstring* str1, sstring* str2);
int StringCompare(sstring *str1, sstring *str2);
sstring *StringGet(sstring *str, int index, int len);
int StringFind(sstring *bstr, sstring *mstr);

int main()
{
    
    
    // 主函数随便改
    sstring *test1 = StringInit("bbcd");
    sstring *test2 = StringInit("bcd");
    //StringConcat(test1, test2);
    //printf("%d", StringCompare(test1, test2));
    //StringShow(StringGet(test2,0,3));
    printf("%d", StringFind(test1,test2));
    return 0;
}

sstring* StringInit(char* ss)
{
    
    
    int lenth = 0;
    //首先创建要返回的
    sstring *str = (sstring*)malloc(sizeof(sstring));
    
    //动态生成失败,直接退出
    if (str == NULL) exit(1);
    //如果传入的是空字符串,我们就返回一个空的字符串
    if (ss == NULL)
    {
    
    
        str->ch = NULL;
        str->len = 0;
        return str;
    }
    // 通过依次遍历,获得传入字符串中,非/0部分长度。
    while(*(ss + lenth) != '\0')
    {
    
    
        ++lenth;
    }
    // 修改我们字符串的长度和动态分配它的储存空间
    str->len = lenth;
    str->ch = (char*)malloc(sizeof(char)*lenth);
    --lenth;
    // 通过遍历,将C语言字符串的内容,复制到我们的新字符串中
    while(lenth >= 0)
    {
    
    
        *(str->ch+lenth) = *(ss+lenth);
        --lenth;
    }

    return str;
}

int StringShow(sstring *str)
{
    
    
    int ptr = 0;
    printf("the string len is %d context is: ", str->len);
    while(ptr < str->len)
    {
    
    
        printf("%c", *(str->ch + ptr));
        ++ptr;
    }
    printf("\n");
    return OK;
}

int StringConcat(sstring* str1, sstring* str2)
{
    
    
    sstring* stringNew = NULL;
    int ptr = 0;
    // 如果两个串的长度都是0,那就直接返回即可
    if (str1->len + str2->len == 0) 
    {
    
    
        return OK;
    }
    // 否则就先生成我们的新串,修改长度与内容
    stringNew = (sstring*)malloc(sizeof(sstring));
    stringNew->ch = (char*)malloc(sizeof(char)*(str1->len+str2->len));
    stringNew->len = str1->len+str2->len;
    // 通过循环,将str1的值写入新串
    for(;ptr < str1->len; ++ptr)
    {
    
    
        *(stringNew->ch+ptr) = *(str1->ch+ptr);
    
    }
    // 在str1写入新串的基础上,向新串写入str2
    for(ptr = 0;ptr < str2->len; ++ptr)
    {
    
    
        *(stringNew->ch+ptr+str1->len) = *(str2->ch+ptr);
    }

    // 然后这里优点坑,因为传递过来的指针是形参,并不是引用
    // 所以 我们只能把新串的值赋值给原来的串
    // 此时,传入函数字符串的地址没变,但是len变了, ch的地址变了
    *str1 = *stringNew;
    return OK;
}

int StringCompare(sstring *str1, sstring *str2)
{
    
    
    int i = 0;

    // 长度都不一样,所以通过长度,反应关系
    if (str1->len > str2->len)
    {
    
    
        return 1;
    }
    else if (str1->len < str2->len)
    {
    
    
        return -1;
    }
    else
    {
    
    
        // 长度一样了,只有依次对比了
        for (; i < str1->len; ++i)
        {
    
    
            // 只要有一个字符不一样,那就根据ascii的关系去返回大小关系
            if (*(str1->ch+i) < *(str2->ch+i))
            {
    
    
                return -1;
            }
            else if (*(str1->ch+i) > *(str2->ch+i))
            {
    
    
                return 1;
            }
        }
        // 循环完了也没有找到不同,所以它俩是一样的
        return 0;
    }
}

sstring *StringGet(sstring *str, int index, int len)
{
    
    
    sstring *rstr = NULL;
    int i = 0;

    // 如果目标串的长度小于我们要求的长度,所以直接返回空的
    if (str->len < index+len)
    {
    
    
        return NULL;
    }
    else
    {
    
    
        // 动态生成我们的返回串
        rstr = (sstring *)malloc(sizeof(sstring));
        rstr->ch = (char *)malloc(sizeof(char)*str->len);
        rstr->len = len;
        // 然后把目标串里的值复制到我们的返回串里
        for (i = 0; i < len; ++i)
        {
    
    
            *(rstr->ch+i) = *(str->ch+index+i);
        }
        return rstr;
    }
    
}

int StringFind(sstring *bstr, sstring *mstr)
{
    
    
    int fptr = 0, lptr = 0;
    int mark = 0;

    // 如果我们要查找的串的长度大于了目标串,那肯定找不到的,直接返回-1
    if (bstr->len < mstr->len)
    {
    
    
        return -1;
    }
    // lptr是指向 我们目标串的开始指针
    // 它只需要从0遍历到(目标串长度-要查找的串的长度)就行了
    for (;lptr <= (bstr->len-mstr->len); ++lptr)
    {
    
    
        // mark是标记位,如果有不同,那就是1 没有不同就还是0
        mark = 0;
        // 这个是查找指针,我们要对比的内容因该是lptr+fptr
        // 它的范围是 0到查找串的长度-1
        for (fptr = 0; fptr < mstr->len; ++fptr)
        {
    
    
            // 对比的内容是 lptr+fptr
            if (*(bstr->ch+lptr+fptr) != *(mstr->ch+fptr))
            {
    
    
                // 有不同,更新标识,并跳出这一轮 fptr的遍历
                mark = 1;
                break;
            } 
        }
        // fptr遍历完了,都还没有不同的,说明找到了
        if (mark == 0)
        {
    
    
            // 那么就因该返回我们lptr的起始位置
            return lptr;
        }
    }
    // 查遍了整个串都没找到,那就只能返回 -1了
    return -1;
}

おすすめ

転載: blog.csdn.net/u011017694/article/details/109531835