C++: Issues with manipulating a PPM file - c++

I'm working on a program that can perform various effects and manipulations on a PPM file. However for testing reasons, it uses cin rather than an input file. It is supposed to be able to perform multiple effects at once, but I am having trouble even getting one right. I'll run a removeBlue() on a line that will work, then try again with different values and it will remove red or green instead. That sort of thing. There's a lot of code, so I'll try to include only what is necessary.
#include <vector>
#include <stdlib.h>
#include <cstdlib>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;
class SimpleImageEffect
{
public:
virtual void processImage(vector<Point> &points) = 0;
};
class RemoveRed : public SimpleImageEffect
{
public:
virtual void processImage(vector<Point> &points)
{
for (Point& p : points)
{
p.setRed(0);
}
}
};
//Just an example of one of the effect classes.
//The code in them is correct, so I won't include the others unless needed.
vector<Point> parse_line(string line)
{
istringstream scanner{line};
vector<Point> result{};
int red = -1;
int green = -1;
int blue = -1;
int counter = 0;
while(scanner.good())
{
if (counter == 0)
{
counter++;
scanner >> red;
}
else if (counter == 1)
{
counter++;
scanner >> green;
}
else if (counter == 2)
{
scanner >> blue;
Point p{ red, green, blue };
result.push_back(p);
counter = 0;
}
}
return result;
}
void readFromCin()
{
string line = "";
vector<string> lines_in_file{};
int i, effect_choice;
SimpleImageEffect *effect = nullptr;
getline(cin, line);
while (line.length() > 0)
{
lines_in_file.push_back(line);
getline(cin, line);
}
for (int i = 0; i < lines_in_file.size(); i++)
{
if (lines_in_file[i] != "P3")
{
effect_choice = strToInt(lines_in_file[i]);
}
else if (lines_in_file[i] == "P3")
{
cout << lines_in_file[i] << endl;
cout << lines_in_file[i+1] << endl;
cout << lines_in_file[i+2] << endl;
}
vector<Point> points = parse_line(lines_in_file[i]);
if (effect_choice == 1) effect = new RemoveRed;
if (effect_choice == 2) effect = new RemoveGreen;
if (effect_choice == 3) effect = new RemoveBlue;
if (effect_choice == 4) effect = new NegateRed;
if (effect_choice == 5) effect = new NegateGreen;
if (effect_choice == 6) effect = new NegateBlue;
if (effect_choice == 7) effect = new AddNoise;
if (effect_choice == 8) effect = new HighContrast;
if (effect_choice == 9) effect = new ConvertToGrayscale;
effect->processImage(points);
for (auto p : points)
{
cout << p;
cout << endl;
}
}
}
int main(int argc, char** argv)
{
string menu_choice;
getline(cin, menu_choice);
if (menu_choice == "1")
{
readFromFile();
}
else
{
readFromCin();
}
return 0;
}
So for example, running it with an input of
2
1
P3
1 1
255
50 50 50
will return
P3
1 1
255
0 50 50
but if I run it with
2
3
P3
1 2
255
50 50 50
1 2 3
it returns
P3
1 2
255
0 50 50
0 2 3
I have absolutely no idea what's causing the issue, so any help at all would be greatly appreciated. Thanks.

