#include <iostream>
#include <string>
using namespace std;
void ReverseString(string &S, int size)
{
static int start = 0;
if (start == size - 1 || start == size)
{
return;
}
else
{
swap(S[start++], S[size - 1]);
ReverseString(S, size - 1);
}
}
int main()
{
cout << "enter a string to reverse" << endl;
string s;
getline(cin, s);
cout << "Before Reversing" << endl;
cout << s << endl;
ReverseString(s, s.size());
cout << "After Reversing" << endl;
cout << s << endl;
return 0;
}
I am trying to nail recursions as much as i can,and i was trying to reverse a string using recursion
i didn't know how to do it at first,tried many different ways to do it,but i saw code samples on string reversing,but none of it made sense to me,so i made my own one,but not quite sure of it,i'm just asking for opinion,is it clean and functional??
Thank You
Using a function local static variable in a recursive function is a bad idea. Recursive functions should get all their state as input arguments.
Here's a simplified version that divides the logic into two functions.
void ReverseString(string &S, int start, int end)
{
if ( start < end )
{
swap(S[start], S[end - 1]);
ReverseString(S, start+1, end - 1);
}
}
void ReverseString(string &S)
{
ReverseString(S, 0, S.size());
}
Most of the time, higher level functions would only call the second function. The first function can be called from a higher level function if there is a need to reverse only a subset of a string.
Here's a sample program
#include <iostream>
#include <string>
using namespace std;
void ReverseString(string &S, int start, int end)
{
if ( start < end )
{
swap(S[start], S[end - 1]);
ReverseString(S, start+1, end - 1);
}
}
void ReverseString(string &S)
{
ReverseString(S, 0, S.size());
}
int main()
{
string s = "The string to reverse" ;
cout << "Before Reversing" << endl;
cout << s << endl;
ReverseString(s);
cout << "After Reversing" << endl;
cout << s << endl;
ReverseString(s, 0, 7);
cout << "After Reversing a subset" << endl;
cout << s << endl;
return 0;
}
and its output
Before Reversing
The string to reverse
After Reversing
esrever ot gnirts ehT
After Reversing a subset
reverse ot gnirts ehT
See it working at https://ideone.com/9nMlsP.
is it ... functional??
If by "functional" you mean "does it work", then you tell me.
If you mean "functional" as in "functional" programming style, then no it isn't. In functional style, you don't modify arguments in place, but instead return a new value. Also relying on global state (i.e. static objects) is very anti-functional.
Here is an example:
std::string
ReverseString(std::string_view sv)
{
if (sv.empty())
return "";
std::string_view x = sv.substr(0, 1)
std::string_view xs = sv.substr(1);
return ReverseString(xs) + x;
}
// usage
s = ReverseString(s);
In future, if Pattern matching was introduced to the language, then it could potentially be written like this:
std::string
ReverseString(std::string_view sv)
{
inspect(sv) {
"": return "";
[x:xs]: return ReverseString(xs) + x;
}
}
However, the current proposal does not suggest introducing support for matching ranges like this, so this is highly theoretical.
Local static variables are dangerous. Since their state will remain between function calls. In my approach i used slen as the length of a string and the currentIndex as the last swapped index on the string. Since it is enough to swap till the middle of the string, finish case is when (currentIndex == slen/2).
I also added some test cases as an example.(even length, odd length, zero case and palindrome)
#include <iostream>
#include <string>
using namespace std;
void ReverseString(string &S, int currentIndex, int slen)
{
if (slen / 2 == currentIndex) return;
swap(S[currentIndex], S[slen - 1 - currentIndex]);
currentIndex++;
ReverseString(S, currentIndex, slen);
}
void testReverseString() {
string s = "";
ReverseString(s, 0, s.length());
assert(s == "");
s = "ahmet";
ReverseString(s, 0, s.length());
assert(s == "temha");
s = "ahaha";
ReverseString(s, 0, s.length());
assert(s == "ahaha");
s = "haha";
ReverseString(s, 0, s.length());
assert(s == "ahah");
}
int main()
{
testReverseString();
return 0;
}
Your function with a static variable can be called only once because after its recursive calls the static variable start will not be equal to 0 as it is required. So the function is not "functional".
Here is a demonstrative program that shows how the function can be written with using a static variable and without using a static variable.
#include <iostream>
#include <string>
#include <utility>
void ReverseString1( std::string &s )
{
static std::string::size_type i = 0;
if ( not ( s.size() - 2 * i < 2 ) )
{
std::swap( s[i], s[s.size() - i - 1] );
++i;
ReverseString1( s );
--i;
}
}
void ReverseString2( std::string &s, std::string::size_type pos = 0 )
{
if ( not ( s.size() - 2 * pos < 2 ) )
{
std::swap( s[pos], s[s.size() - pos - 1] );
ReverseString2( s, pos + 1 );
}
}
int main()
{
std::string s( "Hello World!" );
std::cout << s << '\n';
ReverseString1( s );
std::cout << s << '\n';
ReverseString2( s );
std::cout << s << '\n';
return 0;
}
The program output is
Hello World!
!dlroW olleH
Hello World!
Anyone can reverse a string one char at a time, but much cooler is to reverse each third of the string and swap the outer thirds. This cuts stack depth as well as sowing confusion amongst the competition. Note that max stack depth of recursion per character is N, whereas this is cube root of N.
#include <iostream>
#include <string>
using namespace std;
void ReverseRegion(string &s, int start, int sz)
{
// regions < 2 need no action
if (sz == 2) {
char tmp = s[start];
s[start] = s[start+1];
s[start+1] = tmp;
} else if (sz > 2) {
int s3 = sz/3;
ReverseRegion(s, start, s3);
string tmp = s.substr(0,start) + s.substr(start+sz-s3,s3) + s.substr(start+s3, sz-2*s3) + s.substr(start,s3) + s.substr(start+sz);
// cout << "do: " << tmp << "\n";
s = tmp;
ReverseRegion(s, start+s3, sz-2*s3);
ReverseRegion(s, start, s3);
}
}
void ReverseString(string &S)
{
ReverseRegion(S, 0, S.size());
}
int main()
{
cout << "enter a string to reverse" << endl;
string s;
getline(cin, s);
cout << "Before Reversing" << endl;
cout << s << endl;
ReverseString(s);
cout << "After Reversing" << endl;
cout << s << endl;
return 0;
}
Related
I'm stuck on a particular problem. I'm trying to take a string, and reverse the character cases in the string.
For Example: "HaVinG FuN" should flip to "hAvINg fUn."
I think it has something to do with my loop or my If/Else statements. What am I missing? All capitalized characters come out capitalized still. All lower case characters also come out capitalized as well... My other two functions are behaving correctly, but not my reverseFunct function... FYI I've omitted the other functions to try to cut-down on clutter and focus on my problem.
#include "stdafx.h"
#include <string>
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
// Function Prototypes
void upperFunct(char *);
void lowerFunct(char *);
void reverseFunct(char *);
int main()
{
cout << "Enter a string: " << endl;
char ltrs [300];
cin.getline(ltrs, 300);
char *ptr = nullptr;
ptr = ltrs;
upperFunct(ptr);
lowerFunct(ptr);
reverseFunct(ptr);
return 0;
}
//----------------------------------//
void upperFunct(char *ltrptr)
{
int count = 0;
while (ltrptr[count] != '\0')
{
ltrptr[count] = toupper(ltrptr[count]);
count++;
}
{
cout << "---> toupper function: " << ltrptr << endl;
}
}
//------------------------------------//
void lowerFunct(char *ltrptr)
{
int count = 0;
while (ltrptr[count] != '\0')
{
ltrptr[count] = tolower(ltrptr[count]);
count++;
}
cout << "---> tolower function: " << ltrptr << endl;
}
//------------------------------------//
void reverseFunct(char *ltrptr) // <-----NOT REVERSING CHARACTERS
{
int count = 0;
while (ltrptr[count] != '\0')
{
if (isupper(ltrptr[count]))
{
ltrptr[count] = tolower(ltrptr[count]);
}
else
{
ltrptr[count] = toupper(ltrptr[count]);
}
count++;
}
cout << "---> reverse function: " << ltrptr << endl;
}
Your check for lowercase letters reads as
else if (islower(ltrptr[count]));
Notice the extra semicolon.
This semicolon terminates the if statement, and thus the succeeding conversion to uppercase is not a then-clause to this if statement but rather is executed unconditionally on every character.
Change like this
// Function Prototypes "HaVinG FuN" should flip to "hAvINg fUn."
void reverseFunct(char *);
int main()
{
//cout << "Enter a string: " << endl;
char ltrs[300] = "HaVinG FuN";
//cin.getline(ltrs, 300);
char *ptr = nullptr;
ptr = ltrs;
reverseFunct(ptr);
ptr = nullptr;
return 0;
}
void reverseFunct(char *ltrptr) // <-----NOT REVERSING CHARACTERS
{
int count = 0;
while (ltrptr[count] != '\0')
{
if (isupper(ltrptr[count]))
{
ltrptr[count] = tolower(ltrptr[count]);
}
else
{
ltrptr[count] = toupper(ltrptr[count]);
}
count++;
}
cout << "---> reverse function: " << ltrptr << endl;
}
You're writing C code. Here's a C++ way to do it:
#include <string>
#include <algorithm>
char reverse_case_char(char c) {
const auto uc = static_cast<unsigned char>(c); // Sic.
return ::isupper(uc)? ::tolower(uc): ::toupper(uc);
}
void reverse_case(std::string& str) {
std::transform(str.begin(), str.end(), str.begin(), reverse_case_char);
}
#include <cassert>
int main()
{
std::string fun = "HaVinG FuN";
reverse_case(fun);
assert(fun == "hAvINg fUn");
return 0;
}
Others have already pointed out the mistake in your code so no need to repeat that. Instead this answer will give some alternative ways of implementing the task.
Your code is more C-style than C++ style. C++ has a number of functions/features that will allow you to write this in much shorter forms.
char ltrs[300] = "HaVinG FuN";
for (auto& ch : ltrs) ch = islower(ch) ? toupper(ch) : tolower(ch);
std::cout << ltrs << std::endl;
or
char ltrs[300] = "HaVinG FuN";
std::for_each(ltrs, ltrs + strlen(ltrs), [](char& ch)
{ ch = islower(ch) ? toupper(ch) : tolower(ch); });
std::cout << ltrs << std::endl;
or using the std::string
std::string str("HaVinG FuN");
for (auto& ch : str) ch = islower(ch) ? toupper(ch) : tolower(ch);
std::cout << str << std::endl;
Using these C++ functions/features makes the program shorter, easier to understand and the risk of bugs is lower.
Thanks for the help!!! I ended up figuring out my answer, while being able to maintain my less-than elegant code that is fitting with my class. Bipll ended up giving me what I was after, something to think about in terms that my original array was being modified each time.
I realize that my solution is sloppy and not appropriate for a work environment, but it is in-line with my homework assignment, as our teacher is encouraging us to learn C++ from the ground-up, not getting too much direct answers from places like SO. So I'm glad I learned a bit from here, as well as an indirect way to help me see my issues.
I ended up making a copy of my original array, and just passing that copy to my last reversing function. I was able to use the original array for the first 2 functions because the 1st function capitalized each character in the array, while the 2nd made them all lowercase. The 3rd function, the reverse, therefore had to have access to the original array, but in the 3rd order. The easiest way for a noob like me, given where I am in the class, was to make a copy of the 1st array and use that for the 3rd function.
//Snippet of code I needed
int main()
{
int index = 0;
cout << "Enter a string: " << endl;
const int Size = 300;
char ltrs[Size];
cin.getline(ltrs, Size);
char arrayCopy[Size];
char *ptr = nullptr;
char *ptr2 = nullptr;
ptr = ltrs;
//Copy of ltrs Array
//----------------------------------//
while (ptr[index] != '\0') //
{ //
arrayCopy[index] = ptr[index]; //
index++; //
} //
arrayCopy[index] = '\0'; //
//
ptr2 = arrayCopy; //
//----------------------------------//
return 0;
}
// Function to Reverse
void reverseFunct(char *ltrptr)
{
int count = 0;
while (ltrptr[count] != '\0')
{
if (isupper(ltrptr[count]))
{
ltrptr[count] = tolower(ltrptr[count]);
}
else
{
ltrptr[count] = toupper(ltrptr[count]);
}
count++;
}
cout << "---> reverse function: " << ltrptr << endl;
}
This comment suggests that there is a O(n) alternative to my O(n log n) solution to this problem:
Given string str("helloWorld") the expected output is:
l = 3
o = 2
My solution was to do this:
sort(begin(str), end(str));
for(auto start = adjacent_find(cbegin(str), cend(str)), finish = upper_bound(start, cend(str), *start); start != cend(str); start = adjacent_find(finish, cend(str)), finish = upper_bound(start, cend(str), *start)) {
cout << *start << " = " << distance(start, finish) << endl;
}
Which is obviously limited by the sorting of str. I think this would require a bucket sort solution? Is there anything more clever that I'm missing?
Here's one way, which is O(N) at the expense of maintaining storage for every possible char value.
#include <string>
#include <limits.h> // for CHAR_MIN and CHAR_MAX. Old habits die hard.
int main()
{
std::string s("Hello World");
int storage[CHAR_MAX - CHAR_MIN + 1] = {};
for (auto c : s){
++storage[c - CHAR_MIN];
}
for (int c = CHAR_MIN; c <= CHAR_MAX; ++c){
if (storage[c - CHAR_MIN] > 1){
std::cout << (char)c << " " << storage[c - CHAR_MIN] << "\n";
}
}
}
This portable solution is complicated by the fact that char can be signed or unsigned.
Here is what #bathsheba mentioned and with improvements by #Holt:
#include <string>
#include <climits>
#include <iostream>
void show_dup(const std::string& str) {
const int sz = CHAR_MAX - CHAR_MIN + 1;
int all_chars[sz] = { 0 };
// O(N), N - the length of input string
for(char c : str) {
int idx = (int)c;
all_chars[idx]++;
}
// O(sz) - constant. For ASCII char it will be 256
for(int i = 0; i < sz; i++) {
if (all_chars[i] > 1) {
std::cout << (char)i << " = " << all_chars[i] << std::endl;
}
}
}
int main()
{
std::string str("helloWorld");
show_dup(str);
}
I would like to make an array of words like: "Tom", "Mike","Tamara","Nik"... I would like to make for user to be possible to enter for instance a number 3, and get a random return of words that have the length of 3 so eather ("Tom" or "Nik"). I think this is done with pointers but I don't know how. Words should be stored in different arrays depending on their length. And with pointers you would point to each array ("Tom","Nik" in same array "Tamara" in different array and "Mike" in different array and so on... because their length is not the same). Can someone please help ?
#include<iostream>
#include <string>
using namespace std;
void IzpisPolja(char **polje,int velikost){
int tab[100];
for (int i=0; i<velikost; i++) {
cout<<polje[i]<<endl;
char *zacasni;
tab[i] = strlen(polje[i]);
// cout<<tab[i]<<endl;
}
}
int main(){
const int size = 4;
char* tabelaOseb[size] = {"Tom", "Mike","Tamara","Nik"};
IzpisPolja(tabelaOseb,size);
return 0;
}
Do you want to do it efficiently ? Storing them in separate arrays will increase search time but also increase insertion, deletion complexity.
Otherwise you can just count number of instances of n length words in an array, then generate random number and return the ith of them.
Also suggest using std::vector
const string* getRandNameOfLength(const string* arr,
const int arrlen,
const int length)
{
int num = 0, j, i;
// Counting number of such names
for (i = 0; i < arrlen; ++i)
{
if (arr[i].size() == length)
num++;
}
// No such name found
if (num == 0)
return NULL;
j = rand() % num;
// Returning random entry of given length
for (i = 0; i < arrlen; ++i)
{
if (arr[i].size() == length && j-- == 0)
return &arr[i];
}
// Function shouldn't get here
return NULL;
}
You can use raw pointers to perform your task, of course, but you can also start using some of the many safer facilities that the language (references, iterators and smart pointers) and the C++ standard library can offer.
I'll show you a complete program that can do what you are asking using conteiners (std::vector, std::map) and algorithms (like std::lower_bound) that can really simplify your work once understood.
Note that as a learning exercise (for both of us), I have used as many "new" features as I could, even when maybe wasn't necessary or handy. Read the comments for better understanding.
The words are stored and managed in a class, while the interaction with the user is performed in main().
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <limits>
#include <algorithm>
#include <random> // for mt19937, uniform_int_distribution
#include <chrono> // for high_resolution_clock
size_t random_index( size_t a, size_t b ) {
// Initialize Random Number Generator Engine as a static variable. - Since c++11, You can use those instead of old srand(time(NULL))
static std::mt19937 eng{static_cast<long unsigned int>(std::chrono::high_resolution_clock::now().time_since_epoch().count())};
// use the RNG to generate random numbers uniformly distributed in a range
return std::uniform_int_distribution<size_t>(a,b)(eng);
}
using svs_t = std::vector< std::string >; // I store the words with equal length in a std::vector of std::string
// like typedef, I'll use svs_t instead of std::vector<std::string>
auto string_less_then = [] (const std::string & a, const std::string & b) -> bool { return a.compare(b) < 0; };
// A lambda function is a mechanism for specifying a function object, its primary use is to specify a simple
// action to be performed by some function. I'll use it to compare two string and return true only if a<b
class word_table {
std::map< size_t, svs_t > words; // std::map store elements formed by a combination of a key value and a mapped value, sorted by key
// I'll use word's length as a key for svs_t values
public:
word_table() {}
word_table( std::initializer_list<std::string> vs ) {
insert_words(vs);
}
void insert_words( svs_t vs ) {
for ( auto && s : vs ) add_word(s); // loop for each value in vs, "auto" let the compiler infer the right type of the variable
}
bool add_word( std::string s ) { // I choose to keep the vector sorted and with unique elements
size_t sl = s.length();
if ( sl > 0 ) {
auto & v = words[sl]; // If sl doesn't match the key of any element in the map, a new element is created
// lower_bound return an iterator that poins to the first element in range (begin,end)
auto it = std::lower_bound(v.begin(), v.end(), s, string_less_then); // which does not compare less than s
// I pass the compare function as a lambda
if ( it != v.end() && it->compare(s) == 0 ) return false; // Already present, duplicates not allowed
v.insert(it, s); // Not the most efficient way, but you seem focused on the random access part
return true;
}
return false;
}
bool remove_word( std::string s) {
size_t sl = s.length();
if ( sl > 0 ) {
auto itvw = words.find(sl); // first find the right element in the map, using the string length as a key, but if word is found
if ( itvw == words.end() ) return false; // an iterator to the element following the last element of the container is returned
auto & v = itvw->second; // In a map the elements are stored in pairs, first is the key, second the value
auto it = std::lower_bound(v.begin(), v.end(), s, string_less_then);
if ( it != v.end() && it->compare(s) == 0 ) {
v.erase(it);
if ( v.empty() ) words.erase(itvw);
return true;
}
}
return false;
}
std::string get_random_word( size_t length ) {
if ( length == 0 ) return "";
auto itvw = words.find(length);
if ( itvw == words.end() || itvw->second.empty() ) return "";
return itvw->second[random_index(0, itvw->second.size() - 1)];
}
void show_all() {
for ( auto && i : words ) {
std::cout << " ";
for (auto && w : i.second ) {
std::cout << w << ' ';
}
std::cout << '\n';
}
}
};
constexpr size_t ss_max = std::numeric_limits<std::streamsize>::max();
namespace opt {
enum options { wrong = -1, exit, show, random, add, remove, menu };
}
class menu {
std::map<int,std::string> opts;
public:
menu( std::initializer_list<std::pair<int,std::string>> il ) {
for ( auto && i : il ) opts.insert(i);
}
void show() {
std::cout << "\nYou can choose among these options:\n\n";
for ( auto && i : opts ) {
std::cout << " " << i.first << ". " << i.second << ".\n";
}
}
};
int main()
{
word_table names({"Tom", "Mike","Tamara","Robert","Lenny","Nick","Alex","Sue","Irina","Beth","Anastacia","Bo"});
int choise = opt::exit;
menu menu_options { {opt::exit, "Exit program"}, {opt::show, "Show all stored names"},
{opt::random, "Show a random name"}, {opt::add, "Add a new name"},
{opt::remove, "Remove a name"} };
menu_options.show();
do {
std::cout << "\nPlease, enter a number (" << opt::menu << " to show again all options): ";
std::cin >> choise;
if ( std::cin.fail() ) { // the user enter something that is not a number
choise = opt::wrong;
std::cin.clear();
std::cin.ignore(ss_max,'\n');
}
if ( std::cin.eof() ) break; // use only if you are redirecting input from file
std::string str;
switch ( choise ) {
case opt::exit:
std::cout << "\nYou choose to quit, goodbye.\n";
break;
case opt::show:
std::cout << "\nAll the stored names, classified by word\'s length:\n\n";
names.show_all();
break;
case opt::random:
size_t l;
std::cout << "Please, enter the length of the name: ";
std::cin >> l;
if ( std::cin.good() ) {
std::string rs = names.get_random_word(l);
if ( rs == "" ) {
std::cout << "\nNo name of length " << l << " has been found.\n";
} else {
std::cout << "\n " << rs << '\n';
}
}
break;
case opt::add:
std::cout << "Please, enter the name You want to add: ";
std::cin >> str; // read a string from cin, you can write more than a word (separeted by spaces)
std::cin.ignore(ss_max,'\n'); // but only the first is stored
if ( names.add_word(str) ) {
std::cout << "\n The name " << str << " has been successfully added.\n";
} else {
std::cout << "\n No name has been added";
if ( str != "" ) std::cout << ", "<< str << " is already present.\n";
else std::cout << ".\n";
}
break;
case opt::remove:
std::cout << "Please, enter the name You want to remove: ";
std::cin >> str;
if ( names.remove_word(str) ) {
std::cout << "\n " << str << " has been succesfully removed.\n";
} else {
std::cout << "\n No name has been removed";
if ( str != "" ) std::cout << ", " << str << " wasn't found.\n";
else std::cout << ".\n";
}
break;
case opt::menu:
menu_options.show();
break;
default:
std::cout << "\n Sorry, that's not an option.\n";
}
} while ( choise != opt::exit );
return 0;
}
I hope it could help.
#include <iostream>
#include <vector>
#include <cstring>
#include <ctime>
#include <cstdlib>
using namespace std;
const char* return_rand_name(const char** names, size_t length)
{
std::vector<size_t> indexes;
for(int i=0; names[i][0] != 0; ++i)
if(strlen(names[i]) == length)
indexes.push_back(i);
if(indexes.size()==0)
return NULL;
return names[indexes[rand()%indexes.size()]];
}
int main()
{
srand(time(NULL));
const char* names[] = {"Alex","Tom","Annie","Steve","Jesus","Leo","Jerry",""};
std::cout << return_rand_name(names, 3) << std::endl;
return 0;
}
And if you want to use functions like strlen etc, include <cstring>, not <string> (which contains class template std::string (which you should use in C++ (instead of char*) ) )
I'm trying not to use any storage containers. I don't know if it's even possible. Here is what I have so far. (I'm getting a segmentation fault).
#include <iostream>
#include <string>
using namespace std;
void foo(string s)
{
size_t pos;
pos = s.find(' ');
if(pos == string::npos)
return;
foo(s.erase(0, pos));
cout << s.substr(0, pos) << " ";
}
int main()
{
foo("hello world");
return 0;
}
I know there's probably many things wrong with this code. So rip away. I'm eager to learn. I'm trying to imitate a post order print as you would do in a reverse print of a singly linked list. Thanks.
EDIT:
An example:
"You are amazing" becomes "amazing are You"
The segfault is a stack overflow.
foo( "hello world" ) erases everything up to the first space (" world") and recurses.
foo( " world" ) erases everything up to the first space (" world") and recurses.
foo( " world" )... you get the idea.
Also, once you called foo( s.erase( 0, pos ) ), trying to print s.substr( 0, pos ) after the recursion returns does not make sense. You need to save the substring somewhere before you erase it, so you still have it to print afterwards.
void foo(string s)
{
size_t pos = s.find(' '); // declare-and-use in one line
string out = s.substr( 0, pos ); // saving the substring
if ( pos != string::npos )
{
foo( s.erase( 0, pos + 1 ) ); // recurse, skipping the space...
cout << " "; // ...but *print* the space
}
cout << out; // print the saved substring
}
The problem is that your recursion continues until you run out of memory.
Pay attention to this line:
if(pos == string::npos)
when your erase the substring you don't erase the white space so in the next recursion s.find returns pos = 0 which means that your recursion never ends.
Here is a code that works. Also note that I added a level variable to be able to control the behaviour on the first level (in this case add a endl)
#include <iostream>
#include <string>
using namespace std;
void foo(string s, int l)
{
size_t pos;
pos = s.find(' ');
if(pos == string::npos){
cout << s << " ";
return;
}
string temp = s.substr(0, pos);
foo(s.erase(0, pos+1),l+1);
cout << temp << " ";
if(l == 0)
cout << endl;
}
int main()
{
foo("hello world", 0);
return 0;
}
An approach to recursion, which may allow your compiler to transform automatically to iteration, is to accumulate the result in the function arguments. This will be familiar if you've written recursive functions in any of the Lisp family of languages:
#include <iostream>
#include <string>
std::string reverse_words(const std::string& s, const std::string& o = {})
{
using std::string;
const auto npos = string::npos;
static const string whitespace(" \n\r\t");
// find start and end of the first whitespace block
auto start = s.find_first_of(whitespace);
if (start == npos)
return s + o;
auto end = s.find_first_not_of(whitespace, start);
if (end == npos)
return s + o;
auto word = s.substr(0, start);
auto space = s.substr(start, end-start);
auto rest = s.substr(end);
return reverse_words(rest, space + word + o);
}
int main()
{
std::cout << reverse_words("hello to all the world") << std::endl;
std::cout << reverse_words(" a more difficult\n testcase ") << std::endl;
return 0;
}
I tried to make a brief example by using standard algorithms. I also handles more kinds of spaces than just standard whitespace (tabs for instance).
#include <cctype>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
void print_reverse(string words) {
// Termination condition
if(words.empty())
return;
auto predicate = (int(*)(int))isspace;
auto sit = begin(words);
auto wit = find_if_not(sit, end(words), predicate);
auto nit = find_if (wit, end(words), predicate);
print_reverse(string(nit, end(words)));
// word spaces
cout << string(wit, nit) << string(sit, wit);
}
int main() {
string line;
getline(cin, line);
print_reverse(line);
cout << endl;
}
Here is an example run:
$ ./print-out-the-words-of-a-line-in-reverse-order-through-recursion
You are amazing
amazing are You
The key is in adding 1 to pos in the erase statement.
So try:
#include <iostream>
#include <string>
using namespace std;
void foo(string s)
{
size_t pos;
pos = s.find(' ');
if(pos == string::npos)
{
cout << s << " ";
return;
}
string out = s.substr(0, pos);
foo(s.erase(0, pos+1));
cout << out << " ";
}
int main()
{
foo("hello world");
cout << endl;
return 0;
}
EDIT
Alternatively you could use a char* instead of a std::string, then you do not need to make a temp variable. Try it online.
#include <iostream>
#include <cstring>
void foo(char* s)
{
char* next = std::strchr(s, ' ');
if(next != nullptr)
{
foo(next + 1);
*next = 0;
}
std::cout << s << " ";
}
int main()
{
char s[] = "You are amazing";
foo(s);
std::cout << std::endl;
}
The problem is that you're not doing anything with the last word and you're not doing anything with the remaining chunk.
If you have a recursive reverse printer, you'll want something like this (pseudocode):
def recursive-reverse(string) {
pos = string.find-last(" ");
if pos doesn't exist {
print string;
return;
} else {
print string.create-substring(pos+1, string.end);
recursive-reverse(string.create-substring(0, pos));
}
}
To implement this in C++:
#include <iostream>
#include <string>
void recursive_reverse(std::string &s) {
// find the last space
size_t pos = s.find_last_of(" ");
// base case - there's no space
if(pos == std::string::npos) {
// print only word in the string
std::cout << s << std::endl;
// end of recursion
return;
} else {
// grab everything after the space
std::string substring = s.substr(pos+1);
// print it
std::cout << substring << std::endl;
// grab everything before the space
std::string rest = s.substr(0, pos);
// recursive call on everything before the space
recursive_reverse(rest);
}
}
int main() {
std::string s("Hello World!");
recursive_reverse(s);
return 0;
}
ideone
I'm a beginner on programming. I'm coding a school assignment and its asking me to add commas to a string using recursion. I have most of it done but when I input a number greater than a million it doesn't add a comma before the first digit. This is what i have so far:
// commas - Convert a number (n) into a string, with commas
string commas(int n) {
ostringstream converted;
converted << n;
string number = converted.str();
int size = number.length();
if (size < 4 )
{
return number;
}
if (size >= 4 )
{
return number.substr(0, number.size() - 3) + "," + number.substr(number.size() - 3, number.length());
}
}
Any help would be greatly appreciated!
The algorithm is fairly simple. It is very similar to your solution except I added the part necessary for recursion. To understand how it works, remove tack_on. Here is example output:
1
10
100
These are the first groups that are returned when the terminating condition is reached (s.size() < 4). Then the rest of the groups are prefixed with a comma and "tacked on". The entire string is built using recursion. This is important because if you left number.substr(0, number.size() - 3) in, your output would look like this:
11,000
1010,000
100100,000
11,0001000,000
I use std::to_string which is C++11:
#include <iostream>
std::string addCommas(int n)
{
std::string s = std::to_string(n);
if (s.size() < 4) return s;
else
{
std::string tack_on = "," + s.substr(s.size() - 3, s.size());
return addCommas(n / 1000) + tack_on;
}
}
You only need to make minimal changes for the C++03/stringstream version:
#include <sstream>
std::ostringstream oss;
std::string addCommas(int n)
{
oss.str(""); // to avoid std::bad_alloc
oss << n;
std::string s = oss.str();
// etc
}
Testing:
int main()
{
std::cout << addCommas(1) << "\n";
std::cout << addCommas(10) << "\n";
std::cout << addCommas(100) << "\n";
std::cout << addCommas(1000) << "\n";
std::cout << addCommas(10000) << "\n";
std::cout << addCommas(100000) << "\n";
std::cout << addCommas(1000000) << "\n";
return 0;
}
Output:
1
10
100
1,000
10,000
100,000
1,000,000
I think this one is a bit simpler and easier to follow:
std::string commas(int n)
{
std::string s = std::to_string(n%1000);
if ((n/1000) == 0) return s;
else
{
// Add zeros if required
while(s.size() < 3)
{
s = "0" + s;
}
return commas(n / 1000) + "," + s;
}
}
an alternative approach without recursion:
class Grouping3 : public std::numpunct< char >
{
protected:
std::string do_grouping() const { return "\003"; }
};
std::string commas( int n )
{
std::ostringstream converted;
converted.imbue( std::locale( converted.getloc(), new Grouping3 ) );
converted << n;
return converted.str();
}
will need #include <locale> in some environments
A possible solution for the assignment could be:
std::string commas( std::string&& str )
{
return str.length() > 3?
commas( str.substr( 0, str.length()-3 ) ) + "," + str.substr( str.length()-3 ):
str;
}
std::string commas( int n )
{
std::ostringstream converted;
converted << n;
return commas( converted.str() );
}