简单的 字符串比较函数 易懂 复杂度

本文详细介绍了三种高效的字符串匹配算法,包括简单循环匹配、改进的KMP算法和Boyer-Moore算法,分析了它们的时间复杂度,并讨论了算法在实际应用中的优劣。此外,还提供了代码实现和复杂度分析,帮助读者理解如何在不同场景下选择合适的算法。

1.简单的字符串匹配函数

简单的字符串匹配很简单,就是一个两重循环。

算发一:

#include<stdio.h>

#include<string.h>

 

char s[51],t[11];

int next[11];

int cnt[11];

 

void index(char*s,char *t,int pos)

{

       int i,j,k;

    int x = 0;

    int len1 = strlen(s);

    int len2 = strlen(t);

 

    for(i=pos;i<len1;i++)

    {

        k = i;

        for(j=0;j<len2;j++)

        {           

            if(s[k++]!=t[j])

                break;

        }

        if(j>=len2)

        {

            cnt[x++] = i;

        }

    }

}

 

int main(void)

{

    memset(cnt,-1,11*sizeof(int));

    gets(s);

    gets(t);

    int pos;

    scanf("%d",&pos);

       index(s,t,pos);

    for(int i=0;cnt[i]!=-1;i++)

    {

        printf("    %d",cnt[i]);

    }

return 0;

}

下面分析其复杂度:  

除了在index2,index4,index6,index10四处字符串比较了多次外,在其他地方字符串只比较了一次,总共的比较次数为(n-m+1)+(m-1)+others,others为红色的部分,也就是说其复杂度接近O(n+m)。

假设主串的长度为n,模式串的长度为m,在最坏情况下,对于主串(n-m+1)中的每一个字符,都要和模式中的字符匹配m次,后面的每个字符的匹配次数总共为(1+2+…+(m-1))=m(m-1)/2,则总的匹配次数为(n-m+1)*m+ m(m-1)/2,也即算发复杂度为O(n*m)。

 

  上面这种方法比较的直观和简单,但是复杂度却很高,效率低下,很难应用于实际,下面有个改进的版本,功能是输出第一次出现子串的索引。

算发二:

#include <stdio.h>

#include <string.h>

 

char s[51],t[11];

int next[11];

 

int index(char *s,char *t,int pos)

{

    int i =pos-1;

    int j = 0;

    int len1=  strlen(s);

    int len2 =strlen(t);

 

   while(i<len1&&j<len2)

    {

       if(s[i]==t[j])

        {

            i++;

            j++;

        }

        else

        {

            i -=j-1;

            j =0;

        }

    }

       if(j>=len2)

    {

       returni-len2;

    }

    else

       return-1;

}

 

int main(void)

{

    gets(s);

    gets(t);

    int pos;

   scanf("%d",&pos);

 

    int no =index(s,t,pos);

    if(no>0)

       printf("String s contains substring t at index of %d~~\n",no);

    else

       printf("String s does not contain substring t~~\n");

    return 0;

}

下面让我们来分析其复杂度,

除了在index2,index4,index6,index10四处字符串比较了多次外,在其他地方字符串只比较了一次,假设最终查找到子串的位置为index,在一次查找过程中,最终的比较次数为(index+len2-1)+others,这个others就是之前有过的多次比较的结果。其复杂度接近O(n+m)。在最坏的情况下,其复杂度也是O(n*m)。

算发三:

#include <stdio.h>

#include <string.h>

 

char s[51],t[11];

int next[11];

int cnt[11];

 

void index(char *s,char *t,int pos)

{

   intx=0;

   int i = pos-1;

   int j = 0;

   int len1 =  strlen(s);

   int len2 = strlen(t);

 

   for(i=pos-1;i<len1;)

    {

       while(i<len1&&j<len2)

       {

           if(s[i]==t[j])

           {

                i++;

                j++;

           }

           else

           {

               i -= j-1;

               j = 0;

           }

       }

          if(j>=len2)

       {

          cnt[x++] = i-len2;

             i -= len2-1;

             j = 0;

       }

   }   

}

 

int main(void)

{

   memset(cnt,-1,11*sizeof(int));

   gets(s);

   gets(t);

   int pos;

   scanf("%d",&pos);

 

   index(s,t,pos);

  

   for(int i=0;cnt[i]!=-1;i++)

    {

       printf("    %d",cnt[i]);

    }

   printf("\n");

   return 0;

}

