第四章 串

序言.字符串的创建

//使用字符数组来存储字符串
char s[5] = {'a', 'b', 'c', 'd', '\0'}; //用花括号来初始化字符数组,并且留出一个空间给'\0'字符
char s[5] = "abcd"; //也可以用双引号来初始化字符数组,编译器会自动在末尾添加'\0'字符

//使用指针常量来存储字符串
char *s = "abcd"; //用双引号来定义一个指针常量,指向一个字符串字面量,这个字符串是存储在常量区的,不能被修改

//使用指针变量来存储字符串
char *s = (char *)malloc(5); //用malloc函数动态分配内存空间,返回一个指针变量,指向一个可读写的字符串空间
if (s == NULL) {
  printf("内存分配失败\n");
  exit(1);
}
strcpy(s, "abcd"); //用strcpy函数复制字符串到s指向的空间

//使用string结构体来封装字符串和长度
string *s = (string *)malloc(sizeof(string)); //用malloc函数动态分配内存空间,返回一个指针变量,指向一个string结构体
if (s == NULL) {
  printf("内存分配失败\n");
  exit(1);
}
s->data = (char *)malloc(5); //用malloc函数动态分配内存空间,返回一个指针变量,指向一个可读写的字符串空间
if (s->data == NULL) {
  printf("内存分配失败\n");
  exit(1);
}
strcpy(s->data, "abcd"); //用strcpy函数复制字符串到s->data指向的空间
s->length = 4; //设置字符串的长度

c语言字符串常见函数

//--------------https://www.runoob.com/cprogramming/c-strings.html
strcpy(s1, s2);
复制字符串 s2 到字符串 s1。

strcat(s1, s2);
连接字符串 s2 到字符串 s1 的末尾。

strlen(s1);
返回字符串 s1 的长度。

strcmp(s1, s2);
如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回小于 0;如果 s1>s2 则返回大于 0strchr(s1, ch);
返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。

strstr(s1, s2);
返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。

1.顺序存储

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 255

typedef struct{
    char ch[MAXSIZE+1];
    int length;
}sstring;


//1.赋值          将字符串s2赋值给s1
void StrAssign(sstring *s1,char* s2){
    int i=0;
    while(s2[i]!='\0'){
        s1->ch[i] =s2[i];
        i++;
    }
    s1->length =i;
}

//2.复制      将串s2复制给s1
void StrCopy(sstring *s1,sstring* s2){
    for(int i=0;i<=s2->length;i++){
        s1->ch[i] =s2->ch[i];
    }
    s1->length = s2->length;
}

//3.判空      判定串s是否为空
int StrEmpty(sstring s){
    return s.length==0;
}

//4.求串长     求串s长度
int StrLength(sstring s){
    return s.length;
}

//5.清空串     清空串数据,逻辑删除
void ClearString(sstring * s){
    s->length=0;
    s->ch[0]='\0';
}

//6.销毁串 销毁串,物理删除
void DestroyString(sstring *s){
    s->length =0;
    free(s);
}

//7.串链接
    //方式一 链接不产生新串
void ConCat1(sstring *s1,sstring s2){
    int i=0;
    while(i<s2.length){
        s1->ch[s1->length+i]=s2.ch[i];
        i++;
    }
    s1->length+=s2.length;
    s1->ch[s1->length]='\0';  //末尾添加空字符
}
    //方式二 王道书上的
void ConCat2(sstring*s3,sstring s1,sstring s2){
    int i=0;
    for(i=0;i<s1.length;i++){
        s3->ch[i]=s1.ch[i];
    }
    for(int j=0;j<s2.length;j++){
        s3->ch[i+j]=s2.ch[j];
    }
    s3->length =s1.length+s2.length;
    s3->ch[s3->length] = '\0';
}


//8.求子串
int SubString(sstring *sub,sstring s,int pos,int len){
    if(pos<1 || pos+len-1 >s.length)
        return 0; //越界
    for(int i=0;i<len;i++){
        sub->ch[i] =s.ch[pos+i-1];
    }
    sub->length =len;
    sub->ch[len]=  '\0';
    return 1;
}


//9.比较串
int StrCompre(sstring s1,sstring s2){
    for(int i=1;i<=s1.length && i<=s2.length;i++){
        if(s1.ch[i]!=s2.ch[i])
            return s1.ch[i]-s2.ch[i];
    }
    return s1.length-s2.length;
}

//10.定位模式串在串中首次出现的下标,可能匹配不成功
int Index(sstring s1,sstring s2){   //用s1主串匹配s2模式串
    int i=1,j=1;
    while(i<= s1.length && j<=s2.length){
        if(s1.ch[i] == s2.ch[j]){
            i++; j++;
        }
        else{
            i=i-j+1;   //回溯,i-j等于这一次开始匹配字符的前一个,-2等于下一个
            j=1;
        }
    }
    if(j==s2.length)
        return i-j+1;
    else
        return 0;
}



