用于反转字符串的递归函数

时间:2014-12-26 18:53:36

标签: c++ arrays string recursion

我正在尝试编写一个反转字符串的递归函数,我很确定我的递归基础是可靠的,但我无法让它工作......

基础:如果长度<= 1,则停止。 否则,交换第一个和最后一个元素并向前推进一个元素并将长度减少1.

我在缩短长度方面遇到了麻烦......

我考虑过使用strcat并在每次递归时添加前面的第一个元素,但它只对常量有用...

注2:我无法更改该功能的签名,我也无法使用任何其他库。

不要编辑我在这里使用的库和命令。这些是我所知道和使用的。

#include <string.h>
#include <iostream>

using namespace std;
void recuverse(char s[]);
int main()
{
    char s[] = "abcde";
    recuverse(s);
    cout << s << endl;
}

void recuverse(char s[]){
    int len = strlen(s);
    int i;

    if (len <= 1)return;
    else{
        for (i = len-1; i>0; i--){

            swap(s[0], s[i]);

            recuverse(s + 1);
        }
    }
}

11 个答案:

答案 0 :(得分:2)

实现中的for循环不是必需的:由于具有该循环,您执行的交换太多。事实上,这个练习的重点一直是消除循环。

通过添加一个测量字符串长度的额外函数来修复您的实现,然后调用两个参数recuverse_impl,如下所示:

void recuverse_impl(char *s, size_t len) {
    // Base case
    if (len < 2) return;
    // Swap elements the two ends
    swap(s[0], s[len-1]);
    // then call recuverse_impl again
    recuverse_impl(s+1, len-2);
}

void recuverse(char s[]){
    recuverse_impl(s, strlen(s));
}

如果由于某种原因要求明确禁止传递长度,您可以按如下方式更改实现:

void recuverse(char *s) {
    // Compute the length
    size_t len = strlen(s);
    // Do the base case
    if (len < 2) return;
    // Squirrel away the last element, and replace it with '\0'
    char t = s[len-1];
    s[len-1] = '\0';
    // Make a recursive call
    recuverse(s+1);
    // Now complete the swap
    s[len-1] = s[0];
    s[0] = t;
}

Demo.

答案 1 :(得分:2)

试试这个:

void recuverse(char s[])
{
    int len = strlen(s);
    if (len <= 1)
        return;
    char c = s[len-1];
    s[len-1] = 0;
    recuverse(s+1);
    s[len-1] = s[0];
    s[0] = c;
}

答案 2 :(得分:2)

尽我所知,这是通过这种不合理的限制来实现你所要求的唯一方法。

这是编写此函数的一种愚蠢的,愚蠢的方式,但我相信它符合指定指南中要求的内容。

// Reverses a string in place.
// Note: string cannot be a constant, without write permission
void reverse(char s[])
{
    // Get string length
    int len = strlen(s);

    if (len > 2)
    {
        // Save last character
        char lastChar = s[len - 1];

        // Temporarily shorten string by replacing last character
        // with a null-terminator character
        s[len - 1] = '\0';

        // Recursively swap remaining characters
        reverse(s + 1);

        // Swap first and last character
        s[len  - 1] = s[0];
        s[0] = lastChar;
    }
}

我认为上面的方法很糟糕,因为递归不是解决这个问题的最有效方法。即使使用递归,为此代码的递归部分编写单独的函数也会更有效,其中可能包含跟踪状态的其他参数,并在此处阻止某些重复逻辑。此外,避免使用任何其他库是没有意义的,特别是如果它包含将成为任何C ++应用程序一部分的库。

如果没有这些限制,我可以在这里编写反向函数。

void reverse(char* s)
{
    char *pEnd = s + (strlen(s) - 1);
    while (s < pEnd)
    {
        char c = *s;
        *s++ = *pEnd;
        *pEnd-- = c;
    }
}

答案 3 :(得分:2)

我的C解决方案不使用额外的库(stdio而不是iostream)和相同的函数签名。

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

void recuverse(char s[]){
    char saved;
    int len = strlen(s);
    if (len > 1) {
        saved = s[len-1];   // keep last char    
        s[len-1] = 0;       // shorten string
        recuverse(s+1);     // with shorter string
        s[len-1] = s[0];    // replace last char with first
        s[0] = saved;       // replace first char with last
    }                       // job done
}

int main()
{
    char str0 [] = "";      // test with various
    char str1 [] = "a";
    char str2 [] = "ab";
    char str3 [] = "abc";
    char str4 [] = "abcd";

    recuverse (str0);
    printf ("'%s'\n", str0);
    recuverse (str1);
    printf ("'%s'\n", str1);
    recuverse (str2);
    printf ("'%s'\n", str2);
    recuverse (str3);
    printf ("'%s'\n", str3);
    recuverse (str4);
    printf ("'%s'\n", str4);
}

节目输出

''
'a'
'ba'
'cba'
'dcba'

答案 4 :(得分:2)

似乎我已经理解了你需要的是你想要实现的方法。

