【问题标题】:Write a recursive function that reverses the input string编写一个反转输入字符串的递归函数
【发布时间】:2021-12-15 19:10:33
【问题描述】:

我一直在阅读 C++ For Everyone 一书,其中一个练习说要编写一个函数 string reverse(string str),其中返回值是 str 的倒数。

谁能写一些基本的代码给我解释一下?从昨天开始我就一直在盯着这个问题,无法弄清楚。我得到的最远的是让函数返回str 的第一个字母(我仍然不知道它是怎么发生的)

据我所知(发布此问题一小时后):

string reverse(string str)
{
    string word = "";

    if (str.length() <= 1)
    {
        return str;
    }
    else
    {
        string str_copy = str;
        int n = str_copy.length() - 1;
        string last_letter = str_copy.substr(n, 1);

        str_copy = str_copy.substr(0, n);
        word += reverse(str_copy);
        return str_copy;
    }
    return word;
}

如果我输入“Wolf”,它会返回 Wol。有人在这里帮我 如果我 return word 而不是 return str_copy 那么我得到一个 w 如果我return last_letter,那么我会得到一个l

【问题讨论】:

  • 你希望它返回字符串的其余部分反转,然后是第一个字母。
  • 这个问题与 recursive 函数有什么关系?你说的你的书是什么意思?
  • 哪种方法,递归还是迭代:)?
  • @pajton: "写一个递归函数..."
  • 啊!抱歉,我只是看了问题,没有看标题。

标签: c++ recursion reverse


【解决方案1】:

我将改为解释递归算法本身。以应该产生“tupni”的“输入”为例。您可以通过

递归地反转字符串
  • 如果字符串为空或单个字符,则原样返回。
  • 否则,
    1. 删除第一个字符。
    2. 反转剩余的字符串。
    3. 将上面的第一个字符添加到反向字符串中。
    4. 返回新字符串。

【讨论】:

  • 你的帖子是迄今为止最有帮助的
  • 我尝试使用 C++ 实现这个,与使用迭代器相比速度非常慢
  • @ArmenB。算法选择通常需要在运行速度、内存要求和复杂性之间进行选择。
  • @ArmenB。请记住,问题要求递归实现。
  • 这种方法使用 O(n) 堆栈空间。您可以将其减少到 O(log n),方法是将字符串分成两半,反转后半部,反转前半部,将两个反转的半部相加,然后返回新字符串。也许不像您的解决方案那样清晰和直接,但也没有那么明显。
【解决方案2】:

试试这个

string reverse(string &s)
{
    if( s.length() == 0 )  // end condtion to stop recursion
        return "";

    string last(1,s[s.length()-1]);  // create string with last character
    string reversed = reverse(s.substr(0,s.length()-1));
    return last+reversed; // Make he last character first
}

递归函数必须具有以下属性

  • 它必须再次调用自己
  • 递归结束时必须有条件。否则你有一个功能 会导致堆栈溢出。

这个递归函数基本上是创建一个最后一个字符的字符串,然后用字符串的其余部分(不包括最后一个字符)再次调用自身。真正的切换发生在返回 last+reversed 的最后一行。反之则什么都不会发生。

它的效率很低,但它可以展示这个概念。

【讨论】:

  • @braaterAfrikaaner:我不知道你指的是什么。线索可能在您发表评论的日期吗??
【解决方案3】:

只是为了建议一种更好的递归处理方式:

在 C++ 中使用递归进行字符串反转:

#include <iostream>
#include <string>
using namespace std;

string reverseStringRecursively(string str){
    if (str.length() == 1) {
        return str;
    }else{
        return reverseStringRecursively(str.substr(1,str.length())) + str.at(0);
    }
}

int main()
{
    string str;
    cout<<"Enter the string to reverse : ";
    cin>>str;

    cout<<"The reversed string is : "<<reverseStringRecursively(str);
    return 0;
}

【讨论】:

  • 你可能想使用 getline(cin, str);而不是 cin>>str;如果字符串由空格组成。
【解决方案4】:

