C++ How to handle user input given in contests/problems format - c++

Recently I have been starting to participate in c++ contests but I cannot find the best way to handle user input when given in this format.
E.g. 4 and 3 are the dimensions of the next block of input
4 3
1 2 4 5
1 6 7 4
1 5 0 0
The problem I've been having is that sometimes the automatic testing machine successfully can test its inputs and sometimes no, so far the method I've been using is the next
std::vector<std::vector<char>> vec;
void get_lines(std::string in) {
std::vector<char> line(in.begin(), in.end());
vec.push_back(line);
}
std::cin >> height >> width;//this is in main()
std::cin.ignore();
for (int i = 0; i < height; i++)
{
std::getline(std::cin, input);
get_lines(input);
input = "";
}
But I'm sure it's not the most efficient nor the more stable way to handle this type of input.
How can I handle user input in the above-mentioned format so that the testing machine can easily input its values?

First of all, I am sorry for you that you made the decision to participate in such contests. It will help you to learn on how to solve algorithms, but they usually use an extremely bad programming style.
Anyway. Back to your question. As always. It depends. If you have data that are just separated by white space, you can use nearly always formatted input functions with the extractor operator ´>>´. This operator will ignore (skip) all white space in standard mode, including the "new line" at the end of a line. So, no need to read line by line.
The good point ofthis "contest pages" is that input is always be considered correct. So, you do not need to do input-error checking or data plausibilisation. The will always use some test environment, where they "push" the data in your code via input redirection. In real life, user input is always very error prone and must be checked carefully.
And you see that, although not necessary, they give the dimensions of the matrix, to ease up data input (this would normally not be necessary, because we can find out by ourselves).
So, first read the dimensions.
With that, construct your ´std::vector´
Then use 2 nested range based for loops to read the values
One of many possible examples could look like this:
#include <iostream>
#include <vector>
int main() {
// Define variables that will hold the dimension of the matrix
size_t numberOfRows{}, numberOfColumns{};
// Get user input, the dimension of the matrix
std::cin >> numberOfRows >> numberOfColumns;
// Define our container, including its size
std::vector<std::vector<int>> matrix(numberOfRows, std::vector<int>(numberOfColumns, 0));
// Read values from user input
for (std::vector<int>& row : matrix) for (int& i : row)
std::cin >> i;
// Show output
for (const std::vector<int>& row : matrix) {
for (const int& i : row) std::cout << i << ' ';
std::cout << '\n';
}
}
Also the use of std::istream_iterators in conjunction with range constructors can be used here. But, as said. It depends.
If they have Comma Separated Values, or white space within values, like strings, then you need to use other mechanisms.

You can do it like this:
std::cin >> height >> width;
std::vector<std::vector<int>> vec;
vec.resize(height, vector<int>(width)); // resize
for(int i {0}; i < height; ++i)
{
for(int j {0}; j < width; ++j)
{
std::cin >> vec[i][j];
}
}

Related

Faster File Operations C++