int main()
{
    sstring s1,s2,s3,s4;
    StrAssign(&s1,"eabcd");
    StrCopy(&s2,&s1);
    int empty=StrEmpty(s2);
    int length=StrLength(s2);
    ConCat2(&s3,s1,s2);
    SubString(&s4,s3,1,3);

    printf("%s \n%s \n%s \n%s \n",s1.ch,s2.ch,s3.ch,s4.ch);
    int compare = StrCompre(s3,s4);
    int id =Index(s1,s2);
    ClearString(&s2);
    printf("s2判空:%d  s2长度:%d s3和s4比较:%d s2在s1首次出现id:%d",empty,length,compare,id);
    DestroyString(&s3);
    return 0;
}

2.链式存储

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

typedef struct {
    char *ch;     // 指向动态分配的存储空间
    int length;   // 串的长度
} sstring;

// 1. 赋值,将字符串s2赋值给s1
void StrAssign(sstring *s1, char *s2) {
    s1->ch = (char *)malloc((strlen(s2) + 1) * sizeof(char)); // 分配足够的内存
    if (s1->ch == NULL) {
        exit(1); // 内存分配失败
    }
    strcpy(s1->ch, s2);  // 复制字符串
    s1->length = strlen(s2); // 记录长度
}

// 2. 复制,将串s2复制给s1
void StrCopy(sstring *s1, sstring *s2) {
    s1->ch = (char *)malloc((s2->length + 1) * sizeof(char)); // 分配足够的内存
    if (s1->ch == NULL) {
        exit(1); // 内存分配失败
    }
    strcpy(s1->ch, s2->ch);  // 复制字符串
    s1->length = s2->length; // 记录长度
}

// 3. 判空,判定串s是否为空
int StrEmpty(sstring *s) {
    return s->length == 0;
}

// 4. 求串长,求串s长度
int StrLength(sstring *s) {
    return s->length;
}

// 5. 清空串,清空串数据,逻辑删除
void ClearString(sstring *s) {
    s->ch = NULL;
    s->length = 0;
}

// 6. 销毁串,销毁串,物理删除
void DestroyString(sstring *s) {
    free(s->ch);  // 释放动态分配的内存
    s->ch = NULL;
    s->length = 0;
}

// 7. 串链接
void Concat(sstring *s3, sstring *s1, sstring *s2) {
    s3->ch = (char *)malloc((s1->length + s2->length + 1) * sizeof(char)); // 分配足够的内存
    if (s3->ch == NULL) {
        exit(1); // 内存分配失败
    }
    strcpy(s3->ch, s1->ch);  // 复制 s1 的内容
    strcat(s3->ch, s2->ch);  // 连接 s2 的内容
    s3->length = s1->length + s2->length; // 记录长度
}

// 8. 求子串
/*strncpy: C 库函数 char *strncpy(char *dest, const char *src, size_t n) 把 src 所指向的字符串复制到 dest,
最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。
*/
int SubString(sstring *sub, sstring *s, int pos, int len) {
    if (pos < 1 || pos > s->length || len < 0 || pos + len - 1 > s->length) {
        return 0; // 越界
    }
    sub->ch = (char *)malloc((len + 1) * sizeof(char)); // 分配足够的内存
    if (sub->ch == NULL) {
        exit(1); // 内存分配失败
    }
    strncpy(sub->ch, s->ch + pos - 1, len);  // 复制子串
    sub->ch[len] = '\0'; // 添加字符串结束符
    sub->length = len; // 记录长度
    return 1;
}

// 9. 比较串
int StrCompare(sstring *s1, sstring *s2) {
    return strcmp(s1->ch, s2->ch);
}

// 10. 定位模式串在串中首次出现的下标,可能匹配不成功

/*strstr:C 库函数 char *strstr(const char *haystack, const char *needle)
在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。
或者返回0表示未找到匹配
*/
int Index(sstring *s1, sstring *s2) {
    char *pos = strstr(s1->ch, s2->ch);
    if (pos) {
        return pos - s1->ch + 1; // 返回下标
    } else {
        return 0; // 未找到匹配
    }
}

int main() {
    sstring s1, s2, s3, s4;
    StrAssign(&s1, "abcd");
    StrCopy(&s2, &s1);
    int empty = StrEmpty(&s2);
    int length = StrLength(&s2);
    Concat(&s3, &s1, &s2);
    SubString(&s4, &s3, 1, 3);

    // 打印字符串
    printf("%s\n%s\n%s\n%s\n", s1.ch, s2.ch, s3.ch, s4.ch);

    int compare = StrCompare(&s3, &s4);
    int id = Index(&s1, &s2);
    printf("s2判空:%d  s2长度:%d s3和s4比较:%d  s2在s1中的位置:%d\n", empty, length, compare, id);
    ClearString(&s2);
    // 销毁字符串
    DestroyString(&s1);
    DestroyString(&s2);
    DestroyString(&s3);
    DestroyString(&s4);
    return 0;
}

