web-dev-qa-db-fra.com

Écrire une fonction récursive qui inverse la chaîne d'entrée

Je lisais le livre C++ For Everyone et un des exercices disait d'écrire une fonction string reverse(string str) où la valeur de retour est l'inverse de str.

Quelqu'un peut-il écrire du code de base et me l'expliquer? Je regarde cette question depuis hier et je n'arrive pas à comprendre. Le plus éloigné que j'ai eu est d'avoir la fonction renvoyer la première lettre de str (dont je ne sais toujours pas comment c'est arrivé)

C’est ce que j’ai eu (une heure après avoir posté cette question):

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;
}

Si j'entre "Wolf", il retourne Wol. Quelqu'un m'aide ici Si je return Word au lieu de return str_copy alors je reçois un w Si je return last_letter alors je reçois un l

9
Alex

J'ai deux minutes, je vais donc plutôt expliquer l'algorithme récursif lui-même. Prenons l'exemple "input" qui devrait produire "tupni". Vous pouvez inverser la chaîne récursivement en

  • Si la chaîne est vide ou un seul caractère, retournez-la inchangée.
  • Autrement,
    1. Supprimez le premier caractère.
    2. Inverser la chaîne restante.
    3. Ajoutez le premier caractère ci-dessus à la chaîne inversée.
    4. Renvoie la nouvelle chaîne.
19
David Harkness

Essaye celui-là

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
}

Une fonction récursive doit avoir les propriétés suivantes

  • Il doit s'appeler à nouveau
  • Il doit y avoir une condition à la fin de la récursivité. Sinon, vous avez une fonction qui entraînera un stackoverflow.

Cette fonction récursive crée en gros une chaîne du dernier caractère, puis s’appelle à nouveau avec le reste de la chaîne, à l’exclusion du dernier caractère. Le véritable basculement se produit à la dernière ligne où dernier + inversé est renvoyé. Si c'était le contraire, rien ne se passerait. C'est très inefficace, mais cela montre le concept.

Bien à vous, Alois Kraus

7
Alois Kraus

Juste pour suggérer un meilleur moyen de gérer la récursivité:

Inversion de chaîne à l'aide de la récursivité en 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;
}
6
totjammykd

Je n'écrirai pas d'algorithme complet pour vous, mais voici un indice:

Que diriez-vous d’échanger les deux personnages les plus externes et d’appliquer la même chose aux personnages du milieu?

Oh, et si ce livre proposait vraiment string reverse(string str) comme signature de fonction appropriée, jetez-le et achetez un bon livre à la place.

2
sbi

Voici ma version d'une fonction récursive qui inverse la chaîne d'entrée:

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
}
2
Ann Orlova

Le plus court et le plus facile

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;    
    }   
};
1
Prem K Chettri

Solution récursive à 1 ligne:

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

Vous l'appelez comme ça:

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

Je sais que je ne devrais pas donner de solution, mais puisque personne n’a mentionné cette solution facile, j’ai pensé que je devrais la partager. Je pense que le code est littéralement l'algorithme, il n'est donc pas nécessaire d'utiliser un pseudo-code.

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);
}

Pour l'appeler, utilisez:

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

vous pouvez implémenter votre propre reverse similaire à 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);
}
0
MORTAL

J'ai fait quelque chose comme ça, ça a fait le renversement en place. J'ai pris deux variables qui traversent la chaîne de deux extrémités extrêmes au centre de la chaîne et quand elles se chevauchent ou sont identiques, l'inversion se termine.

Prenons un exemple: saisissez string str = "abcd" et appelez la fonction en tant que

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

et incrémenter/décrémenter les pointeurs de variable de manière récursive. D'abord, les pointeurs pointent vers 'a' et 'd' et les échangent, puis ils pointent vers 'b' et 'c' et les échangent. Finalement, i >= j demande que le cas de base soit vrai et que la récursivité se termine. Le principal intérêt de cette question est de passer la chaîne d’entrée comme référence.

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;
    }
0
Marco167

Toutes les solutions existantes avaient beaucoup trop de code qui ne faisait vraiment rien, alors voici ce que je pense:

#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;
}

P.S. Je suis tombé sur cette question en essayant de trouver un moyen C++ pour std::string de ce que s+1 pour un char * en C est; sans aller tout le chemin de s.substr(1, s.length()-1), qui a l'air trop laid. En fait, il y a std::string::npos, ce qui signifie jusqu'à la fin de la chaîne, et c'est déjà la valeur par défaut pour le deuxième argument, donc, s.substr(1) suffit (en plus, il a aussi semble plus efficace et à égalité avec le s + 1 simple en C).


Notez cependant que la récursivité en général ne s'adapte pas à mesure que l'entrée grossit, à moins que le compilateur ne soit capable de faire ce que l'on appelle l'optimisation de la récursion finale. (La récursivité est rarement invoquée dans les langues impératives.)

Cependant, pour que l'optimisation de la récursion de la queue soit activée, il est généralement nécessaire que, (0), la récursivité ne se produise que dans l'instruction return et que, (1), aucune autre opération ne soit effectuée avec le résultat de la procédure récursive. rappeler dans la fonction parent.

Par exemple, dans le cas ci-dessus, le + s[0] est logiquement créé par le parent après la fin de l'appel enfant (et il le serait probablement même si vous passez par la route la plus désagréable s[s.length()-1] +), aussi pourrait-il empêcher la plupart des compilateurs de queue-récursivité-optimisation, rendant ainsi la fonction très inefficace sur les entrées de grande taille (sinon carrément cassée à cause de l'épuisement du tas).

(Pour ce que cela vaut, j’ai essayé d’écrire une solution plus conviviale (veiller à augmenter le résultat renvoyé par un argument de la fonction elle-même), mais le désassemblage du binaire résultant semble indiquer qu’il est plus complexe que dans les langages impératifs comme C++, voir gcc: n’existe-t-il pas de récursion de la queue si je retourne std :: string en C++? .)

0
cnst