So I am making a renderer in c++ and opengl for a class of mine. I am making an animation program for extra credit that will change values in a text file right before my renderer reads them in each frame. My problem is that this section of code isn't writing fast enough
while (clock() < time_end)
{
timeStep = clock() + fps * CLOCKS_PER_SEC;
for(int k=0; k < currOps.size(); k++)
{
// increase/decrease each set once for the current timestep
// a case for each operation
int pos = currAxis[k];
if(currOps[k] == "loc")
{
opsFile[8+pos] = patch::to_string(atof(opsFile[8+pos].c_str()) + locScale[pos-1]*timeAdjust);
//edit this value by loc adjust
}
else if(currOps[k] == "rot")
{
opsFile[4+pos] = patch::to_string(atof(opsFile[4+pos].c_str()) + rotScale[pos-1]*timeAdjust);
//edit this value by rot adjust
}
else if(currOps[k] == "scl")
{
opsFile[pos] = patch::to_string(atof(opsFile[pos].c_str()) + sclScale[pos-1]*timeAdjust);
//edit this value by scl adjust
}
}
currFile.close(); //save file and restart so we don't append multiple times
currFile.open(files[location[0]].c_str(), ofstream::out); // so we can write to the file after closing
for(int j=0; j <opsFile.size(); j++)
{
// update the file
currFile << opsFile.at(j);
currFile << "\n";
}
while(clock() < timeStep)
{
//wait for the next time steps
}
}
Specifically currFile operations at the end. If I take the currFile operations out it will run at the desired fps. FPS is set to .033 so that it does 30 fps. Also it will run fast enough when fps = 0.1. Any optimizations would be great. If need to see any other part of my code let me know and I will upload. The whole thing is around 170 lines.
currOps, files, and opsFile are vectors of strings
sclScale, rotScale, and locScale are vectors of doubles
currAxis is vectors of ints
Here are some general changes which may help:
I would convert the curOps to an enum rather than a string (save you the string comparisons.) Looks like you should pre-process that container and build a sequence of enums (then your code in the loop becomes a switch)
Don't use vector<string> for curOps, simply read the floats from the file and write the floats out - this will save you all those pointless conversions to and from string. If you wanted to take it further, convert the file to binary (if you are allowed by the exercise), and store a simple structure which contains the floats you need and use memory mapped files (you don't need boost for that, it's straight forward just using mmap!)
Before going down the mmap route - try the float read/write from file. For example, let's say that each "row" in your file corresponds to something like the following:
struct transform {
double x, y, z;
};
struct op {
transform scale, rot, loc;
};
Declare a bunch of stream in/out operators for these (for example:
std::ostream& operator<<(std::ostream& os, const transform& tx) {
return os << tx.x << ' ' << tx.y << ' ' << tx.z;
}
std::istream& operator>>(std::istream& is, transform& tx) {
return is >> tx.x >> tx.y >> tx.z;
}
(a similiar set will be required for op)
Now your vector is std::vector<op>, which you can easily stream in and out from your file, for example, to read:
op i;
while(file >> i) { curOps.push_back(i); }
To write:
for (auto o : curOps) file << o << '\n';
If this is still not enough, then mmap (btw - it's possible on windows too: Is there a memory mapping api on windows platform, just like mmap() on linux?)
Try using the functions in stdio.h instead. iostreams are terribly inefficient.
In your case all you will need is fseek() ... fputs(). Avoiding reopening the file each time should actually help quite a lot.

Key Value Pair implementation C

I have a .txt file that stores student names along with two of their best marks. If a student for some reason, i.e. dropping out of course, fails to pass a course, then no marks are recorded.
My file looks like this
Samuel= 90.5, 95.9
Bill= 25.2, 45.3
Tim
Anthony= 99.9, 12.5
Mark
Rob
Basically, Tim, Mark and Rob failed the course and hence their marks are not stored. Also to differentiate between a failed mark and a pass mark, I have used the = symbol. Basically, I want to store all the names into memory alongside their associated values.
This is my implementation, however it is flawed in the sense that I have declared a double *marks[2] array to store all six marks, when clearly it will only store 3. I am having trouble storing the values into the double array.
This is my code...
istream& operator>> (istream& is, Students& student)
{
student.names = new char*[6];
for (int i=0; i<10; i++)
{
student.names[i] = new char[256];
student.marks[i] = new double[2];
is.getline(student.names[i], sizeof(student.names));
for (int j=0; j < 256; j++)
{
if((student.names[i][j] == '='))
{
int newPos = j + 1;
for (int k = newPos; k < 256; k++)
{
student.names[i][k - newPos] = student.names[k];
}
}
}
}
}
How can I go about storing the values of the students with the valid marks? Please, no use of vectors or stringstreams, just pure C/C++ char arrays
You have a few options, you could use a struct like so
struct Record {
std::string name;
double marks[2];
};
And then stick that into something like std::vector<Record> or an array of them like
Records *r = new Records[1000];
You could also keep three different arrays (either automatically allocated or dynamically allocated or even std::vector), one to hold the name, two to hold the marks.
In each case you would just indicate a fail by some thing like the marks being zero.
Also, you can use
std::string name;
double first, second;
std::cin >> name;
if (name[name.size() - 1] == '=')
std::cin >> first >> second;
And this will parse the input like you want it to for a single line. Once you've done that you can wrap the whole thing in a loop while sticking the values you get into some sort of data structure that I already described.
Hope that gives you a few ideas on where to go!
Here's a strategy:
First of all you need to implement a struct to hold the key-value pair, I suggest the following:
struct Student {
char name[30];
double marks[2];
};
Note that you can give the dimension of the char array inside the struct if you know that the length will never be higher. (which is given here)
Now what you need is to know how many lines are in your ifstream, you could make a loop of is.getline() calls to get there. (don't forget to call is.clear() and is.seekg(0) when finished, to be at the beginning for the real loop)
When you know how many lines are in your ifstream you can use dynamically cast the Array of your struct with the actual length of your file:
Student * students = new Student[lineCount]; // line count of is
As you can see, there's no need to have a std::vector to hold the values. Consider that the getline() loop may be an overkill just to get the line count, alternatively you could give a length to Students at compile-time by making an array with a length that will never be overpassed.
(e.g. Student students[128];)
Now you need to parse the lines, i'd suggest you make a loop like the following (line by line):
// int parseLine ( char* line, char* name, double* marks ) { ...
bool hasMarks=false;
int iLine=0; // Line pos iterator
int iName=0; // Name pos iterator
char mk1Str[4]; // String buffer, Mark 1
char mk2Str[4]; // String buffer, Mark 2
while(line[iLine]!='\0')
{
if(line[iLine]=='=')
{
hasMarks=true;
name[iLine]='\0';
for(int iMark=0;iMark<4;iMark++)
{
mk1Str[iMark]=line[iLine+iMark+2];
mk2Str[iMark]=line[iLine+iMark+8];
// ^^ You can harcode the offsets (2,8) since they don't change
}
break;
}
name[iName++]=line[iLine];
iLine++;
}
Now what you need is to parse the marks to double values, for this you could use the atof() function that works with char*. The bool hasMarks helps you know if a student has defined marks, if not, you could define dummy values like -1 for the mark fields of your struct.
I think this works quite well for your case...

C++ container splitting

I have an unknown number of int variables in a text file, all i know is that the number of variables will be a multiple of 6.
I want to read these files in to a container, and split them down into smaller containers, where each container takes 6 values.
For example, if there is 30 variables in the text file, I want 5 containers, each containing 6 of the variables.And they need to be in the order that they are in the file, i.e., the first container holds the first six values.
I have read the files into a list, and vector for the moment, and was wandering which one is more suited. I've read about the split function, but after a look around, I haven't been able to successfully apply it to one of these attempts, mainly because I don't know how many smaller containers I am going to need
This is my code so far:
Vector Method
std::vector<int> Ticket;
std::ifstream fin (username + "Ticket.txt");
while (!fin.eof())
{
fin >> num;
Ticket.push_back(num);
}
fin.close();
Ticket.shrink_to_fit();
List method
std::list<int> Ticket1;
std::ifstream fin (username + "Ticket.txt");
while (!fin.eof())
{
fin >> num;
Ticket1.push_back(num);
}
fin.close();
Alternatively, if I could somehow read 6 values from the file straight into smaller containers, and keep doing this till the end of the file, hence skipping the big container that would be awesome.
You can use a vector of vectors.
std::vector< std::vector<int> > Ticket;
std::vector<int> newVector;
std::ifstream fin (username + "Ticket.txt");
while ( fin >> num )
{
newVector.push_back( num );
// if the vector is full, then insert it and start afresh
if ( newVector.size() == 6 ) {
Ticket.push_back( newVector );
newVector.clear();
}
}
fin.close();
At the end, the Ticket vector shall contain all the required vectors.
To print each vector to console, use two nested loops:
for ( int i = 0; i < Ticket.size(); i++ ) { // outer vector
for ( int j = 0; j < Ticket[i].size(); j++ ) { // inner vectors
std::cout << Ticket[i][j] << " ";
}
std::cout << "\n";
}
If you create a temporary accumulator, and your ultimate destination:
vector<int> temp ;
vector<vector<int>> package ;
Then just fill up temp, until its full, and push onto the end of package:
while ( fin >> num )
{
temp.push_back( num) ;
if ( temp.size() == MyDesiredSize ) { package.push_back( temp) ; temp.clear() ; }
}
When you push_back on package it will make a copy, that's why you can clear temp afterwards.
Do you need the values within the container to be contiguous as they are within a c-array, or do you need to be able to have more control over the memory allocation using the reserve member function of std::vector? If not, then consider deque or list over vector.
http://www.cplusplus.com/reference/deque/deque/
You also use a fixed size array if you have a C++ 11 compiler that supports it.
http://www.cplusplus.com/reference/array/array/
For instance, you could setup a container like this to setup a list of arrays.
std::list<std::array<int, 6>> containersOfSix;
On the other hand, you might be able to use one of the inserter functions if you would prefer both parts of the container to be dynamic.
http://www.cplusplus.com/reference/iterator/istream_iterator/
http://www.cplusplus.com/reference/iterator/insert_iterator/
Consider reading through that material, and toying around with some of those options. That might lead you to search for other threads related to those, which will help you find more specific examples.
i would use the C function Fscanf()
You can use a format and read the 6 numbers at once.
fscanf(FILE,"%i %i %i %i %i %i",&var1,&var2,&var3,&var4,&var5,&var6)
Then you just need to handle the container, creating one before and reading directly to it or by coping the values if they are what you expect.

C++ fastest cin for reading stdin?

I've profiled a computationally-heavy C++ program on Linux using cachegrind. Surprisingly, it turns out the bottleneck of my program is not in any sorting or computational method ... it's in reading the input.
Here is a screenshot of cachegrind, in case I'm mis-interpreting the profiler results (see scanf()):
I hope I'm right in saying that scanf() is taking 80.92% of my running time.
I read input using cin >> int_variable_here, like so:
std::ios_base::sync_with_stdio (false); // Supposedly makes I/O faster
cin >> NumberOfCities;
cin >> NumberOfOldRoads;
Roads = new Road[NumberOfOldRoads];
for (int i = 0; i < NumberOfOldRoads; i++)
{
int cityA, cityB, length;
cin >> cityA;
//scanf("%d", &cityA); // scanf() and cin are both too slow
cin >> cityB;
//scanf("%d", &cityB);
cin >> length;
//scanf("%d", &length);
Roads[i] = Road(cityA, cityB, length);
}
If you don't spot any issues with this input reading code, could you please recommend a faster way to read input? I'm thinking of trying getline() (working on it while I wait for responses). My guess is getline() may run faster because it has to do less conversion and it parses the stream a less total number of times (just my guess, though I'd have to parse the strings as integers eventually too).
What I mean by "too slow" is, this is part of a larger homework assignment that gets timed out after a certain period of time (I believe it is 90 seconds). I'm pretty confident the bottleneck is here because I purposely commented out a major portion of the rest of my program and it still timed out. I don't know what test cases the instructor runs through my program, but it must be a huge input file. So, what can I use to read input fastest?
The input format is strict: 3 integers separated by one space for each line, for many lines:
Sample Input:
7 8 3
7 9 2
8 9 1
0 1 28
0 5 10
1 2 16
I need to make a Road out of the integers in each line.
Also please not that input is redirected to my program to the standard input (myprogram < whatever_test_case.txt). I'm not reading a specific file. I just read from cin.
Update
Using Slava's method:
Input reading seems to be taking less time, but its still timing out (may not be due to input reading anymore). Slava's method is implemented in the Road() ctor (2 down from main). So now it takes 22% of the time as opposed to 80%. I'm thinking of optimizing SortRoadsComparator() as it's called 26,000,000 times.
Comparator Code:
// The complexity is sort of required for the whole min() max(), based off assignment instructions
bool SortRoadsComparator(const Road& a, const Road& b)
{
if (a.Length > b.Length)
return false;
else if (b.Length > a.Length)
return true;
else
{
// Non-determinism case
return ( (min(a.CityA, a.CityB) < min(b.CityA, b.CityB)) ||
(
(min(a.CityA, a.CityB) == min(b.CityA, b.CityB)) && max(a.CityA, a.CityB) < max(b.CityA, b.CityB)
)
);
}
}
Using enhzflep's method
Considering solved
I'm going to consider this problem solved because the bottleneck is no longer in reading input. Slava's method was the fastest for me.
Streams pretty well know to be very slow. It is not a big surprise though - they need to handle localizations, conditions etc. One possible solution would be to read file line by line by std::getline( std:::cin, str ) and convert string to numbers by something like this:
std::vector<int> getNumbers( const std::string &str )
{
std::vector<int> res;
int value = 0;
bool gotValue = false;
for( int i = 0; i < str.length(); ++i ) {
if( str[i] == ' ' ) {
if( gotValue ) res.push_back( value );
value = 0;
gotValue = false;
continue;
}
value = value * 10 + str[i] - '0';
gotValue = true;
}
if( gotValue ) res.push_back( value );
return res;
}
I did not test this code, wrote it to show the idea. I assume you do not expect to get anything in input but spaces and numbers, so it does not validate the input.
To optimize sorting first of all you should check if you really need to sort whole sequence. For comparator I would write methods getMin() getMax() and store that values in object (not to calculate them all the time):
bool SortRoadsComparator(const Road& a, const Road& b)
{
if( a.Length != b.Length ) return a.Length < b.length;
if( a.getMin() != b.getMin() ) return a.getMin() < b.getMin();
return a.getMax() < b.getMax();
}
if I understood how you current comparator works correctly.
As Slava says, streams (i.e cin) are absolute pigs in terms of performance (and executable file size)
Consider the following two approaches:
start = clock();
std::ios_base::sync_with_stdio (false); // Supposedly makes I/O faster
cin >> NumberOfCities >> NumberOfOldRoads;
Roads = new Road[NumberOfOldRoads];
for (int i = 0; i < NumberOfOldRoads; i++)
{
int cityA, cityB, length;
cin >> cityA >> cityB >> length;
Roads[i] = Road(cityA, cityB, length);
}
stop = clock();
printf ("time: %d\n", stop-start);
and
start = clock();
fp = stdin;
fscanf(fp, "%d\n%d\n", &NumberOfCities, &NumberOfOldRoads);
Roads = new Road[NumberOfOldRoads];
for (int i = 0; i < NumberOfOldRoads; i++)
{
int cityA, cityB, length;
fscanf(fp, "%d %d %d\n", &cityA, &cityB, &length);
Roads[i] = Road(cityA, cityB, length);
}
stop = clock();
printf ("time: %d\n", stop-start);
Running each way 5 times (with an input file of 1,000,000 entries + the first 2 'control' lines) gives us these results:
Using cin without the direction to not sync with stdio
8291, 8501, 8720, 8918, 7164 (avg 8318.3)
Using cin with the direction to not sync with stdio
4875, 4674, 4921, 4782, 5171 (avg 4884.6)
Using fscanf
1681, 1676, 1536, 1644, 1675 (avg 1642.4)
So, clearly, one can see that the sync_with_stdio(false) direction does help. One can also see that fscanf beats the pants off each approach with cin. In fact, the fscanf approach is nearly 3 times faster than the better of the cin approaches and a whopping 5 times faster than cin when not told to avoid syncing with stdio.
inline void S( int x ) {
x=0;
while((ch<'0' || ch>'9') && ch!='-' && ch!=EOF) ch=getchar_unlocked();
if (ch=='-')
sign=-1 , ch=getchar_unlocked();
else
sign=1;
do
x = (x<<3) + (x<<1) + ch-'0';
while((ch=getchar_unlocked())>='0' && ch<='9');
x*=sign;
}
you can use this function for any type of number input, just change the paramater type.
This will run pretty faster than std scanf.
If you want to save more time best thing will be to use fread() and fwrite() but in that case you have to manipulate the input by yourself.
To save time you should use fread() to read a large chunk of data from standard input stream in one call.That will decrease the number of I/O calls hence you will see a large difference in time.

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.