【问题标题】:Count how many times one string appears in another one计算一个字符串在另一个字符串中出现的次数
【发布时间】:2013-07-31 07:14:25
【问题描述】:

我已经尝试解决这个问题超过 3 个小时,但它不能 100% 起作用。请帮帮我。

问题: 创建一个接收两个字符串(A 和 B)的函数,并显示字符串 B 的单词在 A 中出现的次数,而不使用任何属于该库的函数。 例如:

  • 字符串 A:house houuse househousehous
  • 字符串 B:house

需要表明house这个词在字符串A中出现了3次。

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

void count_string_b_a(char *a, char *b){
   int i,j,k=0,size_a,size_b,equal=0,cont=0;
   size_a = strlen(a); 
   size_b = strlen(b);
   j=0;
   for(i = 0; i < size_b; i++){ 
     for(j = 0; j < size_a; j++){ 
        k=0;
        equal=0;
        for(k=0; k<size_b; k++){
           if(a[j+k] == b[i+k]) equal++;
           if(equal==size_b) cont++;
        } 
      } 
   }    
   printf("B %s appears %d times in A %s",b,cont,a);
}

int main(){
   int i;
   char a[40], b[10];
   scanf("%[^\n]s",&a); getchar();
   scanf("%[^\n]s",&b);
   count_string_b_a(a,b);
   getch();
 }

【问题讨论】:

  • 为什么不单步调试调试器中的代码,直到发现问题为止?
  • “不使用任何属于库的函数” 避免明确设计用于处理字符串的库函数的动机可能是什么?如果目标是了解这些函数的工作原理,您可以研究流行实现的源代码,但可以说能够使用它们比能够编写更重要i> 他们。
  • strlen() 不是标准库中的函数吗?我必须假设您被允许使用 I/O 功能......但也许要求是不要使用任何字符串搜索功能。 for (k = 0; ...) 循环之前的分配 k=0 是多余的。
  • 不使用调试器的一个原因是算法错误。通过思考比调试更好地解决这个问题。你有两条绳子,一根针和一个干草堆。对于大海捞针中的每个位置,您需要检查针是否与当前位置匹配。为此,您需要两个嵌套循环,而不是三个。
  • 我认为使用strstr比自己实现要容易,strstr是C语言的标准函数。

标签: c


【解决方案1】:

这是我对这个问题的简单解决方案,使用我在评论中建议的两个循环:

#include <stdio.h>

static
int count_occurrences(const char *haystack, const char *needle)
{
    int count = 0;
    for (int i = 0; haystack[i] != '\0'; i++)
    {
        int j;
        for (j = 0; needle[j] != '\0' && needle[j] == haystack[i+j]; j++)
            ;
        if (needle[j] == '\0')
            count++;
    }
    return count;
}

int main(void)
{
    {
    const char haystack[] = "house houuse househousehous";
    const char needle[] = "house";

    printf("Haystack <<%s>> vs needle <<%s>> = %d\n",
           haystack+0, needle+0, count_occurrences(haystack+0, needle+0));
    printf("Haystack <<%s>> vs needle <<%s>> = %d\n",
           haystack+1, needle+1, count_occurrences(haystack+1, needle+1));
    printf("Haystack <<%s>> vs needle <<%s>> = %d\n",
           haystack+1, needle+0, count_occurrences(haystack+1, needle+0));
    printf("Haystack <<%s>> vs needle <<%s>> = %d\n",
           haystack+1, needle+2, count_occurrences(haystack+1, needle+2));
    printf("Haystack <<%s>> vs needle <<%s>> = %d\n",
           haystack+6, needle+4, count_occurrences(haystack+6, needle+4));
    }

    {
    char *haystack = "pencil pencil penciil pen penc pe pen55cil penci9llppencil55 pencillip peplic pencilrpencilpe";
    char *needle = "pencil"; 
    printf("Haystack <<%s>> vs needle <<%s>> = %d\n",
           haystack+0, needle+0, count_occurrences(haystack+0, needle+0));
    }

    return 0;
}

注意出现次数的计算是如何与出现次数的打印分开进行的。报告出现次数的功能通常很有用;也打印数据的函数不太可能被重用。通常,将 I/O 与计算分开是一个好主意。

样本输出:

Haystack <<house houuse househousehous>> vs needle <<house>> = 3
Haystack <<ouse houuse househousehous>> vs needle <<ouse>> = 3
Haystack <<ouse houuse househousehous>> vs needle <<house>> = 2
Haystack <<ouse houuse househousehous>> vs needle <<use>> = 4
Haystack <<houuse househousehous>> vs needle <<e>> = 3
Haystack <<pencil pencil penciil pen penc pe pen55cil penci9llppencil55 pencillip peplic pencilrpencilpe>> vs needle <<pencil>> = 6

存在更好的算法