Your algorithm logic structure smells a lot, this is what I see:
read all non empty lines into lines_in_file (looks good to me)
for EVERY line (problematic, requires additional logic in inner loop):
if not "P3", try to parse [EVERY] line as integer and set effect_choice (it's not clear from your code, what happens on lines where several integers are provided, but judging from your problem description the first integer is successfully parsed by strToInt function)
if "P3", the current line and next two are copied to output
[EVERY] line is parsed as vector of triplets of numbers
effect is set by new effect for actual value of effect_choice (for EVERY line, also you don't delete the effect at end, so you are leaking memory in per-line counts. Also your current effects look like they may be implemented as static functions of "process" function type, so you don't need to allocate each of them, just store the particular memory address of requested function. And you call it processImage, while you are processing only line, not whole image.
effect is run for current line triplets
the line triplets are outputted
loop to next line (!)
So for example for input:
2
3
P3
1 2
255
50 50 50
1 2 3
I believe (can't run it, as you didn't provide lot of code) this happens:
lines are read, and per particular line this happens:
line "2": effect_choice = 2, effect = RemoveGreen, zero triplets parsed into points, RemoveGreen::processImage() run over empty vector, empty vector printed (ie nothing).
line "3": effect_choice = 3, effect = RemoveBlue, zero triplets parsed into points, RemoveBlue::processImage() run over empty vector, empty vector printed.
line "P3": Lines: {"P3", "1 2", "255"} are printed, zero triplets parsed into points, RemoveGreen::processImage() run over empty vector, empty vector printed.
line "1 2": effect_choice = 1, effect = RemoveRed, zero triplets parsed into points, RemoveRed::processImage() run over empty vector, empty vector printed.
line "255": effect_choice = 255, zero triplets parsed into points, RemoveRed::processImage() run over empty vector, empty vector printed.
line "50 50 50": effect_choice = 50, one triplet {50, 50, 50} parsed into points, RemoveRed::processImage() run over it, modified triplet outputs {0, 50, 50}.
line "1 2 3": effect_choice = 1, effect = RemoveRed, one triplet {1, 2, 3} parsed into points, RemoveRed::processImage() run over it, modified triplet outputs {0, 2, 3}.
All of this should be clearly visible in debugger, while stepping over the code, so you probably are not debugging it, which gets downvoting the question from me, and you will pay in tremendous pain over time, as debugging without debugger is lot more difficult.
Also writing code without thinking about algorithm and code architecture makes the need of debugging lot more likely, so you wasted even more time here, by starting by writing the code.
You should have first design some algorithm and code architecture (what data are processed, how, when new memory is needed, how it will be freed, where the code need to loop, where it need to skip over, or run only once, etc).
Write only overview of how it will work into single-line comments, then split too generic comments into simpler steps until they can be implemented by few lines of C++ code, and move/modify them around until you feel the wanted algorithm will be implemented with minimal "cruft" added (most of the comments does, what is really requested, like "set red in point to zero", and any processing/preparations/moving/etc is minimized only to cases where you can't avoid it by smarter design). (for example in your current code you can read through the header of the file without looping, and start looping only after the pixel data pours in)
Then write the code, start probably with some empty function definition so you can already "run" it in debugger and verify the emptiness works, then implement the comment (or small group of them) which you feel is clear enough to be implemented and can be tested easily (no big dependency on yet-to-implement parts). Debug + test new code. If it works, try to clean up the source to remove anything not really needed, work-in-progress variable names, etc... Then verify it works in final version.
And do it again for another comment (group of), until the implementation is done.
Using unit-testing makes the write-short-code, test+debug, clean-up-source rounds even easier, especially in cases like this, where I/O are pure data, so it's easy to feed specialized test input data into test, and verify the expected output data were produced.

Related

C++ moving characters from one vector to another

I'm new to C++. I am trying to create a program that reads a file named symbols.txt, fill a vector with the symbols, then take chars that are in the range [d;p] and move them to the second vector while erasing them from the first vector.
int main(){
vector<char> sym1;
vector<char> sym2;
int p = 100, d = 80;
char x;
ifstream symbols("symbols.txt");
while (symbols >> x )
{
sym1.push_back(x);
}
for(int i = 0; i < sym1.size(); i++){
if (sym1[i] < p && sym1[i] > d){
sym2.push_back(sym1[i]);
sym1.erase(sym1.begin()+i);
}
}
}
When I do this, the program works if there are no characters the same, otherwise it only moves half of the characters and leaves the other half untouched.
In your implementation, the first thing you need to notice is that in your for loop, sym1.size() changes if you call sym1.erase(). Second, since your variable i increments every time, you skip some elements in the vector.
For example, the element at index 5 is erased, then the element at index 6 will move down to replace it. In the mean time, your loops does i++, so you skip the element that moved to index 5.
I think you should use iterators with C++ containers, below is an example:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<char> sym1;
vector<char> sym2;
int p = 100, d = 80;
char x;
// ifstream symbols("symbols.txt");
// while (symbols >> x)
// {
// sym1.push_back(x);
// }
for(int i = 0; i < 200; i++) {
sym1.push_back(i);
}
int size = sym1.size();
for(vector<char>::iterator it = sym1.begin(); it != sym1.end(); ){
if (*it < p && *it > d){
sym2.push_back(*it);
it = sym1.erase(it);
}
else
it++;
}
for(vector<char>::iterator it = sym2.begin(); it != sym2.end(); it++) {
cout << (int)*it << " ";
}
}
std::vector is good for a lot of things. However, it's terribly inefficient when it comes to insertion or erasing at any other position than the end.
When an element is inserted somewhere (not at end), then the following happens:
The internally managed size is increased by 1. (This may cause a re-allocation of the internal buffer.)
The last element is moved to next position, the second last element is moved to the now "free" position, and so on until the element at insertion index is moved.
Similar happens when an element is erased:
The successor of the element to erase is moved to its previous position, the next is moved to its previous position, and so on until the last element is moved.
Finally, the internally managed size is decreased by 1. (No re-allocation. – The buffer is kept as reserved.)
In OPs case, it's the repeated erasing which makes me concerns. And, when I had this problem in production I used a way to reduce all the moves to the absolutely minimal required.
For this, I use two indices:
one to read and check the characters
one to write the characters which have to be kept in the vector (sym1 in OPs sample).
While the read index is simply incremented for each loop iteration (as usual) the write index is incremented only after an element has been moved (because it should be kept).
As long as nothing is erased, both indices will have identical values. In this case, it's a bit annoying that elements are moved to the position where they already are. However, I consider this as the lesser evil. (Checking whether indices are still identical will probably buy nothing if the move is simple enough.) As soon as something is erased the write index starts to lag behind the read index.
So finally, for a vector of length N there are exactly N write operations to perform (and this for granted). This sounds reliable and not too terrible.
(Erasing elements individually one by one could be in worst case result in
N - 1 + N - 2 + … + 1 moves of elements which are roughly N * (N - 1) / 2 or (N² - N) / 2.)
For the demonstration, the modified sample of OP:
#include <fstream>
#include <iostream>
#include <vector>
int main()
{
std::vector<char> sym1, sym2;
const char p = 'z', d = 'a';
// read sample data
std::ifstream symbols("symbols.txt");
for (char x; symbols >> x;) sym1.push_back(x);
// move all characters in [d, p] to sym2
size_t iWrite = 0;
for (size_t iRead = 0, n = sym1.size(); iRead < n; ++iRead) {
const char c = sym1[iRead];
if (c >= d && c <= p) sym2.push_back(c);
else sym1[iWrite++] = sym1[iRead];
}
// The difference between iWrite - iRead is the number of obsolete elements.
// (It must be equal to sym2.size().)
sym1.resize(iWrite);
// could've been altermatively: sym1.erase(sym1.begin() + iWrite, sym1.end());
// show results:
std::cout << "sym1: '";
for (const char c : sym1) std::cout << c;
std::cout << "'\nsym2: '";
for (const char c : sym2) std::cout << c;
std::cout << "'\n";
}
Input:
I used the above source code as input (as the OP didn't expose the symbols.txt file).
Output:
sym1: '#<>#<>#<>(){::<>1,2;='',='';//::(".");(;>>;)1._();//[,]2_W=0;(_R=0,=1.();R<;++R){=1[R];(>=&&<=)2._();1[W++]=1[R];}//TW-R.//(I2.().)1.(1.()+W,1.());//:::<<"1:'";(:1)::<<;::<<"'\2:'";(:2)::<<;::<<"'\";}'
sym2: 'includefstreamincludeiostreamincludevectorintmainstdvectorcharsymsymconstcharpadzreadsampledatastdifstreamsymbolssymbolstxtforcharxsymbolsxsympushbackxmoveallcharactersindptosymsizetiriteforsizetieadnsymsizeieadnieadconstcharcsymieadifcpcdsympushbackcelsesymiritesymieadhedifferencebetweeniriteieadisthenumberofobsoleteelementstmustbeequaltosymsizesymerasesymbeginiritesymendshowresultsstdcoutsymforconstcharcsymstdcoutcstdcoutnsymforconstcharcsymstdcoutcstdcoutn'
Live Demo on coliru
So, for the range ['a', 'z'], (I used in my demo for better illustration) sym2 ends up containing all lower case characters while sym1 keeps everything else (except the white spaces).
Concerning the missing white spaces I wondered a bit until I realized that the white spaces are filtered out by the read loop:
for (char x; symbols >> x;) sym1.push_back(x);
which used formatted input.
This could be changed using symbols.get(x) instead of symbols >> x but the filtering of white space might be even intended.
Nitpicking:
OP described the range [d;p] (for the characters to move) as requirement.
AFAIK, it's usual that square brackets (or angle brackets) describe ranges with closed ends (i.e. with inclusive border values) while for open ends (exclusive border values) round brackets are used.
Thus, either the requirement has to be (d;p)
or the implementation of the range check
if (sym1[i] < p && sym1[i] > d){ // check for range (d;p)
is not according to the requirement but should be
if (sym1[i] <= p && sym1[i] >= d){ // check for range [d;p]

Need to find duplicates from an array in c++, and then put them in another array

this is my first post here and I would be very happy if you could help me.
The task is - Create an array from 6 input numbers, then put the duplicated numbers in another array and then output the array with the repeated numbers.
Do you have any ideas? I'm still a newbie and need some help. Thanks in advance guys !!
EDIT:
I'm not sure if I'm on the right way, that's why I didn't post what I've done yet. But this is it:
#include <iostream>
using namespace std;
int main()
{
int a[6];
int b[6];
int i,z;
for (i=0; i<6; i++){
cin>>a[i];
}
for (z=0; z<6; z++){
if (a[0]==a[1]) b[z]=a[0];
if (a[0]==a[2]) b[z]=a[0];
if (a[0]==a[3]) b[z]=a[0];
if (a[0]==a[4]) b[z]=a[0];
if (a[0]==a[5]) b[z]=a[0];
if (a[1]==a[2]) b[z]=a[1];
if (a[1]==a[3]) b[z]=a[1];
if (a[1]==a[4]) b[z]=a[1];
if (a[1]==a[5]) b[z]=a[1];
if (a[2]==a[3]) b[z]=a[2];
if (a[2]==a[4]) b[z]=a[2];
if (a[2]==a[5]) b[z]=a[2];
if (a[3]==a[4]) b[z]=a[3];
if (a[3]==a[5]) b[z]=a[3];
if (a[4]==a[5]) b[z]=a[4];
else b[z]=0; cout << b[z];
}
return 0;
}
To give you a better understanding of how to solve this, i'll try to show you what is going on via an example.
Lets say you have just entered the 6 numbers you request via cin, and your a[] variable now looks like this in memory:
a[] = { 5, 2, 6, 2, 1, 6 };
The duplicates here are 2 and the 6. (pretty obvious for us humans) :-)
You start to compare the first 2 values in memory: a[0]==a[1], then the first with the third: a[0]==a[2] and so on. If one of these match, you know the value of a[0] has at least one duplicate in memory.
Whenever that happens, you would like to do something that that information. Store it somewhere (like your b[] array) or just output it directly with cout << a[0].
You are now finished with checking a[0] and can continue with a[1] in the same manor, except you do not have to compare with a[0] because you did that in the previous step. Looking at your code, it seems you already understand that you can skip that.
Lets say you really need to store the duplicates. It would help to keep track of how many duplicates you have found.
Pseudo code:
duplicates = 0;
if (a[0] has a duplicate) { b[duplicates] = a[0]; duplicates++; }
if (a[1] has a duplicate) { b[duplicates] = a[1]; duplicates++; }
// etc...
"has a duplicate" would be like the code you had earlier, like: a[0]==a[1] || a[0]==a[2] || a[0]==[3] and so on.
In your example you have just 6 values, so it is not much work to write all the compare statements yourself. If you needed to do this with many more numbers, it would take you ages to write it, and is prone to little mistakes like typo's. Using a for loop would work for few and many numbers:
Pseude code:
duplicates = 0;
for (z = 0 to 6) {
for (y = z+1 to 6) {
if (a[z]==a[y]) {
b[duplicates] = a[z];
duplicates++;
break; // We know it is a duplicate, continue with the next value
}
}
}
But even this is not perfect. If one number occurs more than 2 times in memory, this will store the same duplicate value multiple times.

Recursive String Transformations

EDIT: I've made the main change of using iterators to keep track of successive positions in the bit and character strings and pass the latter by const ref. Now, when I copy the sample inputs onto themselves multiple times to test the clock, everything finishes within 10 seconds for really long bit and character strings and even up to 50 lines of sample input. But, still when I submit, CodeEval says the process was aborted after 10 seconds. As I mention, they don't share their input so now that "extensions" of the sample input work, I'm not sure how to proceed. Any thoughts on an additional improvement to increase my recursive performance would be greatly appreciated.
NOTE: Memoization was a good suggestion but I could not figure out how to implement it in this case since I'm not sure how to store the bit-to-char correlation in a static look-up table. The only thing I thought of was to convert the bit values to their corresponding integer but that risks integer overflow for long bit strings and seems like it would take too long to compute. Further suggestions for memoization here would be greatly appreciated as well.
This is actually one of the moderate CodeEval challenges. They don't share the sample input or output for moderate challenges but the output "fail error" simply says "aborted after 10 seconds," so my code is getting hung up somewhere.
The assignment is simple enough. You take a filepath as the single command-line argument. Each line of the file will contain a sequence of 0s and 1s and a sequence of As and Bs, separated by a white space. You are to determine whether the binary sequence can be transformed into the letter sequence according to the following two rules:
1) Each 0 can be converted to any non-empty sequence of As (e.g, 'A', 'AA', 'AAA', etc.)
2) Each 1 can be converted to any non-empty sequences of As OR Bs (e.g., 'A', 'AA', etc., or 'B', 'BB', etc) (but not a mixture of the letters)
The constraints are to process up to 50 lines from the file and that the length of the binary sequence is in [1,150] and that of the letter sequence is in [1,1000].
The most obvious starting algorithm is to do this recursively. What I came up with was for each bit, collapse the entire next allowed group of characters first, test the shortened bit and character strings. If it fails, add back one character from the killed character group at a time and call again.
Here is my complete code. I removed cmd-line argument error checking for brevity.
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
using namespace std;
//typedefs
typedef string::const_iterator str_it;
//declarations
//use const ref and iterators to save time on copying and erasing
bool TransformLine(const string & bits, str_it bits_front, const string & chars, str_it chars_front);
int main(int argc, char* argv[])
{
//check there are at least two command line arguments: binary executable and file name
//ignore additional arguments
if(argc < 2)
{
cout << "Invalid command line argument. No input file name provided." << "\n"
<< "Goodybe...";
return -1;
}
//create input stream and open file
ifstream in;
in.open(argv[1], ios::in);
while(!in.is_open())
{
char* name;
cout << "Invalid file name. Please enter file name: ";
cin >> name;
in.open(name, ios::in);
}
//variables
string line_bits, line_chars;
//reserve space up to constraints to reduce resizing time later
line_bits.reserve(150);
line_chars.reserve(1000);
int line = 0;
//loop over lines (<=50 by constraint, ignore the rest)
while((in >> line_bits >> line_chars) && (line < 50))
{
line++;
//impose bit and char constraints
if(line_bits.length() > 150 ||
line_chars.length() > 1000)
continue; //skip this line
(TransformLine(line_bits, line_bits.begin(), line_chars, line_chars.begin()) == true) ? (cout << "Yes\n") : (cout << "No\n");
}
//close file
in.close();
return 0;
}
bool TransformLine(const string & bits, str_it bits_front, const string & chars, str_it chars_front)
{
//using iterators so store current length as local const
//can make these const because they're not altered here
int bits_length = distance(bits_front, bits.end());
int chars_length = distance(chars_front, chars.end());
//check success rule
if(bits_length == 0 && chars_length == 0)
return true;
//Check fail rules:
//1. next bit is 0 but next char is B
//2. bits length is zero (but char is not, by previous if)
//3. char length is zero (but bits length is not, by previous if)
if((*bits_front == '0' && *chars_front == 'B') ||
bits_length == 0 ||
chars_length == 0)
return false;
//we now know that chars_length != 0 => chars_front != chars.end()
//kill a bit and then call recursively with each possible reduction of front char group
bits_length = distance(++bits_front, bits.end());
//current char group tracker
const char curr_char_type = *chars_front; //use const so compiler can optimize
int curr_pos = distance(chars.begin(), chars_front); //position of current front in char string
//since chars are 0-indexed, the following is also length of current char group
//start searching from curr_pos and length is relative to curr_pos so subtract it!!!
int curr_group_length = chars.find_first_not_of(curr_char_type, curr_pos)-curr_pos;
//make sure this isn't the last group!
if(curr_group_length < 0 || curr_group_length > chars_length)
curr_group_length = chars_length; //distance to end is precisely distance(chars_front, chars.end()) = chars_length
//kill the curr_char_group
//if curr_group_length = char_length then this will make chars_front = chars.end()
//and this will mean that chars_length will be 0 on next recurssive call.
chars_front += curr_group_length;
curr_pos = distance(chars.begin(), chars_front);
//call recursively, adding back a char from the current group until 1 less than starting point
int added_back = 0;
while(added_back < curr_group_length)
{
if(TransformLine(bits, bits_front, chars, chars_front))
return true;
//insert back one char from the current group
else
{
added_back++;
chars_front--; //represents adding back one character from the group
}
}
//if here then all recursive checks failed so initial must fail
return false;
}
They give the following test cases, which my code solves correctly:
Sample input:
1| 1010 AAAAABBBBAAAA
2| 00 AAAAAA
3| 01001110 AAAABAAABBBBBBAAAAAAA
4| 1100110 BBAABABBA
Correct output:
1| Yes
2| Yes
3| Yes
4| No
Since a transformation is possible if and only if copies of it are, I tried just copying each binary and letter sequences onto itself various times and seeing how the clock goes. Even for very long bit and character strings and many lines it has finished in under 10 seconds.
My question is: since CodeEval is still saying it is running longer than 10 seconds but they don't share their input, does anyone have any further suggestions to improve the performance of this recursion? Or maybe a totally different approach?
Thank you in advance for your help!
Here's what I found:
Pass by constant reference
Strings and other large data structures should be passed by constant reference.
This allows the compiler to pass a pointer to the original object, rather than making a copy of the data structure.
Call functions once, save result
You are calling bits.length() twice. You should call it once and save the result in a constant variable. This allows you to check the status again without calling the function.
Function calls are expensive for time critical programs.
Use constant variables
If you are not going to modify a variable after assignment, use the const in the declaration:
const char curr_char_type = chars[0];
The const allows compilers to perform higher order optimization and provides safety checks.
Change data structures
Since you are perform inserts maybe in the middle of a string, you should use a different data structure for the characters. The std::string data type may need to reallocate after an insertion AND move the letters further down. Insertion is faster with a std::list<char> because a linked list only swaps pointers. There may be a trade off because a linked list needs to dynamically allocate memory for each character.
Reserve space in your strings
When you create the destination strings, you should use a constructor that preallocates or reserves room for the largest size string. This will prevent the std::string from reallocating. Reallocations are expensive.
Don't erase
Do you really need to erase characters in the string?
By using starting and ending indices, you overwrite existing letters without have to erase the entire string.
Partial erasures are expensive. Complete erasures are not.
For more assistance, post to Code Review at StackExchange.
This is a classic recursion problem. However, a naive implementation of the recursion would lead to an exponential number of re-evaluations of a previously computed function value. Using a simpler example for illustration, compare the runtime of the following two functions for a reasonably large N. Lets not worry about the int overflowing.
int RecursiveFib(int N)
{
if(N<=1)
return 1;
return RecursiveFib(N-1) + RecursiveFib(N-2);
}
int IterativeFib(int N)
{
if(N<=1)
return 1;
int a_0 = 1, a_1 = 1;
for(int i=2;i<=N;i++)
{
int temp = a_1;
a_1 += a_0;
a_0 = temp;
}
return a_1;
}
You would need to follow a similar approach here. There are two common ways of approaching the problem - dynamic programming and memoization. Memoization is the easiest way of modifying your approach. Below is a memoized fibonacci implementation to illustrate how your implementation can be speeded up.
int MemoFib(int N)
{
static vector<int> memo(N, -1);
if(N<=1)
return 1;
int& res = memo[N];
if(res!=-1)
return res;
return res = MemoFib(N-1) + MemoFib(N-2);
}
Your failure message is "Aborted after 10 seconds" -- implying that the program was working fine as far as it went, but it took too long. This is understandable, given that your recursive program takes exponentially more time for longer input strings -- it works fine for the short (2-8 digit) strings, but will take a huge amount of time for 100+ digit strings (which the test allows for). To see how your running time goes up, you should construct yourself some longer test inputs and see how long they take to run. Try things like
0000000011111111 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBAAAAAAAA
00000000111111110000000011111111 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBAAAAAAAA
and longer. You need to be able to handle up to 150 digits and 1000 letters.
At CodeEval, you can submit a "solution" that just outputs what the input is, and do that to gather their test set. They may have variations so you may wish to submit it a few times to gather more samples. Some of them are too difficult to solve manually though... the ones you can solve manually will also run very quickly at CodeEval too, even with inefficient solutions, so there's that to consider.
Anyway, I did this same problem at CodeEval (using VB of all things), and my solution recursively looked for the "next index" of both A and B depending on what the "current" index is for where I was in a translation (after checking stoppage conditions first thing in the recursive method). I did not use memoization but that might've helped speed it up even more.
PS, I have not run your code, but it does seem curious that the recursive method contains a while loop within which the recursive method is called... since it's already recursive and should therefore encompass every scenario, is that while() loop necessary?

grabbing data sets from a file with an arbitrary amount of spaces

**No direct answers or code examples please, this is my homework which i need to learn from. I'm looking for help concerning the algorithm i need to develop.
I seem to be having a logic error in coming up with a solution for a portion of my class work, the program involves multiple files, but here is the only relevant portion:
I have a file PlayerStats that holds the stats for a basketball player in:
rebounds
points
assists
uniform #
my initial reaction would be to create a while loop and read these into a temporary struct that holds these values, then create a merge function that merges the values of the temp struct with the inital array of records, simple enough?
struct Baller
{
//other information on baller
int rebounds;
int assists;
int uniform;
int points;
void merge(Baller tmp); //merge the data with the array of records
}
//in my read function..
Baller tmp;
int j = 0;
inFile << tmp.uniform << tmp.assists << tmp.points << tmp.rebounds
while(inFile){
ArrayRecords[j].merge(tmp);
j++;
//read in from infile again
}
The catch:
The file can have an arbitrary number of spaces between the identifiers, and the information can be in any order(leaving out the uniform number, that is always first). e.g.
PlayerStats could be
11 p3 a12 r5 //uniform 11, 3 points 12 assists 5 rebounds
//other info
OR
11 p 3 r 5 a 12 //same exact values
What I've come up with
can't seem to think of an algorithm to grab these values from the file in the correct order, i was thinking of something along these lines:
inFile << tmp.uniform; //uniform is ALWAYS first
getline(inFile,str); //get the remaining line
int i = 0;
while(str[i] == " ") //keep going until i find something that isnt space
i++;
if(str[i] == 'p') //heres where i get stuck, how do i find that number now?
else if(str[i] == 'a')
eles if(str[i] = 'r'
If you're only going to check one letter, you could use a switch statement instead of if / else, that would make it easier to read.
You know where the number starts at that point, (hint: str[i+1]), so depending on what type your str[] is, you can either use atoi if its a char array, or std::stringstream if it's an std::string.
I'm tempted to give you some code, but you said not too. If you do want some, let me know and I'll edit the answer with some code.
Instead of using a 'merge' function, try using an std::vector so you can just push_back your structure instead of doing any 'merging'. Besides, your merge function is basically a copy assignment operator, which is created by the compiler by default (you don't need to create a 'merge' function), you just need to use = to copy the data across. If you wanted to do something special in your 'merge' function, then you should overload the copy assignment operator instead of a 'merge' function. Simples.
Do something like that:
int readNumber () {
while isdigit (nextchar) -> collect in numberstring or directly build number
return that number;
}
lineEater () {
Read line
skip over spaces
uniform=readNumber ();
haveNum=false;
haveWhat=false;
Loop until eol {
skip over spaces
if (isdigit)
number=readNumber ();
skip over spaces
haveNum=true;
else
char=nextChar;
haveWhat=true;
if (haveChar and haveNum) {
switch (char) {
case 'p' : points=number; break;
...
}
haveNum=false;
haveWhat=false;
}
}
or, if you are more ambitous, write a grammar for your input and use lex/yacc.

C++ selecting a number of random items without repeating

Write a program that randomly selects from a bag of eight objects.
Each object can be red, blue, orange, or green, and it can be a ball or a cube.
Assume that the bag contains one object for each combination (one red ball, one
red cube, one orange ball, one orange cube, and so on). Write code similar to
Example 5.3, using two string arrays—one to identify colors and the other to
identify shapes.
I am trying to write a program to carry out the above exercise - the problem I am having is the same object can be selected more than once each time.
This is the code so far
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
int rand_0toN1(int n);
void choose_object();
char *colour[4] =
{"Red", "Blue", "Orange", "Green"};
char *object[2] =
{"Ball", "Cube"};
int main()
{
int n, i;
srand(time(NULL)); // Set seed for randomizing.
while (1) {
cout << "Enter no. of objects to draw ";
cout << "(0 to exit): ";
cin >> n;
if (n == 0)
break;
for (i = 1; i <= n; i++)
choose_object();
}
return 0;
}
void choose_object() {
int c; // Random index (0 thru 4) into
// colours array
int o; // Random index (0 thru 2) into
// object array
c = rand_0toN1(4);
o = rand_0toN1(2);
cout << colour[c] << "," << object[o] << endl;
}
int rand_0toN1(int n) {
return rand() % n;
}
Let's try to solve this by making a real world analogy:
Let's say you have a massive jar of marbles, of the colors listed above. It's so massive (infinite size!) that you always have the same chance to draw a marble of a given color, always 1/4 each time.
How would you do this in real life? Would you just keep picking randomly, chucking the marble away as you draw it? Or would you maybe keep a little list of things you've drawn already?
Or maybe you only have one of each in the jar... You wouldn't put it back in would you? Because that's kind of what you're doing here.
Each of these thought paths will lead you to a good solution. I don't want to provide a code or anything because this kind of assignment is one that teaches you how to think like a computer.
Since this is homework, I'm not going to give an exact answer, but describe what you could do:
Keep a list of objects you've already chosen.
After you choose an object, compare that object to the list of objects you've already chosen. If it's in the list, choose another object. If it's not in the list, add it to the list.
Make sure that you don't try to choose more than 8 objects, or else you'll end up in an infinite loop in part 2.
These would go in your choose_object() subroutine. You could do it in a while() loop, something like:
int seen_before = 0;
while(!seen_before) {
pick your random numbers
if(numbers not in list) {
add to list
break
}
}