我不会为你写一个成熟的算法,但这里有一个提示:

如何交换最外面的两个字符,然后将其应用于中间的字符?

哦,如果那本书真的建议 string reverse(string str) 作为一个合适的函数签名,那就扔掉它,买一个 good book 代替。

【讨论】:

  • 是的书上说要写函数string reverse(string str)
  • 另外,算法也很简单。我有我的,除了递归对我来说是一个令人困惑的概念,我不知道如何使用递归编写函数
  • @Alex:别难过,递归是一个很难掌握的概念。您是否看过其他示例,例如递归斐波那契算法?在尝试编写任何代码之前,尝试手动(在纸上)递归地计算出第 5 个斐波那契数。
  • 我是这么认为的。我可以试试
  • @sbi:这本书很可能试图用最简单的术语解释递归函数,而不考虑效率。从教学的角度来看,这个签名是有意义的。
【解决方案5】:

这是我对输入字符串进行反转的递归函数版本:

void reverse(char *s, size_t len)
{
    if ( len <= 1 || !s )
    {
        return;
    }
    std::swap(s[0], s[len-1]);// swap first and last simbols
    s++; // move pointer to the following char
    reverse(s, len-2); // shorten len of string
}

【讨论】:

    【解决方案6】:

    最短和最简单

    class Solution {
    public:
        string reverseString(string s) {
            string str;
            if(s != "\0"){
                str = reverseString(s.substr(1, s.length()));
                str += s.substr(0,1);
            }
            return str;    
        }   
    };
    

    【讨论】:

    • 很好地滥用了类概念。
    【解决方案7】:

    1 行递归解决方案:

    string RecursiveReverse(string str, string prev = "") {
        return (str.length() == 0 ? prev : RecursiveReverse(str.substr(0, str.length()-1), prev += str[str.length()-1]));
    }
    

    你这样称呼它:

    cout << RecursiveReverse("String to Reverse");
    

    【讨论】:

      【解决方案8】:

      我知道我不应该给出解决方案,但由于没有人提到这个简单的解决方案,我想我应该分享它。我认为代码字面上就是算法,所以不需要伪代码。

      void c_plusplus_recursive_swap_reverse(std::string::iterator start, 
          std::string::iterator end) 
      {
          if(start >= end) {
              return;
          }
      
          std::iter_swap(start, end);
          c_plusplus_recursive_swap_reverse(++start, --end);
      }
      

      调用它使用:

      c_plusplus_recursive_swap_reverse(temp.begin(), temp.end());
      

      【讨论】:

        【解决方案9】:

        所有现有的解决方案都有太多没有真正做任何事情的代码,所以,这是我的看法:

        #include <iostream>
        #include <string>
        
        std::string
        r(std::string s)
        {
            if (s.empty())
                return s;
            return r(s.substr(1)) + s[0];
        }
        
        int
        main()
        {
            std::cout << r("testing") << std::endl;
        }
        

        附:我偶然发现了这个问题,试图为 std::string 找到 C++ 方式,而 s+1 在 C 中的 char * 是什么;不走s.substr(1, s.length()-1)的整条路线,看起来太难看了。原来,有std::string::npos,这意味着直到字符串的末尾,它已经是第二个参数的默认值,所以,s.substr(1) 就足够了(另外,它也看起来更有效率与 C 中的简单 s + 1 相当。


        但是请注意,递归通常不会随着输入的增大而扩展,除非编译器能够进行所谓的尾递归优化。 (在命令式语言中很少依赖递归。)

        但是,为了激活尾递归优化,通常要求 (0),递归只发生在 return 语句内,并且,(1) 不执行进一步的操作在父函数中递归回调的结果。

        例如,在上述情况下,+ s[0] 在子调用完成后由父级逻辑完成(即使您走更丑陋的s[s.length()-1] + 路由也可能如此),因此,它可能是很好地防止大多数编译器进行尾递归优化,从而使函数在大输入时效率非常低(如果不是由于堆耗尽而彻底破坏)。

        (对于它的价值,我尝试编写一个对尾递归更友好的解决方案(确保通过函数本身的参数来增加返回结果),但是对生成的二进制文件的反汇编似乎表明它是比 C++ 等命令式语言更复杂,请参阅gcc: is there no tail recursion if I return std::string in C++?。)

        【讨论】:

          【解决方案10】:

          您可以实现自己的反向,类似于 std::reverse。

          template <typename BidirIt>
          void reverse(BidirIt first, BidirIt last)
          {
              if((first == last) || (first == --last))
                  return;
          
              std::iter_swap(first, last);
              reverse(++first, last);
          }
          

          【讨论】:

            【解决方案11】:

            我做了这样的事情,它完成了反转。我取了两个变量,它们从两个极端遍历字符串到字符串的中心,当它们相互重叠或相等时,反转终止。

            举个例子:输入string str = "abcd",调用函数为

            ReverseString(str,0,str.length()-1);
            

            并递归地递增/递减变量指针。 首先,指针指向'a''d' 并交换它们,然后它们指向'b''c' 并交换它们。最终i &gt;= j 要求基本情况为真,因此递归终止。这个问题的主要内容是传递输入字符串作为参考。

            string ReverseString(string& str,int i,int j){
                    if(str.length() < 1 || str == "" || i >= j){
                        return "";
                    }
            
                    else{
                        char temp = str[i];
                        str[i] = str[j];
                        str[j] = temp;
                        ReverseString(str,i+1,j-1);
                    }
                    return str;
                }
            

            【讨论】:

              【解决方案12】:

              字符串可以原地反转。如果我们从可能的最小字符串开始,即一个字符串,我们不需要做任何事情。这是我们停止或从递归调用返回的地方,它成为我们的基本情况。

              接下来,我们必须想出一种通用的方法来交换最小的字符串,即两个或更多字符。最简单的逻辑是将当前字符str[current_index] 与对面的字符str[str_length-1 - current_index] 交换。

              最后,为下一个索引再次调用 reverse 函数。

              #include <iostream>
              using namespace std;
              
              void reverse_string(std::string& str, int index, int length) {
                // Base case: if its a single element, no need to swap
                // stop swapping as soon as we reach the mid, hence index*2
                // otherwise we will reverse the already reversed string
                if( (length - index*2) <= 1 ) { 
                  return;
                }
              
                // Reverse logic and recursion:
              
                // swap current and opposite index
                std::swap(str[index], str[length-1 - index]); 
              
                // do the same for next character (index+1)
                reverse_string(str, index+1, length);
              }
              
              int main() {
                std::string s = "World";
                reverse_string(s, 0, s.length());
                std::cout << s << endl;
              }
              

              【讨论】:

                【解决方案13】:

                已经有一些很好的答案,但我想用完整的递归反转字符串添加我的方法。

                #include <iostream>
                #include <string>
                using namespace std;
                
                char * reverse_s(char *, char*, int,int);
                
                int main(int argc, char** argv) {
                if(argc != 2) {
                        cout << "\n ERROR! Input String";
                        cout << "\n\t " << argv[0] << "STRING" << endl;
                        return 1;
                }       
                        char* str = new char[strlen(argv[1])+1];
                        strcpy(str,argv[1]);    
                        char* rev_str = new char[strlen(str)+1];        
                        cout<<"\n\nFinal Reverse of '" << str << "' is --> "<< reverse_s(str, rev_str, 0, strlen(str)) << endl;
                        cin.ignore();
                        delete rev_str, str;
                        return 0;
                }
                
                char* reverse_s(char* str, char* rev_str, int str_index, int rev_index ) {
                if(strlen(str) == 1)
                        return str;
                
                if(str[str_index] == '\0' ) {
                        rev_str[str_index] = '\0';
                        return rev_str;
                }
                
                str_index += 1;
                rev_index -=1;
                
                rev_str = reverse_s(str, rev_str, str_index, rev_index);
                if(rev_index >= 0) {
                        cout << "\n Now the str value is " << str[str_index-1] << " -- Index " << str_in
                dex << " Rev Index: " << rev_index;
                        rev_str[rev_index] = str[str_index-1];
                
                        cout << "\nReversed Value: " << rev_str << endl;
                }
                return rev_str;
                }
                

                【讨论】:

                • 这是一个 C++ 问题而不是 C 问题,需要 std::string 而不是 c 字符串。
                【解决方案14】:
                void reverse(string &s, int &m) {
                    if (m == s.size()-1)
                        return;
                    int going_to = s.size() - 1 - m;
                    string leader = s.substr(1,going_to);
                    string rest = s.substr(going_to+1,s.size());
                    s = leader + s.substr(0,1) + rest;
                    reverse(s,++m);    
                }
                int main ()
                {
                  string y = "oprah";
                  int sz = 0;
                  reverse(y,sz);
                  cout << y << endl;
                  return 0;
                }
                

                【讨论】:

                • 欢迎来到本站。您介意添加一些文字来解释您的代码以及它如何回答问题吗?
                【解决方案15】:
                void ClassName::strgRevese(char *str)
                {
                        if (*str=='\0')
                                return;
                        else
                                strgRevese(str+1);
                        cout <<*str;
                }
                

                【讨论】:

                  【解决方案16】:

                  这是我的 3 行字符串反转

                  std::string stringRevers(std::string s)
                  {
                      if(s.length()<=1)return s;
                      string word=s.at(s.length()-1)+stringRevers(s.substr(0,s.length()-1));//copy the last one at the beginning  and do the same with the rest
                      return word;
                  
                  }
                  

                  【讨论】:

                  • 仅供参考:运行 stringRevers("") 时出现分段错误。
                  • 使用 if(s.length()
                  【解决方案17】:

                  问题是写一个递归函数。这是一种方法。不是一个简洁的代码,但可以满足要求。

                  /* string reversal through recursion */
                  #include <stdio.h>
                  #include <string.h>
                  #define size 1000
                  char rev(char []);
                  char new_line[size];
                  int j = 0;
                  int i =0;
                  int main ()
                  {
                    char string[]="Game On";
                    rev(string);
                    printf("Reversed rev string is %s\n",new_line);
                    return 0;
                  }
                  char rev(char line[])
                  {
                   while(line[i]!='\0')
                    { 
                      i++;
                      rev(line);
                      i--;
                      new_line[j] = line[i];
                      j++;
                      return line[i];
                    }
                    return line[i];
                  }
                  

                  【讨论】:

                  • 该问题被标记为 C++,并且需要 std::string 而不是 C 字符串。
                  【解决方案18】:

                  它会递归地反转原始字符串

                  void swap(string &str1, string &str2)
                  {
                      string temp = str1;
                      str1 = str2;
                      str2 = str1;
                  }
                  
                  void ReverseOriginalString(string &str, int p, int sizeOfStr)
                  {
                      static int i = 0;
                      if (p == sizeOfStr)
                          return;
                  
                      ReverseOriginalString(str, s + 1, sizeOfStr);
                  
                      if (i <= p)
                          swap(&str[i++], &str[p])
                  }
                  
                  int main()
                  {
                      string st = "Rizwan Haider";
                  
                      ReverseOriginalString(st, 0, st.length());
                      std::cout << "Original String is Reversed: " << st << std::endl;
                  
                      return 0;
                  }
                  

                  【讨论】:

                  • 在您的swap() 中,您不能将char 分配给string
                  • 完美地反转任何字符串,char 是错误的
                  • 你确定吗? sReverseOriginalString 中应该是p。您的交换需要引用,但是当您在ReverseOriginalString 中调用它时,您正在传递指针。 std::swap() 反正已经存在了。它还使用了一个永远不会重置的静态变量,因此您的函数在整个程序运行时只能被调用一次
                  猜你喜欢
                  • 2011-03-26
                  • 2015-05-12
                  • 1970-01-01
                  • 2014-08-01
                  • 2013-02-25
                  • 2020-07-27
                  相关资源
                  最近更新 更多