【问题标题】:Recursive function to compare strings without library functions递归函数来比较没有库函数的字符串
【发布时间】:2019-07-24 09:13:53
【问题描述】:

我应该用 C 编程语言编写一个递归函数来检查字符串 1 是否大于或等于或小于字符串 2,从而分别返回 10-1

以下是我编写的代码。该程序无法终止,我无法弄清楚原因。请给我一些建议。谢谢。

int revisedStrcmp(char *s1, char *s2) {
    int i = 0, n = 0, p = 0;

    if (s1[i] == '\0' && s2[i] != '\0') //s1 shorter than s2
        return -1;

    else if (s1[i] != '\0' && s2[i] == '\0') //s1 longer than s2
        return 1;

    else if (s1[i] != '\0' && s2[i] != '\0')  //both not equal to null
    {
        if (s1[i] > s2[i])  n += 1; //s1
        else if (s1[i] < s2[i]) p += 1; //s2
        else
        {
           n += 1; //s1
           p += 1; //s2
        }
        i += 1;
        return revisedStrcmp(s1, s2);
    }
    else    //if s1[i] & s2[i] are null
    {
        if (n > p) //s1 > s2
            return 1;
        else if (n < p)
            return -1;
        else
            return 0;
    }
}

【问题讨论】:

    标签: c string function recursion


    【解决方案1】:

    您的函数中的主要问题是您没有在对revisedStrcmp 的递归调用中传递更新的指针,从而导致无限循环和潜在的堆栈溢出

    这是一个更正和简化的版本:

    int revisedStrcmp(const char *s1, const char *s2) {
        if (*s1 < *s2)
            return -1;
        if (*s1 > *s2)
            return +1;
        // *s1 == *s2
        if (*s1 == '\0')
            return 0;
        return revisedStrcmp(s1 + 1, s2 + 1);
    }
    

    没有必要为较短的字符串设置特殊情况,因为可以在比较中使用空终止符。

    这种特殊的递归风格称为尾递归,现代编译器会将其编译成循环。

    但是请注意,要使revisedStrcmp() 返回与strcmp 相同的顺序,必须对unsigned char 值而不是普通char 执行比较,后者可以在许多架构上默认签名:

    int revisedStrcmp(const char *s1, const char *s2) {
        unsigned char c1 = *s1, c2 = *s2;
        if (c1 < c2)
            return -1;
        if (c1 > c2)
            return +1;
        // c1 == c2
        if (c1 == '\0')
            return 0;
        return revisedStrcmp(s1 + 1, s2 + 1);
    }
    

    【讨论】:

      【解决方案2】:

      原因是s1s2 在递归上是一样的。我的意思是: 如果你有char *s1 = "Hello";char *s2 == Elloh,你的递归调用是一样的。您总是从同一点开始,始终不会以任何方式传递增量(n, p),因此您基本上每次递归调用都从同一点开始。您可以做的是增加指针,这是一个简短的解决方案:

      int revisedStrcmp (char *s1, char *s2) {
          if (*s1 == *s2)
              return *s1 == '\0' ? 0 : revisedStrcmp(s1 + 1, s2 + 1);
      
          return (*s1 > *s2) ? 1 : -1; 
      }                                                                                                    
      

      或者您可以执行以下操作:

      return revisedStrcmp(s1+i, s2+i);
      

      【讨论】:

      • @chqrlie 你是这个意思吗?这是个好主意,谢谢!!!如果它们不同,是的,它可以节省 2 个,但我也可以在其他情况下少用一个测试用例。我的意思是,我可以不测试 if *s2 == '\0',因为如果 '*s1 == *s2` 和 *s1 = '\0' 它自动意味着 s2 = '\0'
      【解决方案3】:

      您没有将i, n, p 变量传递给函数。这样你的函数就不会结束,因为它每次都会以计数器变量为 0 开始。

      【讨论】:

        【解决方案4】:

        在部分:

            else if (s1[i] !='\0' && s2[i] !='\0')  //both not equal to null
            {
                if (s1[i]>s2[i])  n+=1; //s1
                else if (s1[i]<s2[i]) p+=1; //s2
                else
                {
                   n+=1; //s1
                   p+=1; //s2
                }
                i+=1;
                return rStrcmp(s1,s2);
        

        您使用s1s2 调用rStrcmp(s1,s2);,但是,您刚刚处理了一个字符。致电rStrcmp(s1+1,s2+1);


        注意:由于您的函数每次调用只处理一个字符,因此您不需要使用i 来索引字符串。除了在 r​​eturn 语句之前,它始终为 0,因此从不使用它的值:
        int rStrcmp(char *s1, char *s2)
        {
            if (*s1 =='\0' && *s2 !='\0') //s1 shorter than s2
                return -1;
        
            else if (*s1 !='\0' && *s2 =='\0') //s1 longer than s2
                return 1;
        
            else if (*s1 !='\0' && *s2 !='\0')  //both not equal to null
            {
                if (*s1>*s2)  return 1; //s1
                else if (*s1<*s2) return -1; //s2
                else
                    return rStrcmp(s1+1,s2+1);
            }
            else    //if s1[i] & s2[i] are null
            {
                // since both are null, they are the same length and each
                // character was the same: equal
                return 0;
            }
        }
        

        【讨论】:

          【解决方案5】:

          只需将return rStrcmp(s1, s2); 更改为return rStrcmp(s1+i, s2+i);。这样您就可以存储数组位置的增量。

          【讨论】:

            猜你喜欢
            • 2016-04-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-10-25
            • 2011-03-26
            • 2015-05-12
            • 2019-05-11
            相关资源
            最近更新 更多