0

我正在做一个实验室作业,用户输入一个字符串以及字符串中要反转的子字符串的起点和终点。例如,如果用户输入字符串“go bobcats”以及数字 3(用于起始索引)和 7(用于结束索引),则输出应为“go accobts”。我能够编写一个递归函数来反转整个字符串(“go bobcats”变成“stacbob og”),但是我在子字符串方面遇到了麻烦。

完整字符串反转的代码:

void reversing(string s, int start, int end){
    if(s.size() == 0){return;}
    else{
        reversing(s.substr(1), start + 1, end);
        cout << s[0];
    }
}

对于这个的开始和结束索引,我只输入了 0 和 9,因为那将是字符串的全长。

如何调整函数,使其仅反转在用户输入的索引处开始和结束的字符串?此外,使用我当前的函数,我必须endl在 main 中使用 an 在字符串输出的末尾创建一个新行。有没有办法可以在函数内部做到这一点?如果我在每次迭代endlcout << s[0];放置一个新行,使输出垂直:

s

一个

C

b

b

G

主要实现:

string s;
    int start, end;
    cout << "Enter a string: ";
    while(cin.peek() == '\n' || cin.peek() == '\r'){
        cin.ignore();
    }
    getline(cin,s);
    cout << "Now enter two numbers that are within the bounds of the string. ";
    cin >> start >> end;
    cout << "This is how your words look now:\n";
    reversing(s,start,end);
    cout << endl;
4

5 回答 5

2

反转字符串的函数可以交换范围两端的元素,并在两侧将范围减一。

void reversing(string& s, int start, int end) {
    if (start >= end)
        return;
    swap(s[start], s[end]);
    reversing(s, start + 1, end - 1);
}

然后在里面main()

// ...
cout << "This is how your words look now:\n";
reversing(s, start, end);
cout << s << endl;
于 2020-04-14T18:51:52.397 回答
1

有时看到 C++ 被用来教授所有东西而不是 C++ 时,会感到难过。下面是一个实验,看看我们是否可以std::reverse通过实际上忽略你的作业要求并做一些可消化的小步骤来以某种方式接近(你应该实际使用的算法)。

让我们从这个答案中提出的解决方案的一个小变化开始。string我们可以使用迭代器,而不是与索引一起传递。简而言之,迭代器是算法和数据结构之间的粘合剂,更具体地说是容器。它们可以引用容器中的元素,就像索引或指针一样。

void reversing2(std::string::iterator first, std::string::iterator last) {
    if (first >= last) return;
    std::swap(*first,*last);
    reversing2(++first,--last);
} 

迭代器可以像指针一样被取消引用以获取对元素 (*first*last) 的引用。RandomAccessIterators 可以递增 ( ++first)、递减 ( --last) 和比较 ( first >= last),就像使用索引一样。

下一步是困难的,因为它需要更多的挥手。请注意,除了函数签名之外,上述函数中的任何内容实际上都依赖于first并且last是 a 中元素的迭代器std::string。例如,要反转int[]仅签名的子数组,则必须更改:

void reversing2(int* first, int* last) {
    if (first >= last) return;
    std::swap(*first,*last);
    reversing2(++first,--last);
}

这是一个与模板取得联系的好机会。我知道我在这里犯了一个小罪,因为我无法给出详尽的介绍,而只会向您介绍一个非常狭窄的案例。为了使相同的代码可用于不同的容器,我们只需对其稍作修改

template <typename IT>
void reversing(IT first,IT last) {
    if (first >= last) return;
    std::swap(*first,*last);
    reversing(++first,--last);
}

现在可以使用任何 RandomAccessIterator 调用它。所以这:

#include <string>
#include <iostream>
int main() {        
   std::string s{"Hello world"};       
   std::cout << s << '\n';
   reversing2(s.begin()+3,s.begin()+7);    // pass iterators to 4th and 8th character
   std::cout << s << '\n';
   reversing(s.begin()+3,s.begin()+7);
   std::cout << s << '\n';   
   int x[]= {1,2,3,4,5,6};
   reversing(&x[2],&x[5]);                 // pointers are iterators too
   for (const auto e : x) std::cout << e;
}

