I'm learning how to write recursions, and I am confused as to how to simplify the body of a function into a recursion.
For my current assignment, I have "to Mesh two strings by alternating characters from them. If one string runs out before the other, just pick from the longer one. For example, mesh("Fred", "Wilma") is "FWrieldma". Use recursion. Do not use loops."
Well... I created the loop....
string result;
for (int i = 0; i < a.size(); ++i)
{
result += a.at(i) + b.at(i)
}
But making that into a recursion is stumping me.
This is what I have so far (We are not allowed to change anything above or below where it is marked):
#include <string>
using namespace std;
/**
Combines alternate characters from each string.
#param a the first string.
#param b the second string
*/
string mesh(string a, string b)
{
// INSERT CODE BENEATH HERE
string result;
if (a.size() < 1) result = b;
if (b.size() < 1) result = a;
else
{
result = a.at(0) + b.at(1);
}
return result;
// ENTER CODE ABOVE HERE
}
But i know its not right because there is no recursion and it flat out doesn't work
I think this does what you've asked and keeps the function prototype intact. Also it looks similar to your suggested code.
#include <iostream>
using namespace std;
string mesh(string a, string b) {
if (!a.size()) return b;
if (!b.size()) return a;
return a[0] + (b[0] + mesh(a.substr(1), b.substr(1)));
}
int main(int argc, char const *argv[])
{
printf("%s\n", mesh("Fred", "Wilma").c_str());
return 0;
}
First try to find out what is a single step of the recursion. There is more than one way to do it, one possibility is traverse the strings by using some index pos and in a single step add the characters from the respective positions of the strings:
std::string mesh(const std::string& a, const std::string& b,size_t pos) {
/*...*/
std::string result;
if (pos < a.size()) result += a[pos];
if (pos < b.size()) result += b[pos];
/*...*/
}
To recurse we call the method again for the next index and append to result:
std::string mesh(const std::string& a, const std::string& b,size_t pos = 0) {
/*...*/
std::string result;
if (pos < a.size()) result += a[pos];
if (pos < b.size()) result += b[pos];
return result + mesh(a,b,pos+1);
}
Finally we need a stop condition. The recursion should stop when both strings have no more characters at index pos:
std::string mesh(const std::string& a, const std::string& b,size_t pos = 0) {
if (pos >= a.size() && pos >= b.size()) return "";
std::string result;
if (pos < a.size()) result += a[pos];
if (pos < b.size()) result += b[pos];
return result + mesh(a,b,pos+1);
}
For example:
int main() {
std::cout << mesh("Fred","Wilma");
}
will result in the desired FWrieldma output.
Disclaimer: As pointed out by SergeyA, I didn't pay to much attention to performance when writing this answer. I suppose this is an exercise to practice recursion, while in reality I don't see a reason to implement this via recursion.
Just adding onto largest_prime_is_463035's answer.
If you have to keep signature of mesh the same then you would create another function that has the actual implementation and now mesh can be called be only the two string arguments.
#include <string>
#include <iostream>
using namespace std;
/**
Combines alternate characters from each string.
#param a the first string.
#param b the second string
*/
void meshInternal(const string a, const string b, string& result, unsigned int index=0){
if(index >= a.size()){
result += b.substr(index);
return;
}
if(index >= b.size()){
result += a.substr(index);
return;
}
result.push_back(a[index]);
result.push_back(b[index]);
meshInternal(a, b, result, ++index);
}
string mesh(const string a, const string b)
{
string result = "";
meshInternal("Fred", "Wilma", result);
return result;
}
int main() {
string result = mesh("Fred", "Wilma");
std::cout << result << std::endl;
return 2;
}
As it is not possible to pass another parameter in the mesh function, but in every recursive call we need to know which character from string a and string b will be appended to the result. One simple solution may be removing the first character from both string a and string b and append it to the result. Now, as we are passing string a and string b as reference, removing first character will ultimately make the string empty after a while. So, we can check whether both the string a and string b become empty and set it as the base-case of the recursion call.
This code solves the problem:
std::string mesh(string& a, string& b) {
if (a.size() == 0 && b.size() == 0) return "";
std::string result;
if (a.size()) {
result += a[0];
a.erase(0, 1);
}
if (b.size()) {
result += b[0];
b.erase(0, 1);
}
return result + mesh(a,b);
}
int main()
{
string a = "Fred";
string b = "Wilma";
std::cout << mesh(a,b);
return 0;
}
#include <string>
#include <iostream>
#include <string_view>
// recursive mesh function.
// passing the result object for effeciency.
void mesh(std::string& result, std::string_view l, std::string_view r)
{
// check the exit condition.
// If either the left of right are empty add the other to the result.
if (std::begin(l) == std::end(l)) {
result += r;
return;
}
if (std::begin(r) == std::end(r)) {
result += l;
return;
}
// Add letter from the left and right to the result.
result += *std::begin(l);
result += *std::begin(r);
// Adjust the size of the view
l.remove_prefix(1);
r.remove_prefix(1);
// recursively call to get the next letter.
mesh(result, l, r);
}
// Utility wrapper to get view of strings and create
// the result object to be passed to the recursive function.
std::string mesh(std::string const& l, std::string const& r)
{
std::string result;
mesh(result, std::string_view(l), std::string_view(r));
return result;
}
int main()
{
std::cout << mesh("Fred", "Wilma");
}
I am programming my custom string class with multiple methods. The issue is that the comparison method does not work as I intend. Instead of doing nothing when the two char arrays differ, an if conditional still proceeds in my main function.
There are no errors given when I compile with g++. The code is syntactically correct, however logically faulty. I know this because I can give the compare method two char arrays which differ in content, and it will not matter whether they differ this way, as the main function will run the if conditional for "s8.compare(s7) == 1" regardless if the result in the compare method is not true.
I will post the entire code below. Any help is greatly appreciated.
string.h
class Str {
private:
char *value;
int length;
int capacity;
//Doubles the size of the string when called.
void growArray();
//If the two strings are uneven, get absolute value of difference in length.
int difference(int a, int b);
//Calculates the size of a character array, passed in as an argument
int getCharArrSize(const char *v);
public:
Str();
explicit Str(const char *STR);
void copy(Str s);
void concatenate(Str s);
bool compare(Str s);
void print();
};
//Str constructor
Str::Str() {
//Assign value, capacity, and length to any new Str object
value = new char[100];
capacity = 100;
length = 0;
}
//Pass STR object as a pointer to string object constructor
Str::Str(const char *STR) {
length = getCharArrSize(STR);
capacity = 100;
value = new char[capacity];
//Copy contents from STR to string object
for (int i = 0; i < length; i++)
value[i] = STR[i];
}
//Doubles the size of the string when called.
void Str::growArray() {
const char *tmp = value;
capacity *= 2;
value = new char[capacity];
for (int i = 0; i < length; i++)
value[i] = tmp[i];
}
//If the two strings are uneven, get absolute value of difference in length.
int Str::difference(int a, int b) {
int d = 0;
if (a > b) d = a - b;
else if (b > a) d = b - a;
return d;
}
//Calculates the size of a character array, passed in as an argument
int Str::getCharArrSize(const char *v) {
int c = 0;
while (v[c] != '\0') {
c++;
}
return c;
}
//Overwrites the data of the string array with the data contained in s
void Str::copy(Str s) {
//Check ability for empty string object to hold Str s contents
if (capacity > s.length) {
//Copy over each element until s length is reached
for (int i = 0; i < s.length ; i++)
value[i] = s.value[i];
//Set string object length to copy's size
length = getCharArrSize(value);
} else { growArray(); }
}
//Concatenate Str s onto string object
void Str::concatenate(Str s) {
//Check ability for string object to hold itself and concatenated chars
if (capacity > length + s.length) {
//Fill string object with s object until end of combined lengths if necessary
for (int i = 0; i < length + s.length; i++)
value[length + i] = s.value[i];
//Set length based on chars in concatenated string object
length = getCharArrSize(value);
} else { growArray(); }
}
//Compare each element in Str s against string for similarities
bool Str::compare(Str s) {
if (length == s.length) {
if (*value == *s.value) {
while ((*value != value[length]) && (*s.value != s.value[s.length])) {
value++;
s.value++;
}
return true;
} else return false;
} else {
difference(length, s.length);
}
}
//Print function
void Str::print() {
std::cout << value << std::endl;
}
main.cpp
#include"string.h"
int main() {
Str s1("Hello ");
Str s2("World");
Str s3(", my ");
Str s4("Name ");
Str s5("is ");
Str s6("Chad!");
Str s7;
s7.copy(s1);
s7.concatenate(s2);
s7.concatenate(s3);
s7.concatenate(s4);
s7.concatenate(s5);
s7.concatenate(s6);
s7.print();
std::cout << "\n\n";
Str s8("Hello World, My Name is Chad!");
if (s8.compare(s7) == 1) {
std::cout << "They Match!" << std::endl;
}
Str s9("I dont match....");
if (s9.compare(s8) == 0) {
std::cout << "I differ by " << s8.compare(s6) << " characters" << std::endl;
}
}
The above code returns a result that appears correct, however changing (s8.compare(s7) == 1) to something like (s8.compare(s5) == 1) returns 'They match!' when I am trying to check each individual element in the char arrays against one another, and only return true if they are the same length and each character matches in the arrays.
Your program has undefined behavior since Str::compare does not have a return statement in one of the branches.
bool Str::compare(Str s) {
if (length == s.length) {
...
} else {
// Missing return statement.
difference(length, s.length);
}
}
Perhaps you want to change that line to:
return (difference(length, s.length) == 0);
Your loop is running without a comparison. You compare the initial values in the char array and then loop through the rest without comparison. So you will return true every time the initial values are equal.
Below the loop runs after the same length is determined then every char is compared. If they are not equal then the function will return false. Otherwise the function will return true.
bool Str::compare(Str s) {
if (length == s.length) {
while ((*value != value[length]) && (*s.value != s.value[s.length])) {
if (*value == *s.value) {
value++;
s.value++;
} else {
return false;//will return false as soon as a comparison is false
}
}
return true;
} else {
difference(length, s.length);
}
}
You also need to return a boolean from the difference function. If you want to return ints from that function switch to a int return on the compare function and use 0 and 1s as their boolean counterparts.
What would be the most efficient yet simplest way to convert a char to its unsigned binary representation (bytes where the MSB is 0)? I have a method set up like this:
string AsciiToBinary(char value) {
string binary = "";
int code = value;
while (code > 0) {
if ((code % 2) == 1) {
binary.append("1", 1);
} else {
binary.append("0", 1);
}
code = code / 2;
}
return binary;
}
I am assuming that setting an int to a char sets the char's ASCII value to the int. However, my results do not match the ASCII table. I am implementing this function as follows:
char head = stack.pop();
int code = head; // do not need to parse
string binary;
while (!stack.isEmpty()) {
binary = AsciiToBinary(code);
outfile << binary << endl;
binary.clear();
head = stack.pop();
code = head;
}
I have stored all of the chars in a stack.
Thank you for info and direction.
std::string::append() adds the character onto the end of the string. So you are putting the bits on in the reverse order: the LSB is the first character and vice versa. Try this: binary.insert (0, 1, (code % 2 == 1) ? '1' : '0');
This method works well and is editable for all those interested and learning C++:
using namespace std; // bad for updates
#include <string>
string AsciiToBinary(char value) {
string binary = "";
unsigned int code = value;
unsigned int chk = value;
while (code > 0) {
if ((code & 1) == 1) {
binary.append("1", 1);
} else {
binary.append("0", 1);
}
code = code / 2;
}
reverse(binary.begin(), binary.end());
if (chk < 64) {
binary.insert(0, "00");
} else {
binary.insert(0, "0");
}
return binary;
}
I am working on a algorithm where I am trying the following output:
Given values/Inputs:
char *Var = "1-5,10,12,15-16,25-35,67,69,99-105";
int size = 29;
Here "1-5" depicts a range value, i.e. it will be understood as "1,2,3,4,5" while the values with just "," are individual values.
I was writing an algorithm where end output should be such that it will give complete range of output as:
int list[]=1,2,3,4,5,10,12,15,16,25,26,27,28,29,30,31,32,33,34,35,67,69,99,100,101,102,103,104,105;
If anyone is familiar with this issue then the help would be really appreciated.
Thanks in advance!
My initial code approach was as:
if(NULL != strchr((char *)grp_range, '-'))
{
int_u8 delims[] = "-";
result = (int_u8 *)strtok((char *)grp_range, (char *)delims);
if(NULL != result)
{
start_index = strtol((char*)result, (char **)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
while(NULL != result)
{
end_index = strtol((char*)result, (char**)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
while(start_index <= end_index)
{
grp_list[i++] = start_index;
start_index++;
}
}
else if(NULL != strchr((char *)grp_range, ','))
{
int_u8 delims[] = ",";
result = (unison_u8 *)strtok((char *)grp_range, (char *)delims);
while(result != NULL)
{
grp_list[i++] = strtol((char*)result, (char**)&end_ptr, 10);
result = (int_u8 *)strtok(NULL, (char *)delims);
}
}
But it only works if I have either "0-5" or "0,10,15". I am looking forward to make it more versatile.
Here is a C++ solution for you to study.
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int ConvertString2Int(const string& str)
{
stringstream ss(str);
int x;
if (! (ss >> x))
{
cerr << "Error converting " << str << " to integer" << endl;
abort();
}
return x;
}
vector<string> SplitStringToArray(const string& str, char splitter)
{
vector<string> tokens;
stringstream ss(str);
string temp;
while (getline(ss, temp, splitter)) // split into new "lines" based on character
{
tokens.push_back(temp);
}
return tokens;
}
vector<int> ParseData(const string& data)
{
vector<string> tokens = SplitStringToArray(data, ',');
vector<int> result;
for (vector<string>::const_iterator it = tokens.begin(), end_it = tokens.end(); it != end_it; ++it)
{
const string& token = *it;
vector<string> range = SplitStringToArray(token, '-');
if (range.size() == 1)
{
result.push_back(ConvertString2Int(range[0]));
}
else if (range.size() == 2)
{
int start = ConvertString2Int(range[0]);
int stop = ConvertString2Int(range[1]);
for (int i = start; i <= stop; i++)
{
result.push_back(i);
}
}
else
{
cerr << "Error parsing token " << token << endl;
abort();
}
}
return result;
}
int main()
{
vector<int> result = ParseData("1-5,10,12,15-16,25-35,67,69,99-105");
for (vector<int>::const_iterator it = result.begin(), end_it = result.end(); it != end_it; ++it)
{
cout << *it << " ";
}
cout << endl;
}
Live example
http://ideone.com/2W99Tt
This is my boost approach :
This won't give you array of ints, instead a vector of ints
Algorithm used: (nothing new)
Split string using ,
Split the individual string using -
Make a range low and high
Push it into vector with help of this range
Code:-
#include<iostream>
#include<vector>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
int main(){
std::string line("1-5,10,12,15-16,25-35,67,69,99-105");
std::vector<std::string> strs,r;
std::vector<int> v;
int low,high,i;
boost::split(strs,line,boost::is_any_of(","));
for (auto it:strs)
{
boost::split(r,it,boost::is_any_of("-"));
auto x = r.begin();
low = high =boost::lexical_cast<int>(r[0]);
x++;
if(x!=r.end())
high = boost::lexical_cast<int>(r[1]);
for(i=low;i<=high;++i)
v.push_back(i);
}
for(auto x:v)
std::cout<<x<<" ";
return 0;
}
You're issue seems to be misunderstanding how strtok works. Have a look at this.
#include <string.h>
#include <stdio.h>
int main()
{
int i, j;
char delims[] = " ,";
char str[] = "1-5,6,7";
char *tok;
char tmp[256];
int rstart, rend;
tok = strtok(str, delims);
while(tok != NULL) {
for(i = 0; i < strlen(tok); ++i) {
//// range
if(i != 0 && tok[i] == '-') {
strncpy(tmp, tok, i);
rstart = atoi(tmp);
strcpy(tmp, tok + i + 1);
rend = atoi(tmp);
for(j = rstart; j <= rend; ++j)
printf("%d\n", j);
i = strlen(tok) + 1;
}
else if(strchr(tok, '-') == NULL)
printf("%s\n", tok);
}
tok = strtok(NULL, delims);
}
return 0;
}
Don't search. Just go through the text one character at a time. As long as you're seeing digits, accumulate them into a value. If the digits are followed by a - then you're looking at a range, and need to parse the next set of digits to get the upper bound of the range and put all the values into your list. If the value is not followed by a - then you've got a single value; put it into your list.
Stop and think about it: what you actually have is a comma
separated list of ranges, where a range can be either a single
number, or a pair of numbers separated by a '-'. So you
probably want to loop over the ranges, using recursive descent
for the parsing. (This sort of thing is best handled by an
istream, so that's what I'll use.)
std::vector<int> results;
std::istringstream parser( std::string( var ) );
processRange( results, parser );
while ( isSeparator( parser, ',' ) ) {
processRange( results, parser );
}
with:
bool
isSeparator( std::istream& source, char separ )
{
char next;
source >> next;
if ( source && next != separ ) {
source.putback( next );
}
return source && next == separ;
}
and
void
processRange( std::vector<int>& results, std::istream& source )
{
int first = 0;
source >> first;
int last = first;
if ( isSeparator( source, '-' ) ) {
source >> last;
}
if ( last < first ) {
source.setstate( std::ios_base::failbit );
}
if ( source ) {
while ( first != last ) {
results.push_back( first );
++ first;
}
results.push_back( first );
}
}
The isSeparator function will, in fact, probably be useful in
other projects in the future, and should be kept in your
toolbox.
First divide whole string into numbers and ranges (using strtok() with "," delimiter), save strings in array, then, search through array looking for "-", if it present than use sscanf() with "%d-%d" format, else use sscanf with single "%d" format.
Function usage is easily googling.
One approach:
You need a parser that identifies 3 kinds of tokens: ',', '-', and numbers. That raises the level of abstraction so that you are operating at a level above characters.
Then you can parse your token stream to create a list of ranges and constants.
Then you can parse that list to convert the ranges into constants.
Some code that does part of the job:
#include <stdio.h>
// Prints a comma after the last digit. You will need to fix that up.
void print(int a, int b) {
for (int i = a; i <= b; ++i) {
printf("%d, ", i);
}
}
int main() {
enum { DASH, COMMA, NUMBER };
struct token {
int type;
int value;
};
// Sample input stream. Notice the sentinel comma at the end.
// 1-5,10,
struct token tokStream[] = {
{ NUMBER, 1 },
{ DASH, 0 },
{ NUMBER, 5 },
{ COMMA, 0 },
{ NUMBER, 10 },
{ COMMA, 0 } };
// This parser assumes well formed input. You have to add all the error
// checking yourself.
size_t i = 0;
while (i < sizeof(tokStream)/sizeof(struct token)) {
if (tokStream[i+1].type == COMMA) {
print(tokStream[i].value, tokStream[i].value);
i += 2; // skip to next number
}
else { // DASH
print(tokStream[i].value, tokStream[i+2].value);
i += 4; // skip to next number
}
}
return 0;
}
What I want to do is convert a string such as
"a4b2f0" into "f0b2a4"
or in more simple terms:
turning "12345678" into "78563412"
The string will always have an even number of characters so it will always divide by 2. I'm not really sure where to start.
One simple way to do that is this:
std::string input = "12345678";
std::string output = input;
std::reverse(output.begin(), output.end());
for(size_t i = 1 ; i < output.size(); i+=2)
std::swap(output[i-1], output[i]);
std::cout << output << std::endl;
Online demo
A bit better in terms of speed, as the previous one swaps elements twice, and this one swap each pair once:
std::string input = "12345678";
std::string output = input;
for(size_t i = 0, middle = output.size()/2, size = output.size(); i < middle ; i+=2 )
{
std::swap(output[i], output[size - i- 2]);
std::swap(output[i+1], output[size -i - 1]);
}
std::cout << output << std::endl;
Demo
Let's get esoteric... (not tested! :( And definitely not built to handle odd-length sequences.)
typedef <typename I>
struct backward_pair_iterator {
typedef I base_t;
base_t base;
bool parity;
backward_pair_iterator(base_t base, parity = false):
base(base), parity(parity) {
++base;
}
backward_pair_iterator operator++() {
backward_pair_iterator result(base, !parity);
if (parity) { result.base++; result.base++; }
else { result.base--; }
return result;
}
};
template <typename I>
backward_pair_iterator<I> make_bpi(I base) {
return backward_pair_iterator<I>(base);
}
std::string output(make_bpi(input.rbegin()), make_bpi(input.rend()));
static string reverse(string entry) {
if (entry.size() == 0) {
return "";
} else {
return entry.substr (entry.size() - 2, entry.size()) + reverse(entry.substr (0, entry.size() - 2));
}
}
My method uses the power of recursive programming
A simple solution is this:
string input = "12345678";
string output = "";
for(int i = input.length() - 1; i >= 0; i-2)
{
if(i -1 >= 0){
output += input[i -1];
output += input[i];
}
}
Note: You should check to see if the length of the string when mod 2 is = because otherwise this will go off the end. Do something like I did above.