上面编码的算法是幼稚的;有许多更好的字符串匹配算法可用(例如,Boyer-Moore、Knuth-Morris-Pratt:参见Exact String Matching Algorithms 示例)。但是,它确实有效并且易于理解。对于示例字符串,这可能无关紧要;对于生物信息学和 DNA 片段匹配,这很重要。

【讨论】:

    【解决方案2】:
    if(equal==size_b) cont++;
    

    我认为需要:

    if(equal==size_b) {cont++;equal=0;}
    

    重置您的计数器以查找下一个匹配项。

    【讨论】:

      【解决方案3】:

      您可能应该read the scanf manual, carefully。事实上,这适用于所有标准库函数。 %[^\n]s 不是 %s 格式说明符的派生词;这是一个%[^\n],然后尝试读取(并丢弃)文字's' 字符。我建议通过从末尾删除s 来修复它,并在第一次使用任何C 标准库函数之前阅读手册。不要忘记检查返回值。

      在什么情况下你可以使用strlen,但不能使用strncmp?摆脱这个:

       for(j = 0; j < size_a; j++){ 
          k=0;
          equal=0;
          for(k=0; k<size_b; k++){
             if(a[j+k] == b[i+k]) equal++;
             if(equal==size_b) cont++;
          } 
        }  
      

      改为使用strncmp(&amp;a[i], b) 来确定相等性。如果您在本练习中无法使用任何标准库函数,请编写您自己的符合标准的strlenstrncmp,并将它们手动内联到您的函数中。然后你可能会意识到你的两个最里面的循环没有做他们应该做的事情。我建议你做的这个练习是浪费时间,因为它教你做错事。如果您必须重新发明 strncmpstrlen,请编写自己的 strncmpstrlen

      【讨论】:

        【解决方案4】:

        像这样使用strstr

        #include <stdio.h>
        #include <string.h>
        
        int count_string_b_a(const char *a, const char *b){
            int count = 0;
            size_t lenb = strlen(b);
            const char *p = a;
            while(NULL != (p = strstr(p, b))){
                ++count;
                p += lenb;
            }
            return count;
        }
        
        int main(){
            int cont;
            char a[40], b[10];
        
            printf("A>");
            scanf("%39[^\n]", a);
            printf("B>");
            scanf(" %9[^\n]", b);
            cont = count_string_b_a(a, b);
            printf("B \"%s\" appears %d times in A \"%s\"\n", b, cont, a);
        
            return 0;
        }
        

        【讨论】:

        • A:"howhowhow" B:"howhow"的情况,算1。应该是2?
        • 请注意“不使用任何属于库的函数”的要求。显然,I/O 函数来自“库”;我们可以合理地将其解释为“库中没有字符串操作函数”。
        【解决方案5】:

        这是我在计算一个单词在某个字符串中出现多少次的问题的方法。自定义的 mystrlen() 函数模仿 C 的 strlen 函数。您需要的唯一头文件是 stdio.h

        
        
            #include &ltstdio.h&gt
        
            int mystrlen(char *s)
            {
                int length = 0;
        
                while(*s != '\0')
                {
                    length++;
                    s++;
                }
                return length;
            }
        
            void match(char *haystack, char* needle)
            {
                    int j = 0;
        
                    int i,counter=0;
        
                    for(i = 0;i &lt mystrlen(haystack);i++)
                    {
        
                        if(haystack[i] == needle[j])
                        {
                            if(j == mystrlen(needle)-1)
                            {
                                counter++;
                                j = 0;
                                continue;
                            }       
                        }
                        else{
                            j = 0;
                            continue;
                        }
                        j++;
        
                    }
                    printf("%d the counter shows",counter);
            }
            int main()
            {
        
                char *haystack = "house houuse househousehous";
        
                char *needle = "house";
        
                match(haystack,needle);
        
        
            }
        
        

        【讨论】:

        • 您的解决方案几乎 100% 有效,我会尝试理解并找出错误。例如,如果我写: char *haystack = "pencil pencil penciil pen penc pe pen55cil penci9llppencil55 pencillip peplic pencilrpencilpe";和 char *needle = "铅笔";计数器会显示 5,应该是 6。非常感谢
        • pencil 代码的问题模式是ppencil。代码计算不正确。仅看到一个显式循环也令人惊讶——这使分析变得复杂。
        • 当您进入字符串的一部分时,代码会失败:在ppencilpepencilpenpencilpencpencilpencipencil 中寻找pencil 失败)。在for 循环控制中使用mystrlen() 不是一个好主意。这意味着外部循环在干草堆的长度上是二次的。循环内的mystrlen() 问题较少,但如果使用长度,则应在循环外预先计算它们。 (int haylen = strlen(haystack); int pinlen = strlen(needle); 什么的)。或者您可以修改代码以检查大海捞针和针头的空字节。
        猜你喜欢
        • 2011-07-01
        • 2011-07-13
        • 1970-01-01
        • 2014-11-14
        • 1970-01-01
        • 2014-05-26
        • 1970-01-01
        • 2015-10-08
        • 1970-01-01
        相关资源
        最近更新 更多