将产生这个输出:

Hello world
Helow olrld
Hello world
126543

最终,这就是前面的全部动机,我们可以看到 与reversing非常相似std::reverse。当然std::reverse不是递归的,并且有一个小警告:标准算法通常在半开区间上工作,即由两个迭代器组成的范围firstlast其中first包含在区间中,但在区间中last的最后一个元素之后。因此,要获得相同的结果,您必须使用第二个迭代器调用它,而不是使用上述函数:

std::reverse(s.begin()+3,s.begin()+8);  // pass iterators to 4th and one past the 8th character

完整的在线示例

于 2020-04-14T19:59:00.097 回答
0

好吧,我也有一个解决方案,但没有实现库函数只是为了让您有一种实现的感觉,而且非常简单。

  1. 调整你的功能- 递归地交换开始和最后一个位置,而不是穷举。

    1. endl在 main 中-如果您只想将答案保存在输入字符串中,那么是的,您必须在 main 中执行此操作。否则就在从函数 put 'endl' 返回之前。

我的代码是这样的。

#include<bits/stdc++.h>
using namespace std;


void rev(string &str,int s,int l){ // s = start l = last
     if(l<s) return ;            // base condition when l precedes s
     else {
         char temp = str[s];
         str[s] = str[l];
         str[l] = temp;
         rev(str,++s,--l);
     }
     return ;           
}

int main(){
   string str;
   int s,l;
   getline(cin,str);
   cin>>s>>l;
   assert(s<str.size() && l<str.size());
   rev(str,s,l);
   cout<<str;
} 
于 2020-04-14T19:31:21.980 回答
0

有不同的方法来解决这个问题,贪婪的方法是使用 substring 将确切的字符串传递给 reverse 函数:

void reversing(string s){
    if(s.size() == 0){return;}
    else{
        reversing(s.substr(1));
        cout << s[0];
    }
}

void main(string s, int start, int end) {
    string substring = reversing(s.substr(start, end - start + 1));
    cout << s.substr(0, start) + substring + s.substr(end + 1);
}

否则你需要编辑你的函数,只有在这样的范围内才能编辑字符串

void reversing(string s, int start, int end, int index = 0, string output = ""){
    if(s.length() == index){return output;}
    else{
        if (index >= start && index <= end) {
            output = output + s[end - (index - start)];
        } else {
            output += s[index];
        }
        reversing(s, start, end, index+1, output);
        cout << output[output.length()-1];
    }
}
于 2020-04-14T20:20:29.857 回答
0

在您的函数声明中,第一个参数的类型不是引用类型。因此,该函数处理作为参数传递给函数的原始字符串的副本。

但是在任何情况下,您的递归函数定义都是无效的。至少不需要提取子字符串。

注意函数的第二个和第三个参数应该是 type std::string::size_type。否则,当参数具有 int 类型时,用户可以为参数提供负值,并且函数将具有未定义的行为。

当函数返回对反转字符串本身的引用时也更好。

事实上,在函数中,您只需要使用一项检查开始位置是否小于结束位置。

这是一个演示程序,显示了如何定义函数。

#include <iostream>
#include <string>

std::string & reversing( std::string &s, std::string::size_type start, std::string::size_type end )
{
    if ( not s.empty() )
    {
        if ( not ( end < s.size() ) ) end = s.size() - 1;

        if ( start < end )
        {
            std::swap( s[start], s[end] );
            reversing( s, start + 1, end - 1 );
        }
    }       

    return s;
}

int main() 
{
    std::string s( "Hello bobaloogie" );

    std::cout << s << '\n';
    std::cout << reversing( s, 0, 4 ) << '\n';
    std::cout << reversing( s, 6, s.size() ) << '\n';

    return 0;
}

程序输出为

Hello bobaloogie
olleH bobaloogie
olleH eigoolabob
于 2020-04-14T19:25:02.367 回答