I am working on a lab assignment where the user inputs a string and a starting and stopping point for a substring within the string to be reversed. For example, if a user inputs the string "go bobcats", and the numbers 3 (for starting index) and 7 (for ending index), the output should be "go acbobts". I was able to write a recursive function that reverses an entire string ("go bobcats" becomes "stacbob og"), but I am having trouble with the substring aspect.
code for full string reverse:
void reversing(string s, int start, int end){
if(s.size() == 0){return;}
else{
reversing(s.substr(1), start + 1, end);
cout << s[0];
}
}
For the starting and ending index for this I just entered 0 and 9 because that would be the full length of the string.
How can I adjust the function so that it only reverses the string starting and ending at the indexes the user inputs? Also, with my current function I have to use an endl in the main to make a new line at the end of the output of the string. Is there a way I can do this inside the function? If I put an endl after cout << s[0]; it puts in a new line after each iteration making the output vertical:
s
t
a
c
b
o
b
o
g
Implementation in main:
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;
A function to reverse the string can swap the elements at both ends of the range and decrease the range by one on both sides.
void reversing(string& s, int start, int end) {
if (start >= end)
return;
swap(s[start], s[end]);
reversing(s, start + 1, end - 1);
}
And then inside main():
// ...
cout << "This is how your words look now:\n";
reversing(s, start, end);
cout << s << endl;
Sometimes it is sad to see how C++ is used to teach everything but not C++. The following is sort of an experiment to see if we can somehow approach std::reverse (the algorithm you should actually use) by actually ignoring the requirements of your homework and doing small digestable steps.
Lets start with a small variation on the solution presented in this answer. Instead of passing the string together with indices we can use iterators. In a nutshell, iterators are the glue between algorithms and data structures, more specifically container. They can refer to elements in a container, just like an index or pointer can do.
void reversing2(std::string::iterator first, std::string::iterator last) {
if (first >= last) return;
std::swap(*first,*last);
reversing2(++first,--last);
}
Iterators can be dereferenced like pointers to get a reference to the element (*first and *last). RandomAccessIterators can be incremented (++first), decremented (--last) and be compared (first >= last), just like you would do it with indices.
The next step is a difficult one, because it requires even more handwaving. Note that apart from the function signature nothing in the above function actually depends on first and last being iterators for elements in a std::string. For example to reverse a subarray of an int[] only the signature would have to change:
void reversing2(int* first, int* last) {
if (first >= last) return;
std::swap(*first,*last);
reversing2(++first,--last);
}
That makes a nice opportunity to get in touch with templates. I know that I am commiting a small crime here, because I cannot give a thorough intro, but will only present you a very narrow case. To make the same code usable for different containers we just have to modify it a little
template <typename IT>
void reversing(IT first,IT last) {
if (first >= last) return;
std::swap(*first,*last);
reversing(++first,--last);
}
This can now be called with any RandomAccessIterator. So this:
#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;
}
Will produce this output:
Hello world
Helow olrld
Hello world
126543
Eventually, and this was the whole motivation for the preceding, we can see that the reversing is quite similar to std::reverse. Of course std::reverse is not recursive and there is one small caveat: standard algorithms typically work on half-open intervals, ie a range made from two iterators first and last where first is included in the interval, but last is one past the last element in the interval. Hence to get the same result, you would have to call it with the second iterator one position further than with the above function:
std::reverse(s.begin()+3,s.begin()+8); // pass iterators to 4th and one past the 8th character
Complete online example
In your function declaration the type of the first parameter is not a referenced type. So the function deals with a copy of an original string passed to the function as an argument.
However in any case your recursive function definition is invalid. At least there is no need to extract a sub-string.
Pay attention to that the second and the third parameters of the function should have the type std::string::size_type. Otherwise the user can supply a negative values for the parameters when they have the type int and the function will have undefined behavior.
Also it is better when the function returns reference to the reversed string itself.
In fact within the function you need to use only one check that the start position is less than the end position.
Here is a demonstrative program that shows how the function can be defined.
#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;
}
The program output is
Hello bobaloogie
olleH bobaloogie
olleH eigoolabob
well i also have a solution but without implementing library function just to give you a feel of implementation and it's pretty simple.
adjusting your function - swap the start and last position recursively instead of doing
exhaustively .
endl in the main - if you wish to save the answer in input string only then yes you have to do that in main . Else just before returning from function put 'endl '.
My code goes like this.
#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;
}
There are different way to approach this problem, the greedy one is to use substring to pass the exact string to the reverse function:
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);
}
else you need to edit your function that reverse to edit the string only when in such range
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];
}
}
Related
there is a problem with the code. Displays an error "std::out_of_range at memory location". during debugging.
The task of the code is to find all the letters "A" in the text and delete them.
**ะก++ code:
**
#include <iostream>
#include <string>
using namespace std;
int main()
{
string a;
getline(cin, a);
int n = 0;
do {
n = a.find('a',1);
cout << n;
a.erase(n, 0);
cout << a;
} while (n != -1);
cout << a;
}
I tried to change int to double, but the program does not work correctly. However, the error disappears
There are two problems with this do-while loop
do {
n = a.find('a',1);
cout << n;
a.erase(n, 0);
cout << a;
} while (n != -1);
The first one is that you are starting to search the letter 'a' starting from the position 1 instead of the position 0.
The second one is that if the letter 'a' is not found then n is equal to std::string::npos and you are using this value in the call of erase. You need to check that n is not equal to std::string::npos before calling the member function erase.
And the call of erase in any case is incorrect.
Instead of the do-while loop it is better to use the for loop. For example
for ( std::string::size_type n; ( n = a.find( 'a' ) ) != std::string::npos; )
{
std::cout << n;
a.erase(n, 1 );
std::cout << a << '\n';
}
Also you should declare the variable n as having the type std::string::size_type.
And as #Ted Lyngmo wrote in a comment if your compiler supports C++ 20 then you can use standard C++ function erase defined for standard containers like
std::erase( a, 'a' );
to remove all occurrences of the letter 'a' in the string.
So while working through a course on Udemy over C++ one of the challenges was to check a string to see whether it was a palindrome or not. I completed the task successfully but went about it a different way than the instructor. I understand there are a multitude of ways to complete a task but I am wondering which is more efficient and why? It may seem stupid to be wondering about this while reteaching myself coding but I feel this is something I should be keeping in mind.
//Instructors code//
# include<iostream>
using namespace std;
/*program for reverse a string and check a string is a palidrome
*/
int main()
{
string str="MADAM";
string rev="";
int len=(int)str.length();
rev.resize(len);
for(int i=0, j=len-1; i<len; i++, j--)
{
rev[i]=str[j];
}
rev[len]='\0';
if(str.compare(rev)==0)
cout<<"palindrome"<<endl;
else
cout<<"not a pallindrome"<<endl;
return 0;
}
My Approach
#include <iostream>
using namespace std;
int main(){
string str1="test";
// cout << "Enter a string to check if it is a Palindrome: ";
// getline(cin,str1);
string str2;
string::reverse_iterator it;
for(it=str1.rbegin(); it!= str1.rend(); it++)
{
str2.push_back(*it);
}
if(!str1.compare(str2))
cout << "\nPalindrome";
else
cout << "\nNot a Palindrome";
return 0;
}
Thank you in advance.
In theory the code from your instructor is more efficient, but both examples have issues.
With your instructors code the main issue is the use of
int len=(int)str.length();
In this example, it is okay because we know the size of the string will fit in a int, but if you were getting a string from an outside source, this could be a problem. A std::string using an unsigned integer type to store the size of the string and that means you can have a string who's size is larger then what can fit in an int. If that were to happen, then code is not going to work correctly.
With your code you a avoid all that, which is great, but you also leave some performance on the table. In theory your code of
for(it=str1.rbegin(); it!= str1.rend(); it++)
{
str2.push_back(*it);
}
is going to cause str2 to have multiple buffer allocations and copies from the old buffer to the new buffer as it grows. This is a lot of extra work that you don't need to do since you already know how much space you need to allocate. Having
str2.reserve(str1.size() + 1);
before the loop pre-allocates all the space you need so you don't have those potential performance hits.
Then we come to the fact that both of your examples are using a second string. You don't need another string to check for a palindrome. What you can do is just check and see if the first and last characters are the same, and if they are move on to the first+1 and last-1 character and so on until you reach the middle or they don't match. You can do that using a construct like
bool is_palindrome = true;
for (auto start = str.begin(), end = str.end() - 1;
start < end && is_palindrome;
++start, --end)
{
if (*start != *end)
is_palindrom = false
}
if (is_palindrome)
std::cout << "palindrome\n";
else
std::cout << "not a pallindrome\n";
The simplest and most efficient way (no copying required) would be something like this:
inline bool is_palindrome(const std::string& u) {
return std::equal(u.begin(), std::next(u.begin(), u.length() / 2), u.rbegin());
}
I would say that both are almost the same, but as mentioned in the comments, the line:
str2.push_back(*it);
Is actually very inefficient, since std::string may copy the existing string to a new location in the memory, and then append the next char to the string, which is wasteful.
But I am wondering, why to create the copy in the first place?
It is very simple to run both from start to end, and from end to start to check it out, meaning:
bool is_polindrom(const std::string& str)
{
for (std::size_t idx = 0, len = str.length(); idx < len / 2; ++idx)
{
if (str[idx] != str[len - 1 - idx])
{
return false;
}
}
return true;
}
Running the code with:
int main()
{
const std::string right1 = "MADAM";
const std::string right2 = "MAAM";
const std::string wrong1 = "MADAAM";
const std::string wrong2 = "MEDAM";
std::cout << "MADAM result is: " << is_polindrom(right1) << std::endl;
std::cout << "MAAM result is: " << is_polindrom(right2) << std::endl;
std::cout << "MADAAM result is: " << is_polindrom(wrong1) << std::endl;
std::cout << "MEDAM result is: " << is_polindrom(wrong2) << std::endl;
}
Will yield:
MADAM result is: 1
MAAM result is: 1
MADAAM result is: 0
MEDAM result is: 0
You don't need extra memory in this case, since it is possible to iterate over a string from the end to the beginning, and you need to run on it exactly once (and notice that I stop when idx >= len / 2 since you don't really need to check each letter twice!).
At first this seemed easy to do but I was mistaken. I want to 'replace' a char (a variable) in a string with a int (value). But how?
I tried replace() because I'm working with a string and it worked but it will not work if I wish to change the value of the variable again to another
value because then the original variable will not be found. I have been struggling with this for the passed 2 days. Any help will be much appreciated on how to do this.
changeVar(string startingExpr, char var, int val)
{
for(int i = 0; i < startingExpr.length(); i++)
{
if(startingExpr[i] == var)
{
cout << "I found x! Now to replace it!";
startingExpr[i] = val; //'Replace' x with 5, but x but how?
}
}
}
Your help on this one will be much appreciated.
J
If you want to be able to replace the "variable" by the "value" as many times as you want, you should keep a copy of the original string and do the replacement from there only.
Another option is to undo the replacement (replace the value by the variable) and redo with another value, provided the undo can be done unambiguously.
I am sorry to hear this problem wasted your more than 2 days. You shouldcarefully read a basic C++ textbook. As your problem is a very basic one. If you understand the arguments passing for function, you will sort this out!
More specific, you function is not wrong, but just did not deliver the results you want. Because your function using argument, which will make a copy of argument startingExpr inside the function body, when you make replacement using "startingExpr[i] = val", the replacement is happened on the copy of startingExpr (which is a local variable just visible inside the function), your original startingExpr does change at all.
The solution is very simple, change argument passing with its reference, just add &, now the declaration your function should be: "changeVar(string startingExpr, char var, int val)"
Try the following code, which will demonstrate my explanation:
#include <iostream>
#include <string>
using namespace std;
//the original function which was reported had problem
// This because the function using parameter not reference
void changeVar(string startingExpr, char var, int val)
{
for(int i = 0; i < startingExpr.length(); i++)
{
if(startingExpr[i] == var)
{
cout << "I found x! Now to replace it!(But the replace is happend inside the function, the original string is not changed!)"<<endl;
startingExpr[i] = val; //'Replace' x with 5, but x but how?
}
}
}
// updating using the reference
//void changeVar(string & startingExpr, char var, int val)
void changeVar_refe(string & startingExpr, char var, int val)
{
for(int i = 0; i < startingExpr.length(); i++)
{
if(startingExpr[i] == var)
{
cout << "I found x! Now to replace it!(Now using reference, the replace is happend inside the original string, which will be changed!)"<<endl;
startingExpr[i] = val; //'Replace' x with 5, but x but how?
}
}
}
int main()
{
//lets test the original function
string my_name="Hi there, I am C++ taoism .";
cout<<"The original string is: "<<my_name<<endl;
//lets change a to A
changeVar(my_name,'a',65);
cout<<"The changed string is: "<<my_name<<endl;
cout<<endl;
cout<<"Using the reference to test ... "<<endl;
cout<<endl;
cout<<"The original string is: "<<my_name<<endl;
//lets change a to A
changeVar_refe(my_name,'a',65);
cout<<"The changed string is: "<<my_name<<endl;
//cout <<"Char A is int 65:"<<int('A')<<endl;
}
Your mistake is to assign the number that is different from the ASCII character represntation. In ASCII table characters '0', '1' .. '9' goes one after another. So you can rewrite your code as:
startingExpr[i] = '0' + val;
But please aware that this is good for one character case only. If you need to replace multiple chars then your solution without need for a function is that:
#include <iostream>
#include <string>
int
main()
{
std::string a("SomeVar1"), b("SomeVar356");
std::string::size_type index = std::string::npos;
std::cout << "Before: " << a << std::endl;
if ((index = a.rfind("1")) != std::string::npos)
a.replace(index, 1, std::to_string(2));
std::cout << "After: " << a << std::endl;
std::cout << "Before: " << b << std::endl;
if ((index = b.rfind("356")) != std::string::npos)
b.replace(index, 3, std::to_string(673));
std::cout << "After: " << b << std::endl;
return 0;
}
This is slightly optimized since it is using rfind (search from the end of the string).
P.S. As the comments suggested - you can use std::replace with reverse iterators and lambda for condition. Since it is available in C++11 I wrote a small example in universal style.
Say as part of input, a user inputted nrt:x to tell the program to calculate the nth root of x. If I wanted to send n and x to another method to simplify the nth root, I was thinking I could use std::string::find to look for "rt:". If find returns true, I then need to send n and x to another method, but how could I do that after "rt:" is found? For example, user inputs 7rt:3. Find would return true for "rt:", how could I then send 3 and 7 to another method?
if(std::string::find(rt:)) {
//manipulate numbers before/after rt: from user input
if(result will be an int) {
nthRoot(double n, double x);
}
If(result will not be an int) {
nthRootSimplify(double n, double x);
}
}
void nthRoot(double x, double n){
double nthRootSol = pow(x, double(1 / n));
}
edit: Code I have written as a solution with your guy's help. Any advice would be great. I see myself running into problems if "n" or "z" are longer than 1 int.
void findNthRoot(string x) {
if(x.find("rt:") != string::npos) {
unsigned position = x.find("rt:");
cout << position << endl;
double n = position - 1;
cout << n << endl;
double z = position + 3;
cout << z << endl;
string str1 = x.substr(n, 1);
string str2 = x.substr(z);
cout << str1 << endl;
cout << str2 << endl;
}
}
int main() {
findNthRoot("2 - 1+3rt:4");
return 0;
}
output is:
7
6
10
3
4
with the most important being that "3" and "4" are the values of str1 and str2
If you are assuming that input will always begin with n and end with the number under the radical, you can use std::string::front() to access the first element and std::string::back() to access the last element.
find would not return true. Such a find would be pretty damn useless. The real std::string::find returns the position of the found string.
Knowing the position, you can now separate your string into the "before" and "after" part using std::string::substr.
I am looking for some quick tips on a homework assignment. We are given a few problems and have to write two quick programs on how to solve the problems with one each of iteration and recursion. I'm sure this is easier than I think, but I am getting easily confused over the two. By no means do I want anyone to fully solve the problems for me, I won't learn anything! But if you could look at what I have so far and let me know if I am heading in the right direction. Also, the code does not need to compile, our professor wants us to have a general idea of the differences of iteration vs. recursion.
Problem: check a string to see if it is a palindrome.
My solution- I think it is the iterative solution:
bool iterative_palindrome (const string& str) {
string line, result;
stack <char> stack_input;
//user enters string, program takes it
cout << "Enter string: " << endl;
while (getline (cin, line) && (line != "")) {
//push string into stack
for (size_t i = 0; i < line.size(); i++) {
stack_input.push(line[i]);
//create reverse of original string
while (!stack_input.empty()) {
result += stack_input.top();
stack_input.pop();
return result;
}
//check for palindrome, empty string
if (line == result || line = "0" || line.empty()) {
return true;
cout << line << " is a palindrome!" << endl;
} else {
return false;
cout << line << " is NOT a palindrome." << endl;
cout << "Enter new string: " << endl;
}
}
}
}
I remind everyone, I am pretty new to this stuff. I've read a few things already, but am still having a hard time wrapping my head around this.
Here's the general idea:
Iterative:
Initialize two pointers one pointer to the start and end of the string.
Compare the characters pointed, if different -> not palindrome.
Increase the start pointer and decrease the end pointer.
Repeat until start pointer >= end pointer.
Recursive (more difficult than iterative in this case):
End condition: A string of length zero or one is a palindrome.
A string is a palindrome if the first and last characters are the same and if the string without the first and last characters is a palindrome.
You can implement this recursive algorithm more efficiently by passing pointers to the first and last character in the string instead of copying the string between recursions.
Hope this helps :-)
I figure writing code is the best way to explain the two approaches. Is this code understandable?
bool iterative_palindrome(const string& str) {
int size = str.size();
for (int i=0; i<str.size()/2; i++) {
if (str[i] != str[size-i-1])
return false;
}
return true;
}
You call this like recursive_palindrome(str, 0).
bool recursive_palindrome(const string& str, int index) {
int size = str.size();
if (index >= size/2)
return true;
if (str[index] == str[size-index-1])
recursive_palindrome(str, index+1);
else
return false;
}