【问题标题】:Count occurences of a subarray in a bigger array using recursion使用递归计算更大数组中子数组的出现次数
【发布时间】:2016-07-10 09:30:39
【问题描述】:

我必须编写一个递归函数来计算短数组 s2 在更大的数组 s1 中出现的次数而不重叠。我可以使用多个可以帮助我的函数,但它们必须都是递归函数。例如:

#define n 10
#define p 2

s1[n]={0,2,3,23,54,1,8,23,54,1}
s2[p]={23,54}
OUTPUT: 2 (we see s2 two times in s1)

我想写一个递归函数,告诉我是否至少有一次出现,然后在另一个计算出现次数的递归函数中使用这个函数。所以这就是我写的:

//Initially pos1=0 and pos2=0

int find(int *s1,int *s2,int pos1,int pos2){
if(n-pos1<p-pos2)
    return 0;

if(*(s1+pos1)==*(s2+pos2)){
    if(pos2==p-1)
        return pos1;
    else{
        if(find(s1,s2,pos1+1,pos2+1))
            return pos1;
    }
}
return find(s1,s2,pos1+1,0);
}

然后我写了第二个应该计算出现次数的递归函数:

 // Initially occ(s1,s2,0);
 int occ(int *s1,int *s2,int memo){
    if(memo==n){ //end of s1
        return 0;
    }
    else{
        if(find(s1+memo,s2,memo,0))
    return 1+occ(s1+memo,s2,memo+p);
    }
}

其背后的想法是验证是否至少出现了一次,如果有发生则计数,然后对 s1 的剩余部分重做验证,直到结束。

问题是第二个函数的代码根本不起作用,我找不到修复它的方法。

那么,如何使用上面编写的函数 find() 编写第二个递归函数来计算出现次数?

【问题讨论】:

  • 为什么第二个函数的代码根本不起作用你调试了吗?
  • 是的,我尝试了很多次,每次都失败,我发布的代码是我的最终结果。我不知道为什么会失败
  • 如果 s1[n]={0,0,0,3,4,0,0,0,3,4,0,0,0,3,4,0,0 有效,0,3,4};和 s2[p]={3,4}。实际上输出为 4。但如果 s2[p]={0,0} 输出为 0,这是不正确的。
  • 当使用你上面提到的代码并打印函数的结果很好:printf("%d",find(s1,s2,0,0)); 结果我得到 3,你确定你发布了你的最后一个版本吗?
  • 是的,我没有写其他任何东西,但是最终结果由 occ() 给出,函数 find 应该返回第一次出现的位置。

标签: c arrays recursion count find-occurrences


【解决方案1】:

来自OP's comment

如果s1[n]={0,0,0,3,4,0,0,0,3,4,0,0,0,3,4,0,0,0,3,4};s2[p]={3,4} 有效。实际上输出是 4。但是如果 s2[p]={0,0} 输出是 0 这是不正确的。

  • 这是因为,当s2={0,0} find() 函数返回 pos1 = 0 因为子集出现在最开始因此在 occ() 函数中 if(find( s1+memo,s2,memo,0)) 评估为 false 并终止函数而不返回任何值,这会调用 未定义的行为

  • 这可以通过返回除0 之外的任何数字来避免,但它不能是数组s1 中的任何有效位置值。

  • 由于位置不能为负数,所以我选择了-1


查看以下代码以了解如何避免它:

#include <stdio.h>

#define n 10
#define p 2

int s1[n]={0,2,3,23,54,1,8,23,54,1};
int s2[p]={23,54};

//find function
int find(int* s1,int* s2,int pos) //only used `pos` instead of `pos1`, removed `pos2`
{
    if(pos > n-2)
    {
        return -1; //returns `-1` upon reaching the end of the code
    }

    if(*(s1+pos) == *(s2+0)) //check at `s1+pos`
    {
        if(*(s1+(pos+1)) == *(s2+1)) //check next element `s1+pos+1`
        {
            return pos; //if both true return `pos`
        }

        else
        {
            return find(s1,s2,pos+1); //else recursively find in the rest of the array
        }
    }

    return find(s1,s2,pos+1); // recursively find in the rest of the array
}


//occurence function    
int occ(int *s1, int *s2,int memo)
{
    if(memo == -1) //if end of the array, end adding occurrences by returning 0 
    {
        return 0;
    }

    else
    {
        memo = find(s1, s2, memo); //scan position into memo

        if(memo != -1) //if not end of the array i.e, `-1` add to occurrence
        {
            return 1+occ(s1,s2,memo+2);
        }

        else
        {
            return 0; //else return 0 and recursion would end in next call as memo is -1
        }
    }
}

//main function
int main(void)
{
    printf("%d",occ(s1,s2,0)); //just to see the output
} 
  • 输出:

    2 //true as {23,54} occur two times
    
  • 输入为:(编译时间)

    #define n 20
    #define p 2
    
    s1[n]={0,0,0,3,4,0,0,0,3,4,0,0,0,3,4,0,0,0,3,4};
    s2[p]={0,0};
    
  • 输出:

    4 //true as {0,0} occurs at 0,5,10,16
    

【讨论】:

  • 我什至没有想到 if(find(s1+memo,s2,memo,0)) 在那种情况下是假的!我过于专注于寻找一种计算发生次数的好方法。太好了!
  • @Dipok 你对我对函数所做的更改满意吗?如果您有任何疑问,请随时问我
  • 是的,我很好,但如果函数 find() 也有 pos2 可能会更通用,这样我们就可以使程序更灵活,例如我们可以s2[] 有 5 或 7 个元素,而不仅仅是两个。但是根据练习要求我们做的事情,您的解决方案完全没问题:) @Cherubim Anand
猜你喜欢
  • 2023-03-12
  • 2022-01-06
  • 2021-10-10
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 2017-04-14
  • 2015-06-18
相关资源
最近更新 更多