I have an assignment I am working on that uses recursion. I'm still having a little trouble understanding recursion, or at least how it all works, but I think I'm starting to grasp it, even though I'm not all that sure why anything works.
My assignment has two parts, but for the moment, I just need a little help with the first part. Here's what I have to do:
Write a recursive function that will return the position of the first occurence of a >character within a C String
This is what I have so far...
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;
int test(string s, char x);
int main ()
{
test("lets test for the letter s", "s" );
}
int test(string s, char x)
{
if(s.length() == 0)
return 0;
else if (s[0] == x)
return 1 + test(s.substr(1, s.length()), x);
else
return test(s.substr(1, s.length()), x);
}
So i think this should work, but I'm a little confused as to how to get the function to test anything. I'm pretty sure I have the string part done correctly in my function call in main, but I can't get the char to accept a value. The way I understand it, i should enter the text I want to scan, and then the character I want to look for. Can anyone tell me what I am doing wrong, or even I'm even close with the recursive function?
You should do something like the following:
int main ()
{
test("lets test for the letter s", 's');
//should pass char constant
//not string literal for second parameter
}
int test(string s, char x)
{
if(s.length() == 0)
return 0;
else if (s[0] == x)
return 1 + test(s.substr(1, s.length()-1), x);
//^^^second parameter of substring is length
else
return test(s.substr(1, s.length()), x);
}
Character constants go in single quotes. To test your function write something like:
cout << test("lets test for the letter s", 's') << endl;
As for your recursive function, you're close. The if statements have the right tests, you just need to adjust the return statements a bit.
if (s.length() == 0)
return -1;
If the string is empty the character isn't found. I suggest returning -1 rather than 0 because a return value of 0 suggests (to me) that the character was found at position 0. -1 is the traditional return code from functions like these when a character isn't found.
else if (s[0] == x)
return 0;
Do you see why this is return 0? You found the character x at index 0, so that's what you should return: 0!
else
return 1 + test(s.substr(1, s.length() - 1), x);
The last test is the only one that needs to be recursive. Here's where you put the 1 +. And you also need to reduce length() by 1.
"s" will be treated as a char array or a string. To represent a single char you should use 's'
int main ()
{
cout << "location = " << test("lets test for the letter s", 's' );
^^^^
}
Related
I am trying to find the length of the longest consecutive character('!') in a string.
For example, input:
!!!!Hello!!
Output:
4
I am trying to solve this problem with recursion and this is my approach:
unsigned int length_of_longest_consecutive_dquotes(const char line[], int start)
{
if (line[start] != '\0') {
if (line[start] == '!') {
return length_of_longest_consecutive_mark(line,start+1) + 1;
}
else
return length_of_shortest_consecutive_mark(line,start+1);
}
return 0;
}
Where Start = 0; I am not able to figure out what shall I implement in the length_of_shortest_consecutive_dquotes(line,start) function.
Please suggest me some better algorithm for implementing it. Thanks!
At each iteration you have to remember the preceding parsed character, and then compare with the first of the remaining part of the array. If they are the same then add one to the length of the current possible longest sequence, if not length is 1 (the length of a new possible longest sequence). Of course you also have to remember the highest length.
Something like that?
#include <iostream>
unsigned int length_of_longest_consecutive(char previous,const char *line,int ll,int current_length)
{
if (*line==0) return ll>current_length?ll:current_length;
if (*line==previous) {
return length_of_longest_consecutive(*line,line+1,ll,current_length+1);
}
return length_of_longest_consecutive(*line,line+1,ll>current_length?ll:current_length,1);
}
int main() {
const char *a = "a!!!b!!!!ccccc!!d";
std::cout << length_of_longest_consecutive('\0',a,0,0) << std::endl;
}
I am really having a hard time getting recursions but i tried recursion to match a pattern inside a string.
Suppose i have a string geeks for geeks and i have a pattern eks to match.I could use many methods out there like regex, find method of string class but i really want to do this thing by recursions.
To achieve this i tried this code:
void recursion(int i,string str)
{
if(!str.compare("eks"))
cout<<"pattern at :"<<i<<'\n';
if(i<str.length() && str.length()-1!=0)
recursion(i,str.substr(i,str.length()-1));
}
int main()
{
string str("geeks for geeks");
for(int i=0;i<str.length();i++)
recursion(i,str.substr(i,str.length()));
}
Output :
Desired Ouput :
pattern at 2
pattern at 12
What could i be doing wrong here and what would be a good way to do this with recursions?
I understood a lot of topics in cpp but with recursions , i know how they work and even with that whenever i try to code something with recursions , it never works.Could there be any place that could help me with recursions as well?
You will never get pattern at 2, since compare doesn't work like that. Ask yourself, what will
std::string("eks for geeks").compare("eks")
return? Well, according to the documentation, you will get something positive, since "eks for geeks" is longer than "eks". So your first step is to fix this:
void recursion(int i, std::string str){
if(!str.substr(0,3).compare("eks")) {
std::cout << "pattern at: " << i << '\n';
}
Next, we have to recurse. But there's something off. i should be the current position of your "cursor". Therefore, you should advance it:
i = i + 1;
And if we reduce the length of the string in every iteration, we must not test i < str.length, otherwise we won't check the later half of the string:
if(str.length() - 1 > 0) {
recursion(i, str.substr(1));
}
}
Before we actually compile this code, let's reason about it:
we have a substring of the correct length for comparison with "eks"
we never use i except for the current position
we advance the position before we recurse
we "advance" the string by removing the first character
we will end up with an empty string at some point
Seems reasonable:
#include <iostream>
#include <string>
void recursion(int i, std::string str){
if(!str.substr(0,3).compare("eks")) {
std::cout << "pattern at: " << i << '\n';
}
i = i + 1;
if(str.length() - 1 > 0) {
recursion(i, str.substr(1));
}
}
int main () {
recursion(0, "geeks for geeks");
return 0;
}
Output:
pattern at: 2
pattern at: 12
However, that's not optimal. There are several optimizations that are possible. But that's left as an exercise.
Exercises
compare needs to use substr due to it's algorithm. Write your own comparison function that doesn't need substr.
There's a lot of copying going on. Can you get rid of that?
The for loop was wrong. Why?
Recursive function must not run into loop. And you have some mistakes.Try this code.
void recursion(string str, string subStr, int i){
if(str.find(subStr) != string::npos ) {
int pos = str.find(subStr);
str = str.substr(pos + subStr.length(), str.length()-1);
cout << "pattern at " << (pos + i) << endl;
recursion(str, subStr, pos+subStr.length() );
}
}
int main(int argc, char** argv) {
string str("geeks for geeks");
string subStr("eks");
recursion(str, subStr, 0);
return 0;
}
Question - Given a string a '0', '1' and '?'. Generate all possible strings where you can replace '?' with '0' or '1' ?
For eg - Input - "0??"
Output - "000", "001", "010", "011".
I have written a simple program for it -
void gen(string& str, int index)
{
int i;
if(str.length() == index)
{
cout << str << endl;
return;
}
else
{
for(i=index; str[i]!='\0' && str[i]!='?';i++);
if(str[i] == '?')
{
str[i] ='0';
gen(str,i+1);
str[i] ='1';
gen(str,i+1);
}
}
return;
}
int main()
{
string s ="0??";
gen(s, 0);
return 0;
}
It is not working correctly....
BUT IF YOU REPLACE THE ARGUMENT IN void gen(String &, int) to
void gen(String, int)....
THEN IT WILL WORK CORRECTLY..
Can Anyone explain me please....
When you pass the string by reference, there is a single string that is operated on by all of the recursive calls to gen() - instead of each call to gen() working on its own local copy. Each recursive call to gen() modifies the (shared) string, removing all the '?' characters; when that call returns, there are no more '?' characters left to process so it simply terminates.
when you pass the string by value, each invocation of the gen() function gets its own local copy of the string; Any changes it makes to that string are thrown away and forgotten when the function returns to the previous level. In this case your logic is correct.
(There was also a bug which caused it to crash on my Windows machine until I fixed it: std::string is not null-terminated, so rather than checking for std[i] == '\0' you should do something like i < str.length().)
reference will maintain the value changed in the function call
after set str[1] ='0';
sub call: gen(str,2); will output combination: 000 001
reset str[1] ='1';
str is still 011
gen(str,i+1); output nothing
hope this piece of code can help
#include <string>
#include <iostream>
#include <stdio.h>
using namespace std;
void gen(string& str, int index)
{
int i;
if(str.length() == index)
{
cout << str << endl;
return;
}
else
{
for(i=index; str[i]!='\0' && str[i]!='?';i++);
if(str[i] == '?')
{
printf("before set pos %d to 0: %s\n",i,str.c_str());
str[i] ='0';
printf("after set pos %d to 0: %s\n",i,str.c_str());
gen(str,i+1);
printf("before set pos %d to 1: %s\n",i,str.c_str());
str[i] ='1';
printf("after set pos %d to 1: %s\n",i,str.c_str());
gen(str,i+1);
}
}
return;
}
int main()
{
string s ="0??";
gen(s, 0);
return 0;
}
it outputs:
One simple solution will be:
As each '?' should be replaced with 0 and 1, we can see that there will be '2 ** (number of ?)' such possible replacement in the string. Eg., if we have three '?' in the string there will be 8 such possible replacement and if we consider their numeric value, they will be 0,1,2...,7 and binary representation of which will be 000,001,002,....,111. Basically we should take the the numeric values and replace the '?'s with the bits from the numeric values.
I am doing online work using CodeLab for C++ and am not sure what's wrong with my code. Here is the question:
Write a recursive, int-valued function, len, that accepts a string and returns the number of characters in the string.
The length of a string is:
0 if the string is the empty string ("").
1 more than the length of the rest of the string beyond the first character.
And here's my code:
int len(string s)
{
if (s.length()==0)
return 0;
else
{
return 1+(len(s)-1);
}
}
It says I have a run-time error.
Any help?
Thanks.
Well here:
return 1+(len(s)-1);
The length of the string never decreases. So you will eventually have a stackoverflow because you never hit your base case (s.length() == 0). You need to get a substring where the length of s decreases by 1:
return 1+(len(s.erase(0,1))); // erases 1 char from beginning then recurses
Hopefully this is purely academic, because std::string has a length method that will run in constant time. (Not to mention erasing from the front of a string is probably horribly inefficient-- see the other answers that work with char *)
You are never modifying s in your code, so if s is not empty you keep calling the same function and again, with the same parameter; your never stop. Your computer runs out of stack space and the program crashes.
Others have given you some ideas/options. Here's mine suggestion:
int len(const std::string &s, int start)
{
/* If we are starting at the end, there's no more length */
if(start == s.length())
return 0;
/* one plus whatever else... */
return 1 + len(s, start + 1);
}
Assuming str is the string you want to get the length of, you can call it as: len(str, 0)
If you need to use a const char * version try this:
int len(const char *s)
{
if((s == NULL) || (*s == 0))
return 0; /* we ran out of string! */
return 1 + len(s + 1);
}
len(s) will never decrease and cause a stackoverflow. I would do something like:
int len(const char * s) {
if(*s == '\0')
return 0;
else
return 1 + len(s+1);
}
Another solution:
int len(string s)
{
if (s.length()==0)
return 0;
else
{
s = s.substr(0, s.size()-1);
return 1+(len(s));
}
}
When I use getline, I would input a bunch of strings or numbers, but I only want the while loop to output the "word" if it is not a number.
So is there any way to check if "word" is a number or not? I know I could use atoi() for
C-strings but how about for strings of the string class?
int main () {
stringstream ss (stringstream::in | stringstream::out);
string word;
string str;
getline(cin,str);
ss<<str;
while(ss>>word)
{
//if( )
cout<<word<<endl;
}
}
Another version...
Use strtol, wrapping it inside a simple function to hide its complexity :
inline bool isInteger(const std::string & s)
{
if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
char * p;
strtol(s.c_str(), &p, 10);
return (*p == 0);
}
Why strtol ?
As far as I love C++, sometimes the C API is the best answer as far as I am concerned:
using exceptions is overkill for a test that is authorized to fail
the temporary stream object creation by the lexical cast is overkill and over-inefficient when the C standard library has a little known dedicated function that does the job.
How does it work ?
strtol seems quite raw at first glance, so an explanation will make the code simpler to read :
strtol will parse the string, stopping at the first character that cannot be considered part of an integer. If you provide p (as I did above), it sets p right at this first non-integer character.
My reasoning is that if p is not set to the end of the string (the 0 character), then there is a non-integer character in the string s, meaning s is not a correct integer.
The first tests are there to eliminate corner cases (leading spaces, empty string, etc.).
This function should be, of course, customized to your needs (are leading spaces an error? etc.).
Sources :
See the description of strtol at: http://en.cppreference.com/w/cpp/string/byte/strtol.
See, too, the description of strtol's sister functions (strtod, strtoul, etc.).
The accepted answer will give a false positive if the input is a number plus text, because "stol" will convert the firsts digits and ignore the rest.
I like the following version the most, since it's a nice one-liner that doesn't need to define a function and you can just copy and paste wherever you need it.
#include <string>
...
std::string s;
bool has_only_digits = (s.find_first_not_of( "0123456789" ) == std::string::npos);
EDIT: if you like this implementation but you do want to use it as a function, then this should do:
bool has_only_digits(const string s){
return s.find_first_not_of( "0123456789" ) == string::npos;
}
You might try boost::lexical_cast. It throws an bad_lexical_cast exception if it fails.
In your case:
int number;
try
{
number = boost::lexical_cast<int>(word);
}
catch(boost::bad_lexical_cast& e)
{
std::cout << word << "isn't a number" << std::endl;
}
If you're just checking if word is a number, that's not too hard:
#include <ctype.h>
...
string word;
bool isNumber = true;
for(string::const_iterator k = word.begin(); k != word.end(); ++k)
isNumber &&= isdigit(*k);
Optimize as desired.
Use the all-powerful C stdio/string functions:
int dummy_int;
int scan_value = std::sscanf( some_string.c_str(), "%d", &dummy_int);
if (scan_value == 0)
// does not start with integer
else
// starts with integer
You can use boost::lexical_cast, as suggested, but if you have any prior knowledge about the strings (i.e. that if a string contains an integer literal it won't have any leading space, or that integers are never written with exponents), then rolling your own function should be both more efficient, and not particularly difficult.
Ok, the way I see it you have 3 options.
1: If you simply wish to check whether the number is an integer, and don't care about converting it, but simply wish to keep it as a string and don't care about potential overflows, checking whether it matches a regex for an integer would be ideal here.
2: You can use boost::lexical_cast and then catch a potential boost::bad_lexical_cast exception to see if the conversion failed. This would work well if you can use boost and if failing the conversion is an exceptional condition.
3: Roll your own function similar to lexical_cast that checks the conversion and returns true/false depending on whether it's successful or not. This would work in case 1 & 2 doesn't fit your requirements.
Here is another solution.
try
{
(void) std::stoi(myString); //cast to void to ignore the return value
//Success! myString contained an integer
}
catch (const std::logic_error &e)
{
//Failure! myString did not contain an integer
}
Since C++11 you can make use of std::all_of and ::isdigit:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string_view>
int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[])
{
auto isInt = [](std::string_view str) -> bool {
return std::all_of(str.cbegin(), str.cend(), ::isdigit);
};
for(auto &test : {"abc", "123abc", "123.0", "+123", "-123", "123"}) {
std::cout << "Is '" << test << "' numeric? "
<< (isInt(test) ? "true" : "false") << std::endl;
}
return 0;
}
Check out the result with Godbolt.
template <typename T>
const T to(const string& sval)
{
T val;
stringstream ss;
ss << sval;
ss >> val;
if(ss.fail())
throw runtime_error((string)typeid(T).name() + " type wanted: " + sval);
return val;
}
And then you can use it like that:
double d = to<double>("4.3");
or
int i = to<int>("4123");
I have modified paercebal's method to meet my needs:
typedef std::string String;
bool isInt(const String& s, int base){
if(s.empty() || std::isspace(s[0])) return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
bool isPositiveInt(const String& s, int base){
if(s.empty() || std::isspace(s[0]) || s[0]=='-') return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
bool isNegativeInt(const String& s, int base){
if(s.empty() || std::isspace(s[0]) || s[0]!='-') return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
Note:
You can check for various bases (binary, oct, hex and others)
Make sure you don't pass 1, negative value or value >36 as base.
If you pass 0 as the base, it will auto detect the base i.e for a string starting with 0x will be treated as hex and string starting with 0 will be treated as oct. The characters are case-insensitive.
Any white space in string will make it return false.