<think>好的,用户现在想了解C++中计算字符串长度的函数。根据用户提供的引用内容,我需要先整理一下相关的信息,确保回答准确。首先,用户提到的引用[1]和[2]提到C++中的size()和length()函数,这两个是string类的成员函数,作用相同。引用[3]和[4]则讨论了C语言的strlen函数以及sizeof操作符的区别,还有注意事项。 用户的上一次问题是关于哈夫曼树的构建和编码生成,现在转向了C++字符串长度的问题,这可能是在学习过程中遇到了不同知识点的问题。需要确认用户的需求是单纯询问有哪些函数,还是想了解它们之间的区别和使用场景。 根据引用内容,需要明确区分不同函数的使用对象:size()和length()用于C++的string类,而strlen用于C风格的字符数组。同时,sizeof是操作符,用于计算变量所占内存大小,包括'\0',而其他函数不包括。此外,用户可能容易混淆这些函数,特别是在处理字符数组时,如果在函数内部使用sizeof,可能会得到指针的大小而不是字符串长度,这点需要特别强调。 还要注意用户可能的误区,比如认为sizeof可以正确获取字符串长度,但实际上在字符数组作为参数传递时,sizeof会失效。同时,strlen需要遇到'\0'才能正确计算长度,如果字符数组没有正确终止,会导致未定义行为。 需要结构清晰地分点说明每个函数的特点,对比它们的不同,并给出示例代码帮助理解。最后,根据用户之前的互动习惯,可能需要生成相关问题来进一步巩固知识点,比如不同函数的区别、如何处理不含'\0'的情况等。 总结回答结构应该是:先介绍各个函数,分点说明适用场景和注意事项,对比它们的不同,然后给出示例代码,最后附上相关问题。确保回答准确、易懂,并覆盖用户可能存在的疑问点。</think>根据提供的参考资料,C++中计算字符串长度的主要方法有以下四种,根据不同的字符串类型需要选择对应的函数: ### 一、根据字符串类型选择函数 1. **`size()`与`length()`**(面向`std::string`类) - 二者完全等价,返回**有效字符个数**(不包含结尾的`\0`) - 示例: ```cpp std::string str = "Hello 世界"; cout << str.size(); // 输出 8(5字母+1空格+2汉字) cout << str.length(); // 同上 ``` 2. **`strlen()`**(面向C风格字符数组) - 需包含头文件`<cstring>` - 计算直到`\0`前的**有效字符数** - 示例: ```cpp const char* ch = "Perseverance"; cout << strlen(ch); // 输出 12(注意中文可能需要特殊处理) ``` 3. **`sizeof()`运算符**(特殊场景使用) - 计算**内存占用总字节数**(包含`\0`) - 对字符数组直接使用时: ```cpp char arr[] = "Hello"; cout << sizeof(arr); // 输出 6(5字符+1个\0) ``` - 注意:当字符数组作为函数参数传递时,`sizeof()`会退化为指针大小[^4] ### 二、核心区别对比表 | 函数/运算符 | 适用对象 | 包含`\0`? | 时间复杂度 | 常见错误场景 | |------------------|------------------|------------|------------|----------------------| | `size()`/`length()` | `std::string` | 否 | O(1) | 用于非string对象 | | `strlen()` | `char[]/char*` | 否 | O(n) | 未正确终止的字符数组 | | `sizeof()` | 所有变量/类型 | 是 | 编译时确定 | 误判动态分配内存大小 | ### 三、代码示例对比 ```cpp #include <iostream> #include <cstring> #include <string> using namespace std; int main() { // 场景1:标准stringstring str = "π≈3.14"; // Unicode字符 cout << str.size(); // 输出 6(π占2字节,数字和符号占4字节) // 场景2:C风格字符串 const char* ch = "ABC\0DEF"; // 含隐藏的\0 cout << strlen(ch); // 输出3(遇到\0提前终止) // 场景3:字符数组 char arr[] = {'H','i','\0','!'}; cout << sizeof(arr); // 输出4(包含所有元素) cout << strlen(arr); // 输出2(到第一个\0截止) } ``` ### 四、特殊注意事项 1. **中文处理**:`strlen()`按字节计算,一个UTF-8中文字符占3字节 ```cpp const char* ch = "中文"; cout << strlen(ch); // 输出6(非字符数!) cout << string(ch).size(); // 输出2(正确字符计数) ``` 2. **动态内存**:`sizeof()`无法获取动态分配数组的长度 ```cpp char* p = new char[20]; cout << sizeof(p); // 输出指针大小(如8字节),非实际内存 ``` 3. **安全替代方案**:推荐使用`std::string_view`(C++17+) ```cpp string_view sv = "Safe length check"; cout << sv.size(); // 避免拷贝且支持非空终止字符串 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值