3.简单模式匹配

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

int Index(char *mainString, char *pattern) {
    int len1 = strlen(mainString);
    int len2 = strlen(pattern);

    for (int i = 0; i <= len1 - len2; i++) {
        int j;
        for (j = 0; j < len2; j++) {
            if (mainString[i + j] != pattern[j]) {
                break;
            }
        }
        if (j == len2) {
            return i; // 匹配成功,返回匹配位置
        }
    }

    return -1; // 未找到匹配
}

int main() {
    char mainString[] = "ABABCABCACBAB";
    char pattern[] = "ABCAC";

    int result = Index(mainString, pattern);

    if (result != -1) {
        printf("Pattern found at position: %d\n", result);
    } else {
        printf("Pattern not found.\n");
    }

    return 0;
}

4.kmp算法

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
构建部分匹配表,用于避免不必要的字符比较。
使用两个指针 i 和 j 分别指向主串和模式串。
在匹配时,如果字符匹配,同时移动 i 和 j。
如果字符不匹配,根据部分匹配表调整 j,或者移动 i。
如果成功匹配整个模式串,返回匹配的位置。
*/


// 构建部分匹配表
void Index(char *pattern, int *table) {
    int len = strlen(pattern);
    int j = 0;

    table[0] = 0;

    for (int i = 1; i < len; i++) {
        while (j > 0 && pattern[i] != pattern[j]) {
            j = table[j - 1];
        }

        if (pattern[i] == pattern[j]) {
            j++;
        }
        table[i] = j;
    }
}

// KMP算法
int KMPPatternMatch(char *mainString, char *pattern) {
    int len1 = strlen(mainString);
    int len2 = strlen(pattern);
    int *table = (int *)malloc(len2 * sizeof(int));

    BuildPartialMatchTable(pattern, table);

    int i = 0, j = 0;
    while (i < len1) {
        if (pattern[j] == mainString[i]) {
            i++;
            j++;
        }

        if (j == len2) {
            free(table);
            return i - j; // 匹配成功,返回匹配位置
        }

        if (i < len1 && pattern[j] != mainString[i]) {
            if (j != 0) {
                j = table[j - 1];
            } else {
                i++;
            }
        }
    }
    free(table);
    return -1; // 未找到匹配
}

int main() {
    char mainString[] = "ABABCABCACBAB";
    char pattern[] = "ABCAC";
    int result = Index(mainString, pattern);
    if (result != -1) {
        printf("Pattern found at position: %d\n", result);
    } else {
        printf("Pattern not found.\n");
    }
    return 0;
}

5.优化的kmp算法

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
构建Next数组,用于跳过不必要的字符比较。
使用两个指针 i 和 j 分别指向主串和模式串。
在匹配时,如果字符匹配,同时移动 i 和 j。
如果字符不匹配,根据Next数组调整 j,或者移动 i。
如果成功匹配整个模式串,返回匹配的位置。
这个优化的KMP算法在大多数情况下具有更好的性能,特别是在处理较长的主串和模式串时。它通过避免不必要的字符比较来提高匹配速度。
*/


// 构建Next数组
void BuildNextArray(char *pattern, int *next) {
    int len = strlen(pattern);
    int j = -1;
    next[0] = -1;

    for (int i = 1; i < len; i++) {
        while (j >= 0 && pattern[i] != pattern[j + 1]) {
            j = next[j];
        }

        if (pattern[i] == pattern[j + 1]) {
            j++;
        }

        next[i] = j;
    }
}

// 优化的KMP算法
int Index(char *mainString, char *pattern) {
    int len1 = strlen(mainString);
    int len2 = strlen(pattern);
    int *next = (int *)malloc(len2 * sizeof(int));

    BuildNextArray(pattern, next);

    int j = -1;
    for (int i = 0; i < len1; i++) {
        while (j >= 0 && mainString[i] != pattern[j + 1]) {
            j = next[j];
        }

        if (mainString[i] == pattern[j + 1]) {
            j++;
        }

        if (j == len2 - 1) {
            free(next);
            return i - j; // 匹配成功,返回匹配位置
        }
    }

    free(next);
    return -1; // 未找到匹配
}

int main() {
    char mainString[] = "ABABCABCACBAB";
    char pattern[] = "ABCAC";

    int result = Index(mainString, pattern);

    if (result != -1) {
        printf("Pattern found at position: %d\n", result);
    } else {
        printf("Pattern not found.\n");
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值