您可以编写类似

的功能
void recuverse( char s[] )
{
    recuverse( s , std::strlen( s ) );
}

void recuverse( char s[], size_t n )
{
    if ( !( n < 2 ) )
    {
        std::swap( s[0], s[n-1] );
        recuverse( s + 1, n - 2 );
    }
}

但它是一个错误的解决方案,因为它不是函数void recuverse( char s[] );,它是一个递归函数。函数void recuverse( char s[], size_t n );是递归的。但根据你的任务,函数void recuverse( char s[] );应该是递归的。

所以唯一正确的解决方案如下。

#include <iostream>
#include <utility>

char * recuverse( char s[] )
{
    if ( *s  )
    {
        char *p = s;

        do
        {
            std::swap( *p, *( p + 1) );
        } while ( *p++ );

        recuverse( s );

        std::swap( *p, *( p - 1 ) );
    }

    return s;
}


int main() 
{
    char s[] = "abcde";

    std::cout << s << std::endl;
    std::cout << recuverse( s ) << std::endl;

    return 0;
}

输出

abcde
edcba

这个递归函数既不使用除std::swap之外的标准函数,也可以替换代码。:)

我更喜欢该函数的返回类型char *与标准C字符串函数类似。如果您希望该函数具有返回类型void,那么它将看起来像

void recuverse( char s[] )
{
    if ( *s  )
    {
        char *p = s;

        do
        {
            std::swap( *p, *( p + 1) );
        } while ( *p++ );

        recuverse( s );

        std::swap( *p, *( p - 1 ) );
    }
}

为了理解这个反向函数如何在没有标准函数strlen的情况下工作,让我们使用简化的例子“abc”逐步考虑它的操作。

所以我们有一个终止为零的字符串

abc\0

我将写为abc0

while循环

while ( *p++ ) ...

交换字符,直到它将交换终止零。

在第一次递归调用中,循环正在执行以下操作

abc0
bac0
bca0
bc0a

现在函数调用自身,但现在字符串看起来像

BC0

所以在循环中会有

bc0
cb0
c0b

在下一个递归调用中,参数将为

C0

在循环中交换两个字符

0c

所以最后用空字符串调用该函数。因此它只是将控件返回给调用者,调用者交换字符串的最后一个字符

考虑到整个字符串现在看起来像

0cba

我们需要将终止零tp移动到字符串末尾的有效位置。这是通过循环后的交换来完成的。

0c => c0
--------
c0b => cb0
-----------
cb0a => cba0

就是这样。:)

答案 5 :(得分:1)

这里是递归反向的正确版本:

void reverse(char *s, char *e) {
    if (s < e) {
        char t = *s;
        *s = *e;
        *e = t;
        reverse(s+1, e-1); // here is length is decreased by 2
    }
}

void recuverse(char s[]) {
    int len = strlen(s);

    reverse(s, s+len-1);
}

答案 6 :(得分:1)

这不是改变签名,而是使用std::swap交换s [begin]和s [end]直到它到达中间。要完成递归并保留签名,你可以(doens并不意味着你应该)将begin,mid和length声明为全局变量:

int beg = 0;
int len = 0;
int mid = 0;

void recuverse(char s[]) {
    if (beg == 0) { // this block runs one time.
        len = strlen(s)-1;
        mid = len / 2;
    }
    if (beg == mid)
        return;
    swap(s[beg], s[len]);
    ++beg, --len;
    recuverse(s);
}

输出:edcba

答案 7 :(得分:1)

如果允许使用静态变量,请尝试使用

void recuverse(char s[]){
    static int e;
    int z=strlen(s)-e++;           // z is the number of characters to be evaluated
    if(z>1){    
        char t=*(s+z-1);
        *(s+z-1)=*s;
        *s=t;
        recuverse(s+1);
    }
}

答案 8 :(得分:0)

如果您注意mirror(cs) = cat(mirror(s),c)c是字符,s是字符串),那么:

void rev(char *s) {
  if (*s==0) return;
  rev(s+1);
  sprintf(s,"%s%c",s+1,*s);
}

答案 9 :(得分:0)

在C ++实现下,递归反转字符串

这里基础案例是在字符串

中找到NULL字符
    #include<bits/stdc++.h>
using namespace std;


    void reverse(string s,long i){


        if(s[i] == '\0')
        return;


        reverse(s,i+1);

        cout<<s[i];
        return;
    }

    int main(){


        string s;

        cin>>s;


        reverse(s,0);
        return 0;
    }

答案 10 :(得分:-1)

你可以试试这个:

#include <string.h>
#include <iostream>

using namespace std;

void recuverse(char *s, int right);

int main()
{
    char s[] = "abcde";
    recuverse(s , 0);
    cout << s << endl;
}

void recuverse(char *s, int right){ // Here right is the position of the right position(from right to left) of character with which you will swap
    int len = strlen(s);
    int i;

    if (len <=right)return;

    swap(s[0], s[len-1-right]);

    recuverse(s + 1, right+1);
}