简体   繁体   English

递归布尔函数,用于检查字符串是否为回文结构

[英]Recursive boolean function to check if a string is a palindrome

Write a recursive boolean function that returns 1 if a string is a palindrome and 0 if not. 编写递归布尔函数,如果字符串是回文,则返回1,否则返回0。

bool ispalindrome(char str[])

Notes: the function must be recursive (not a wrapper for recursive function), it has to use the given (above) signature and no global or static variables are allowed, also, we can't 'destroy' the given string. 注意:函数必须是递归的(不是递归函数的包装器),它必须使用给定的(上面)签名并且不允许全局或静态变量,而且,我们不能“破坏”给定的字符串。

My attempt: 我的尝试:

bool ispalindrome(char str[]){
    bool res;
    if (*str == 0 || *(str + 1) == 0)
        return 1;
    else{
        res = ispalindrome(str + 1);

Now I'm stuck, I thought of making a helper function that uses dynamic arrays that would have the first and last elements from the original string removed and use that in the recursive call but I don't think that's the intended solution. 现在我陷入了困境,我想到了一个使用动态数组的辅助函数,该数组将删除原始字符串中的第一个和最后一个元素,并在递归调用中使用它,但我不认为这是预期的解决方案。

EDIT: I've made some progress, but it doesn't work: 编辑:我已经取得了一些进展,但它不起作用:

bool ispalindrome(char str[]){
    bool res;
    int l = strlen(str);
    char t;
    if (*str == 0 || *(str + 1) == 0)
        return 1;
    else{
        t = str[l-1];
        str[l-1] = 0;
        res = ispalindrome(str + 1);
        if (res == 0)
            return 0;

        if (str[0] == str[l - 2])
            res =1;
        else 
            res=0;
        str[l] = t;
        return res;
    }
}

So, your current code almost works. 所以,你当前的代码几乎可以工作。 The only issues that I see is that in one case you return before you revert the changes in the string. 我看到的唯一问题是,在一个案例中,您在还原字符串中的更改之前返回。 Also, you have an off by one error in your indexing. 此外,您的索引中有一个错误。

Let's also note some stylistic fixes: 我们还要注意一些风格修复:

  1. *(str + 1) really should be str[1] . *(str + 1)确实应该是str[1] They're equivalent, but the latter is what is expected. 它们是等价的,但后者是预期的。

  2. Since you've already calculated l = strlen(str) , you could use that for your first conditional, since it's a bit more readable what that means. 由于您已经计算了l = strlen(str) ,因此可以将其用于第一个条件,因为这意味着更易读。

  3. You can also use longer variable names. 您还可以使用更长的变量名称。 They aren't more expensive. 它们并不贵。

  4. Personally, I like that if you're writing the null character into a string, that you use the null character instead of 0 . 就个人而言,我喜欢将空字符写入字符串中,并使用空字符代替0 That is '\\0' . 那是'\\0' But that's just me. 但那只是我。

And the code: 和代码:

bool ispalindrome(char str[]){
    int l = strlen(str);

    // Recusive Base Case
    if (l == 0 || l == 1)
        return true;

    // Save the last character of the string
    char t = str[l-1];
    str[l-1] = '\0';

    // Recursive call on the substring
    bool res = ispalindrome(str + 1);

    // Now, this is where you messed up. Before we return,
    // we need to fix the string!
    str[l-1] = t;

    // If the recursive call thinks that it's not a palindrome,
    // then we won't disagree.
    if (res == false)
        return res;

    // Check the (current) first position of the string against the last
    // You had an off by one error here.
    return (str[0] == str[l - 1]);
}

Can we make a small improvement to the runtime of the code? 我们可以对代码的运行时进行小的改进吗?

One annoying property of how your code works is that we will always have around strlen(str) / 2 recursive calls. 代码工作方式的一个令人讨厌的特性是我们将始终使用strlen(str) / 2递归调用。 Could we make the code run faster on an example like "abracadabra" , where the second letter of the string causes the palindrome test to fail. 我们能否在"abracadabra"等示例中使代码运行得更快,其中字符串的第二个字母会导致回文测试失败。

One way to speed it up would be to do the test (str[0] == str[l - 1]) before the recursive call. 加速它的一种方法是在递归调用之前进行测试(str[0] == str[l - 1]) We could implement this fairly easily, and it might looks something like this: 我们可以相当容易地实现它,它可能看起来像这样:

bool ispalindrome(char str[]){
    int length = strlen(str);

    // Recursive Base Case
    if (length == 0 || length == 1)
        return true;

    // Check our case.
    // Note that this is occuring __before__ the recursive call
    if (str[0] != str[length - 1])
        return false;

    // Save the last character of the string
    char t = str[length - 1];
    str[length - 1] = '\0';

    // Recursive call on the substring
    bool res = ispalindrome(str + 1);

    // We need to fix the string
    str[length - 1] = t;

    return res;
}

All of this being said... 所有这一切都说......

I've seen this question a couple of times on stackoverflow, and I'm always curious what the instructor is looking for. 我已经在stackoverflow上看了几次这个问题,而且我总是好奇教练正在寻找什么。 The classic version of this problem is solved by passing the string length as an additional parameter. 通过将字符串长度作为附加参数传递来解决此问题的经典版本。 By doing this, we save a ton of work. 通过这样做,我们节省了大量的工作。

Every solution posted so far (including mine) calls strlen() on every recursive call. 到目前为止发布的每个解决方案(包括我的)都会在每次递归调用时调用strlen() That means that all of these solutions are at least O(n^2) . 这意味着所有这些解决方案至少为O(n^2) If we could pass the length to the recursive call, we could easily solve the problem in O(n) . 如果我们可以将长度传递给递归调用,则可以轻松解决O(n)的问题。 This would be an extremely large reduction in work. 这将极大地减少工作量。

Additionally, you could also then write the code in a tail recursive manner. 此外,您还可以以尾递归方式编写代码。 This can allow the compiler to generate code that is much nicer for the processor to execute. 这可以允许编译器生成对处理器执行更好的代码。 (Basically, it will transform the code into what a for-loop would look like). (基本上,它会将代码转换为for循环的样子)。 This is very helpful because you then don't have as many concerns about running out of stack space on very large strings. 这非常有帮助,因为您不必担心大型字符串上的堆栈空间不足。

But, because of the limitations that your instructor has placed, we can't do any of these things. 但是,由于教师的限制,我们不能做任何这些事情。 Which is kind of lame. 真是la脚。

without a compiler... 没有编译器...

bool ispalindrome(char str[])
{
    int len = strlen(str);

    if( len <= 1)
    {
        return TRUE;
    }
    else if (str[0] != str[len - 1])
    {
        reutrn FALSE;
    }
    else
    {
        char *str2 = malloc(len - 1);
        strncpy(str2, str + 1, len - 2);
        str2[len - 2] = NULL;
        BOOL result = ispalindrome(str2); 
        free(str2);
        return result;
    }
}

psuedocode (meaning, there is no thing called string in C, and I didn't try to compile it, and my imaginary library calls that are similar to real library calls could have the params in the wrong orders, etc): psuedocode(意思是,在C中没有称为string东西,我没有尝试编译它,我的虚拟库调用类似于真正的库调用可能会在错误的命令中使用params等):

bool isPalendrome(string s)
{
    if (s[0] == s[strlen(s)-1]) // if the value of the first is the same as the last
    {
        if ((&s[strlen(s)-1] - &s[0]) < 3)// if the address of the end and the address of the start are 1, or 2, we have a palindrome of 1 or 2 chars..
        {
            return true;
        }
        s2 = alloca(strlen(s) - 1);// or VLA , -1 because -2 char, +1 for null
        s2[strlen(s) - 2] = '\0';
        strncpy(s+1,s2,strlen(s)-2);
        return isPalendrome(s2)
    }
    return false;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM