Comparing vectors of different length c++ - c++

I'm developing a version of Conway's Game of Life in which a user may input their own rules for cell birth, death, and survival in the format "B##/S##". In order to implement these rules, I use basic string parsing to move the birth (B) rules and survival (S) rules into separate vectors. However, I'm running into trouble forming the survival vector.
The original cell rules are in a vector, and its contents are compared to the cell birth vector. The problem I have is that when a rule string such as "B012345678/S183" is entered, parts of the survival vector are not being added because one vector is longer than the other, causing a comparison of empty values and a segfault.
My question is: is there something I can do to fill those empty values, or is there a way to pass over those empty values?
// Extract cell birth rules from rules string
vector<char> cellBirth(vector<char> cellrules) {
int i = 0;
vector<char> birthrule;
while (cellrules[i] != 'S') {
birthrule.push_back(cellrules[i]);
++i;
}
return birthrule;
}
// Extract cell survival rules
vector<char> cellSurvive(vector<char> cellrules, vector<char> cellbirth) {
vector<char> surviverule;
long size = cellrules.size();
//cout << "Cellrule size: " << size << endl;
for (int i = 0; i < size; i++) {
if (cellrules[i] != cellbirth[i]) { //Comparison happens here
surviverule.push_back(cellrules[i]);
}
}
return surviverule;
}

cellbirth is always going to be smaller than cellrules, so your approach is wrong. There are MANY ways to skin this cat, here is one:
vector<char> cellSurvive(vector<char> cellrules) {
vector<char> surviverule;
bool pastS = false;
for (int i = 0; i < cellrules.size(); i++) {
if (pastS)
surviverule.push_back(cellrules[i]);
else if (cellrules[i] == 'S')
pastS = true;
}
return surviverule;
}

Related

Why is my c++ sorting function so much slower than my c# sorting function?

I'm very new to c++, but I do have experience with other object oriented programming languages.
I'm attempting to alphabetically sort the lines in a file I have, which has roughly 5300 lines. I originally wrote the program in c++ for practice, but was curious to see how it would perform against my main language, c#.
To my surprise, the same sorting algorithm which takes my c++ function 18-20 seconds to execute, finishes in less than 3 seconds in c#.
Given that I am very new to c++ (and not a very experienced programmer in general), I am sure this must be an error in the way I wrote something.
With all that being said, I am aware that there are quicker sorting methods to use. However, both programs are using the same algorithm so I don't understand the reason for the large performance gap.
I will note that I have tried converting the data to an array instead of a vector, but sorting the array was only consistently about 3 seconds faster (about 15 seconds total instead of 18).
What am I doing wrong? Any/all help is appreciated!
Below is the c++:
void select_sort_alphabetical(std::vector<std::string> _vector)
{
std::cout << "<< SORTING... >>" << "\n\n";
int char_index, i, j, size = _vector.size(), loop_iterations = 0;
char char1, char2;
std::string temp;
// Iterate through all lines
for (i = 0; i < (size - 1); i++)
{
for (j = (1 + i); j < size; j++)
{
char_index = 0;
char1 = _vector[i][char_index]; // Getting first character of each line
char2 = _vector[j][char_index];
// While the letters to be compared are the same, move onto the next character
while (char1 == char2)
{
char_index++;
char1 = _vector[i][char_index]; // Setting chars to the next characters in each line
char2 = _vector[j][char_index];
}
// Once the characters are different - if line x.ascii_code greater than line x+1.ascii_code...
if (_vector[i][char_index] > _vector[j][char_index]) // comparing characters
{
// Swapping places
temp = _vector[i];
_vector[i] = _vector[j];
_vector[j] = temp;
}
loop_iterations++;
}
}
//print_lines_from_vect(_vector);
// Clearing contents of vector and freeing up memory (trying to, anyway)
_vector.clear();
_vector.shrink_to_fit();
std::cout << "\nIterations: " << loop_iterations << "\n";
}
and here is the c#:
public static string[] select_sort_alphabetical(string[] lines, ref int loop_iterations)
{
Console.WriteLine("<< SORTING... >>");
// Iterate through all lines
for (int i = 0; i < (lines.Length - 2); i++)
{
for (int j = (1 + i); j < (lines.Length); j++)
{
int char_index = 0;
char char1 = lines[i][char_index]; // Getting first character of each line
char char2 = lines[j][char_index];
// While the letters to be compared are the same, move onto the next character
while (char1 == char2)
{
char_index++;
char1 = lines[i][char_index];
char2 = lines[j][char_index];
}
// Once the characters are different - if line x.ascii_code greater than line x+1.ascii_code...
if (lines[i][char_index] > lines[j][char_index]) // comparing characters
{
// Swapping places
string temp = lines[i];
lines[i] = lines[j];
lines[j] = temp;
}
loop_iterations++;
}
}
return lines;
}
One reason your algorithm would be slower, without taking in account other differences between languages, is swapping lines:
// Swapping places
string temp = lines[i];
lines[i] = lines[j];
lines[j] = temp;
in c#, string temp = original means temp and original point to the same string. modifying each will reflect in the other.
in c++, string temp = original means temp is a new string. Modifying one will not modify the other.
C++ provides move class members, which allow new objects to "steal" the resources of the original object.
std:.swap, in order to swap objects, make something like
string temp = steal(lines[i]);
lines[i] = steal(lines[j]);
lines[j] = steal(temp);
This is a simplification of the real mechanism.
Btw, if you use swap, you will see far faster debug, because that line swapping is a big cost in your algorithm.

C++ If I sort a vector, how can I get another vector to align with that vector? [duplicate]

This question already has answers here:
Suppose we have two std::vectors v1 and v2 and we dont want to combine these in a struct. How to transform v2 the same way v1 was transformed by sort?
(3 answers)
Closed 1 year ago.
I created this little project in C++ for a basketball 'gameish' thing. One thing I wanted to implement was a funciton that allowed one to see who had the highest or lowest stats out of all of the players, in this case, specifically, points per game (ppg).
I broke up the stat components of the players and the names of the players into two different vectors, vector <vector <string> > names and vector <vector <double>> stats. I made it so that names[0] correlated to stats[0], so LeBron and his stats would be represented by say 1. I figured out how to sort the vectors by descending or ascending order, but when I sort a vector, say stats[0], the order is now different from the original order, and so it doesn't align with names[0]. So when I print stats[0][i] belongs to names[0][i] it no longer is true, as the two are no longer 'connected'. I've tried to troubleshoot this myself first, but came up empty, and then tried searching online for an answer which I haven't found, perhaps I didn't look hard enough. What do I do to make it so that the now mixed-up order of the stats vector can be written out correctly?
This code I created, seen below, works sometimes, for ppg it works until around 20. I tried to create it so that you could use any vector .
void sorting_test(bool ascend, int number, vector <double> statistic) {
vector <vector <double>> ppg_desc {
{},//ppg
{},//slot
{},//locked
};
//
for (int i = 0; i < statistic.size(); i++) {
ppg_desc[0].push_back(statistic[i]);
ppg_desc[1].push_back(i);
}
sort(ppg_desc[0].begin(), ppg_desc[0].end());
if (ascend == false)
reverse(ppg_desc[0].begin(), ppg_desc[0].end());
//
for (int i = 0; i < statistic.size(); i++) {
//
bool lok = false;
//
for (int f = 0; f < statistic.size(); f++) {
//
for (int d = 0; d < ppg_desc[2].size(); d++) {
//
if (i == ppg_desc[1][d]) {
//
lok = true;
//
for (int s = f + 1; s < statistic.size(); s++) {
//
if (statistic[s] == ppg_desc[0][i]) {
lok = false;
f = s;
if (f >= statistic.size()) f = statistic.size() - 1;
}
}
}
}
//
//if (stats[6][f] == ppg_desc[0][i] && lok == false) ppg_desc[1][i] = f, ppg_desc[2].push_back(ppg_desc[1][i]), cout<<i<<"-";
if (statistic[f] == ppg_desc[0][i] && lok == false) ppg_desc[1][i] = f, ppg_desc[2].push_back(i);
}
}
//
for (int i = 0; i < number; i++) {
cout << i << ".) " << ppg_desc[0][i] << " - " << names[0][ppg_desc[1][i]] << endl;
}
//
}
What you basically need is a list of the indices, sorted by one of the vectors content.
This can be achieved with a variant of std::sort taking function objects / lambdas; something like this:
std::vector<int> score = {2,4,3};
std::vector<std::string> names = {"a", "b", "c"};
std::vector<int> V(N);
std::iota(V.begin(),V.end(), 0); // fill V with values increasing by 1
std::sort(V.begin(),V.end(), [&](int i,int j){return score[i]<score[j];} );
std::cout << "Names sorted by score: " << names[V[0]] << ", "<< names[V[1]] << ", "<< names[V[2]] << "\n";
As you can see, you can use the indices in V, now sorted by score, as index into names.
See example at cpp.sh
Inspiration: https://stackoverflow.com/a/40183830
An alternative solution, as suggested in comments, would be to include all values that belong together (both names and scores in my example) into a struct, then have a vector of this struct, and then again use above sort method with a specialized sorting function.
struct Player { std::string name; int score; }
std::vector<Player> players;
//... insert some players
std::sort(players.begin(), players.end(), [](auto const & p1, auto const & p2) { return p1.score < p2.score; });
// .. and now all your data is sorted by score!

Quicksort String Vector Alphabetically

I was having trouble with my code. I pass in an array of strings (names) and I want to do a quick sort and sort them alphabetically. Then, what I would like to do is with my array of years and ages, is swap those values respectively with the values swapped in my names array. However, I'm having trouble trying to implement that.
In the main function, I pass in:
quicksort(names, names[0], names[names.size() - 1]);
And in that code contains
void quicksort(vector<string> &names, string min, string max){
cout << "\n\tSorting names...\n";
int temp = 0,
i = 0;
string lowMin = max,
lowMax = min,
highMin = max,
highMax = min,
pivot;
vector<string> below,
above;
if (min != max){
pivot = (max[i] + min[i]) / 2;
while (temp < names.size()){
if (names[temp] <= pivot){
if (lowMax.compare(names[temp]) < 0){
lowMax = names[temp];
}
if (lowMin.compare(names[temp]) > 0){
lowMin = names[temp];
}
below.push_back(names[temp]);
}
else {
if (highMax.compare(names[temp]) < 0){
highMax = names[temp];
}
if (highMin.compare(names[temp]) > 0){
highMin = names[temp];
}
above.push_back(names[temp]);
}
temp++;
}
if ((below.size() > 1) && (names.size() != below.size())){
quicksort(below, lowMin, lowMax);
}
if ((above.size() > 1) && (names.size() != above.size())){
quicksort(above, highMin, highMax);
}
for (size_t i = 0; i < below.size(); i++){
names[i] = below[i];
}
for (size_t i = below.size(); i < names.size(); i++){
names[i] = above[i - below.size()];
}
}
} // // End quicksort()
In this case, would it be better to make a swap function and send in two integers so I can swap values in my other vector arrays? For example, I was thinking swapValue(int i, int j){ /* do something */}
Also, can someone explain to me the difference between foobar[i].swap(foobar[j]) and swap(foobar[i], foobar[j])? Are these methods more efficient than say creating a temp variable and swapping values?
Don't implement quicksort if you do it only because you need some sorting algorithm to use.
You seem to have three std::vector for name, age and year, where elements at the same position are related. Why not combine everything?
struct Person //or some name
{
std::string name;
int age;
int year;
int operator<(const Person &other) //comparison
{
return name.compare(other.name);
}
};
Of course, you could make a full class with the Big5 etc. too, if you want.
Now, with a vector<Person> v;, you can use std::sort:
std::sort(v.begin(), v.end());
That's all.
...If you still want to have a quicksort function, take eg. this, and change the lines with the swaps so that swaps are made on all three vectors.
About your other question:
The swap of std::string and the independent function swap with string paramters do the same thing (technically they don't have to, they are completely independent, but they do).
And why swap(a,b) is better than c=a;a=b;b=c;:
In the second code, values are copied three times. For std::string, this means three times allocating new memory and copying the whole content. Swap can do it without any content copy (it can access the internal pointers etc. and exchange only these).

How to apply a sort function to a string.find( ) to print results alphabetically?

I have a program that reads a text file into a struct (members- str author and str title) and gives the user the option to display all records in the file, search for an author, or search for a title. Now I need to integrate a sort function into this process, so that when the user searches by author or title the results are listed alphabetically.
The following sort function works perfectly with my showAll function, but I have absolutely no idea how I can modify my search functions to alphabetize the results.
Sort function code:
void sortByTitle(int counter){
//variable
int a, b, minIndex;
string temp;
for (a = 0; a < counter; a++){
minIndex = a;
for (b = a + 1; b < counter - 1; b++){
if (books[b].title < books[minIndex].title){
minIndex = b;
}
}
if(minIndex != a) {
temp = books[a].title;
books[a].title = books[minIndex].title;
books[minIndex].title = temp;
cout << books[a].title << endl;
}
}
}
And this is my current title search function:
int showBooksByTitle(int counter, string bookTitle){
int recordCount = 0;
//find the user-input string inside bookTitle
for (int a = 0; a < counter; a++){ //loop through the whole file
if (books[a].title.find(bookTitle) != string::npos){
//print a matching record
cout << books[a].title << " " << "(" << books[a].author << endl;
//keep track of the number of matching records
recordCount++;
}
}
return recordCount;
}
My assignment specifies these function headers, that the search functions return the number of records found, and that the data be read into a struct (rather than a vector). So I have to leave those aspects as they are.
How can I apply the selection sort to the search function so that I can print the records in order?
Any help would be much appreciated!
Here you set
smallestIndex = index;
then you check if
books[index].title < books[smallestIndex].title
It appears you are trying to implement a selection sort. A good snippet can be found here.
Furhtermore:
I don't see the need for declaring loc outside the for-loop. say for(int loc....
There is an abundance of sorting algorithms on wikipedia and you can use std::sort.
In the second line you shadow index with the same variable in the
for-loop.
I don't know how you store books, but if you would use std::vector you don't have to pass counter every time. You can just use books.size().

Using struct with an insertion sort

I'm having some trouble with an insertion sort, passing in data from a struct.
It's returning the error: |98| cannot convert 'store' to 'int' in assignment.
struct store{
char tag[5];
int cost;
long int volume;
};
void costSort(store storedEntries[], int count);
void volumeSort(store storedEntries[], int count);
int main(){
store record[100];
ifstream fin;
char choice;
int count = 0;
fin.open("stockdata.txt");
//file read in
if(fin.good())
{
while(!fin.eof())
{
fin >> record[count].tag;
fin >> record[count].cost;
fin >> record[count].volume;
count++;
}
count--;
}
cout << "Main Menu:" << endl;
cout << "c: sort data by Cost\nv: sort data by trade Volume\nq: Quit\nEnter Choice: ";
cin >> choice;
switch(choice)
{
case 'C':
case 'c': //costSort(record, count);
break;
case 'V':
case 'v': volumeSort(record, count);
break;
case 'q':
case 'Q': return 0;
break;
}
return 0;
}
void volumeSort(store record[], int count)
{
int p = 0, item = 0;
for(int i=1; i<count; i++){
cout << "test";
item = record[i];
p = (i - 1);
while(p>=0 && item < record[p]){
record[p+1] = record[p];
p--;
}
record[p+1] = item;
cout << record[i].tag << " " << record[i].volume << endl;
}
}
The insertion sort is in the function void volumeSort().
Any advice would be appreciated, i haven't had any issues up until now :S
You're comparing non-like types with no operator provided to support the comparison (and none needed if this is done correctly). Currently you're comparing int to store. What you should be comparing is two volume members of two store objects.
A simple loop that is probably closer to what you want would be something like this:
// note: count is size_t, an unsigned magnitude. only used signed
// integer types where it makes sense a negative integer will be
// plausible input.
void volumeSort(store record[], size_t count)
{
for(size_t i=1; i<count; ++i)
{
// compare current element to one below us, swapping if needed
// and stopping as soon as we reach an equal or lesser record
size_t j=i;
while(j>0 && record[j].volume < record[j-1].volume)
{
std::swap(record[j-1], record[j]);
--j;
}
}
}
Or something similar. Note the comparison of:
record[j].volume < record[j-1].volume
in the while condition. Apples to apples...
For an interesting insertion_sort that utilizes two wonderful features of the standard library, std::upper_bound and std::rotate, a rather dense version of the function can be created, looking something like this:
void insertion_sort(store record[], size_t len)
{
for (auto it = record; it != record+len; ++it)
{
std::rotate(std::upper_bound(record, it, *it,
[](const store& lhs, const store& rhs) { return lhs.volume < rhs.volume; }),
it, std::next(it));
}
}
This is considerably more efficient than it first may seem, as the search for the proper placement of the prospect element is done in O(logN) using std::upper_bound. Then std::rotate opens the hole where the element goes and it is swapped into place.
Just some food for thought. Coupled with the comparator that is going to inlined by even remedial optimization and it has a lot more punch than you may first think. Still not as kick-ass as std::sort, usually highly optimized utilizing multiple algorithms, but still good brain food.
Best of luck.
You are trying to compare a int with a store.
This will not work unless you overload < operator to compare a int and a store.
store record[];
int p = 0, item = 0;
//[...]
while (p >= 0 && item < record[p])
//Neither can you assign that
record[p + 1] = item;
Operator example:
bool operator<(const int &left, const store &s)
{
//You could also do some calculation in here,
//if you want to compare a value inside the struct
//like this:
return left < s.cost;
//Please... do it in place.
//item < record[p].cost;
}
if you want to sort by volume you should take
record[i].volume even when comparing...the types should be same when comparing values..
Similarly for other cases..