如何最好地遵循功能来理解它在做什么?

时间:2012-03-30 14:04:43

标签: c++ algorithm refactoring pseudocode

这个问题很笼统,但我将举一个具体的例子。

解释了需要解决的具体问题here。描述很长,所以我不会剪切和粘贴,但基本思路是输入字符串S和T(因为它们在下面的代码中调用),找到需要对S生成T的最小更改次数。一个变化可能是:

  • 在字符串的任意一端插入一个字母。
  • 从字符串的任何一端删除一个字母。
  • 将一个字母改为任何一个字母。

以下是我要跟踪的解决方案。我正在寻找的是如何最好地解决方案的提示。我可以使用哪些方法来阅读和理解代码(让我们放弃逐步调试代码)。

#include<iostream>
#include<cstring>
#include<stdio.h>
using namespace std;
char S[2010];
char T[2010];
int lens,lent;
int main()
{
    int i,j,ma,p;

    while(scanf("%s%s",S,T)!=EOF)
    {
        lens=strlen(S);
        lent=strlen(T);
        ma=0;p=0;
        for(i=0;i<lens;i++)
        {
            p=0;
            for(j=0;j<lent;j++)
            {
                if(i+j>=lens)
                    break;
                if(S[i+j]==T[j]){p++;}
            }
            if(ma<p)
                ma=p;
            if(ma==lent)
                break;
        }
        for(i=0;i<lent;i++)
        {
            p=0;
            for(j=0;j<lens;j++)
            {
                if(i+j>=lent)
                    break;
                if(T[i+j]==S[j]){p++;}
            }
            if(ma<p)
                ma=p;
            if(ma==lent)
                break;
        }
        printf("%d\n",lent-ma);
    }
    return 0;
}

5 个答案:

答案 0 :(得分:3)

第1步:向自己解释变量代表什么:

S:我们想要从中提取子字符串的字符串

T:在用尽可能少的操作修改提取的子字符串之后,我们想要实现的字符串

lens:字符串S的长度

lent:字符串T的长度

i:S中从中提取子字符串的索引

j:字符串T中我们想要与子字符串中相应字符匹配的字符中的索引

p:为当前调查的子字符串

找到的匹配字符数量

ma:任何子字符串的最大匹配字符数


第2步:确定了这些含义后,将第一个循环翻译成单词非常简单:

for loop 1 :    selects a start position of the substring

    set the match counter to 0, since we start investigation of a new substring


    for loop 2 :    loops through the substring

        if 1 :      if there is no char left to read string S, stop looping

        if 2 :      if the current character in the extracted substring matches
                a character in the "goal" string, increment the match counter (p)


    if 3 :      now, we finished looping through a substring,
            if the count of matching characters in the substring and the goal
            string was higher than for any of the previous counts,
            then store this value as the max count

    if 4 :      if the max count of matching characters is equal to the 
            length of the "goal string", dr Moriatry can receive the goal string
            with 0 substring changes, and hence, we can stop looping

下一个循环类似。 S和T的作用有所逆转。但请注意,S和T的角色尚未完全逆转(正如有些人所说)。外部for循环的结束条件在两种情况下都使用T的长度,这是有道理的。

这里我们从字符串T(“目标”字符串)中提取子字符串,并尝试将它们与字符串S匹配。为什么我们这样做?

我希望编写代码的人想要考虑以下情况,例如:

S = "b"     T = "abc"

如果我们只从S中提取子串并将它们与整个T字符串匹配,从第一个索引开始(就像第一个循环那样),我们只比较“做b(在S中)匹配a(T中的第一个字符)然后我们继续说:“由于没有子字符串匹配,我们需要3个字符串更改操作来接收字符串T”(这显然是错误的,因为我们可以实现它通过选择“b”作为要提取的子字符串,并进行2次更改操作以最终得到T)

答案 1 :(得分:2)

最好的解决方案是在理解代码时重写代码。几件事:

  1. 注意重复的代码。他对S和T做了同样的事情,角色也是相反的。您可以使用两个字符串作为参数和use来创建函数foo() foo(S,T)foo(T,S)
  2. 尝试打破太多深度。当你看到许多嵌套循环时,大部分时间内某些内部循环可以看作是一个特定的函数。
  3. 逐步重命名变量,因为您正在了解更多正在发生的事情
  4. 最后但并非最不重要的是, 不会放弃逐步调试

答案 2 :(得分:2)

理解代码的关键是理解变化最小的变量的含义,在本例中为ma和p,并识别编码习语。

两个代码段

if(ma<p)
    ma=p;
if(ma==lent)
    break;

是变量p的“高水位线”成语(在最大可能值上具有中断条件)。只要在从i开始的LHS子串的j位置处的字符与RHS的j位置字符匹配,p就递增。因此,对于由j(内部循环)索引的循环,p是处于相同j位置的相同字符的数量。所以我会将p(至少在我脑中)重命名为“number_of_identical_chars_in_same_pos”。

由i索引的循环找到LHS中每个子字符串的最高p(保存在ma中),该子字符串以LHS的最后一个字符结尾(如果子字符串长,则更早)。所以ma应该重命名为“max_common_chars_in_a_span”。这两个循环一起找到任意子串的相同位置中的最大公共字符数,以任何一方的最后一个字符结尾。

最后一步(留给认真的学生)是要了解这是如何解决问题的,这是数学,而不是编程。

答案 3 :(得分:1)

我首先要对程序进行一些字符串操作。第一步是尝试为变量提供更好的名称。

我用sPos替换'i'作为字符串S中的位置。好吧,至少这适用于第一个循环,对于第二个循环'i'改变意思是T中的位置,所以我想实际上然后决定摆脱i,而是有两个变量,所以每个变量都有一个与其名称相匹配的目的。

然后对j,ma和p尝试相同的事情。

一旦完成,我会考虑尝试找出两个'for'循环的作用。他们看起来几乎相同。也许它们可以分成一个被调用两次的函数。再次,尝试弄清楚这个函数的作用并仔细命名,以便名称解释其用途。

重复这样的步骤,直到你得到一些让人有意义的代码。

答案 4 :(得分:1)

  1. 将两个外部循环提取到它们自己的函数中。
  2. 找到共性(提示:他们只修改ma)。
  3. 提取这种共性。
  4. 将内部循环解压缩到它们自己的函数(提示:代码相同)。
  5. 为每个功能编写单元测试以测试您的理解。