C++ Vector push / pop - c++

I've been looking all over for a solution to this. Not using c++11.
for(int a = 1; a < team1.chan; a++)
{
team1.nums.push_back(ppb.back());
ppb.pop_back();
cout << team1.nums[a] << " " << endl;
}
ppb is an uns int vector with 1-1000 that have been shuffled.
team1 is a struct with nums as an uns int vector.
I'm trying to take the last number in ppb and assign it to the first number in team1.nums.
Then I need to delete that value in ppb so I have no duplicates.
I printed the actual numbers in ppb and they are fine. When I compile I get about 40 numbers like 2397295 then about 80 zeroes.
I am slowly getting C++, but vectors are killing me. Thank you.

Vectors are zero indexed but your 'a' starts at 1.
So the first value from ppb.back() is stored at team1.nums[0] but you print team1.nums[1].
The next value from ppb.back() is stored at team1.nums[1] but now you print team1.nums[2].

Try to loop using
while(ppb.empty() == false)
{
...// Your code here
}

I think that all you need is
team1.nums.assign( std::make_move_iterator( team1.rbegin() ), std::make_move_iterator( team1.rend() ) );
team1.clear();
Or if the move constructor is not supported then
team1.nums.assign( team1.rbegin(), team1.rend() );
team1.clear();

It is better to use iterators when using containers. It will avoid such indexing errors. Also you have access to some neat functions like std::copy which puts all the copy code you wrote in just one line.
std::copy(ppb.rbegin(),ppb.rend(),back_inserter(team1.nums));
back_inserter uses the vector::push_back so you dont have to reserve the space

Related

why doesn't user defined function sort the elements of same length in the order given?

My task is to sort the words of a string in the increasing order of their length and for words of same length, I have to keep them in the order given.
for ex: "to be or not to be" will become "to be or to be not".
i am first making a vector 'v' of all the words in the string and then trying to sort the vector using user defined function in sort() function of C++.
Here is my code:
#include <bits/stdc++.h>
using namespace std;
static bool comparelength(string first,string second){//function to compare length
return first.size()<second.size();
}
int main() {
string text="Jlhvvd wfwnphmxoa qcuucx qsvqskq cqwfypww dyphntfz hkbwx xmwohi qvzegb ubogo sbdfmnyeim tuqppyipb llwzeug hrsaebveez aszqnvruhr xqpqd ipwbapd mlghuuwvec xpefyglstj dkvhhgecd kry";
vector<string> v;
string cur="";
text+=" ";
for(int i=0;i<text.size();i++){
if(text[i]==32){//if space is encountered then the word is inserted in the vector
v.push_back(cur);
cur="";
}
else{
cur+=text[i];//if not space then text[i] is added to the current word
}
}
sort(v.begin(),v.end(),comparelength);//sort the vector
for(int i=0;i<v.size();i++)
cout<<v[i]<<" ";
Now it gives this output:
"Kry xqpqd ubogo hkbwx qvzegb jlhvvd xmwohi qcuucx qsvqskq llwzeug ipwbapd dyphntfz cqwfypww tuqppyipb dkvhhgecd sbdfmnyeim xpefyglstj mlghuuwvec aszqnvruhr hrsaebveez wfwnphmxoa"
But the correct output should be:
"Kry hkbwx ubogo xqpqd jlhvvd qcuucx xmwohi qvzegb qsvqskq llwzeug ipwbapd cqwfypww dyphntfz tuqppyipb dkvhhgecd wfwnphmxoa sbdfmnyeim hrsaebveez aszqnvruhr mlghuuwvec xpefyglstj"
see the position 1,2 and 3(using 0 indexing).
it should give: hkbwx ubogo xqpqd.
but it gives: xqpqd ubogo hkbwx.
which makes me think that it is not sorting the words of same length in the order given. You can find many other positions where this happens(for ex: 4,5,6 and 7).
But for the string "leetcode plus try suck geaser is cool best"
it gives the correct output which is: "is try plus suck cool best geaser
leetcode"
Can anyone make it clear why is it not working for the former string but working for the latter.
I've tried doing
static bool comparelength(string first,string second){
if(first.size()==second.size())
return true;
if(first.size()<second.size())
return true;
else
return false;
}
But this throws runtime error.
sorry for making the question messy but i really want to understand this.
std::sort is not stable, ie order of elements that are equivalent is not necessarily preserved. If you get a stable sorting from std::sort then this is just by chance. Stable sorting is more expensive (O(N·log(N)^2) vs O(N·log(N))), hence you have to explicitly ask for it. It can be done with std::stable_sort.
You could use std::sort with a custom comparator if you would populate a container of std::pair<std::string,size_t> where second is the index in the original container. However, I suppose using std::stable_sort is simpler.

Show the percentage of process completion in a C++ program

I am making a set of C++ library as a part of my Data Structures assignment, which includes custom implementation of vector, sorting algorithms, stacks, etc. I am supposed to work on the running time of sorting algorithms, bubble sort, selection sort, quick sort, etc., which are part of my library.
Now the data set given to test the algorithms in of the order of 10^6. I ran bubble sort on a data of 2*10^6 elements, and it took about 138 minutes for the program to run, and in all this time, I did not know if my sorting algorithm is working correctly or not, or is it even working or not. I would want to add another feature to the sorting functions, i.e they could display the percentage of sorting done, and I think this is possible, since algorithms like bubble sort are deterministic.
I need a message like something to appear as soon as I start the process:
Bubble sort under progress. Done: 17%
This percentage is to be determined by the algorithm. Consider the example of bubble sort with 10000 elements. If you look at the bubble sort algorithm(refer here: https://en.wikipedia.org/wiki/Bubble_sort), it has 2 loops, and after each iteration of the main loop, one element is fixed to its correct position in the sorted array. So after like 1 iteration, the percentage should increase by 0.01%.
Though this percentage calculation has a problem that in this case, the time for the percentage to increase keeps on decreasing, but something like this would do.
Also, this number should increase as and when required, on the same place. But I have no idea how to implement it.
You can pass a callback function of a generic type to your bubblesort function and call the function at reasonable intervals.
This will impact performance, but this shouldn't be a concern when you're using bubblesort anyway.
First we'll need some includes:
#include <iostream>
#include <vector>
#include <random>
#include <chrono>
And then the bubblesort function, which I essentially took from wikipedia: https://en.wikipedia.org/wiki/Bubble_sort#Optimizing_bubble_sort
template <typename T, typename Func>
void bubblesort(std::vector<T> &v, Func callback) {
size_t const len = v.size();
size_t n = v.size();
while(n > 0) {
size_t newn = 0;
for(size_t i = 1; i <= n-1; ++i) {
if (v[i - 1] > v[i]) {
std::swap(v[i-1], v[i]);
newn = i;
}
}
n = newn;
callback(100-static_cast<int>(n*100/len));
}
}
We will call the given callback function (or use operator() on an object) whenever it's done sorting in one element.
The parameter we pass is an integer percentage of how far we've come. Note that due to integer arithmetic you cannot change the order of operations with n*100/v.size() or else it would always result in 0, since n will always be smaller than v.size();
using namespace std::chrono; //to avoid the horrible line becoming even longer
int main() {
std::vector<int> vec;
/* fill vector with some data */
std::mt19937 generator(static_cast<unsigned long>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count())); //oh god
for(int i = 0; i < 100000; ++i) {
vec.push_back(static_cast<int>(generator()));
}
For initialization we get create a random number generator and seed it with the current time. Then we put some elements in the vector.
char const *prefix = "Bubble sort under progress. Done: ";
int lastp = -1;
bubblesort(vec, [&lastp,prefix](int p){
//if progress has changed, update it
if(p != lastp) {
lastp = p;
std::cout << "\r" << prefix << p << "%" << std::flush;
/*std::flush is needed when we don't start a new line
'\r' puts the cursor to the start of the line */
}
});
std::cout << "\r" << prefix << "100%" << std::endl;
//make sure we always end on 100% and end the line
}
Now the core part: we pass a C++ lambda function to our bubblesort function as a callback. Our bubblesort function will then call this lambda with the percentage value and write it to the screen.
And voilà, we got ourselves some neat output:
https://youtu.be/iFGN8Wy9T3o
Closing notes:
You can of course integrate the lamda function into the sort function itself, however I would not recommend this as you lose a lot of flexibility. But it's a design choice that's up to you - if you don't need the flexibility, just hardcode it.
The percentage is not very accurate, in fact knowing you're at 20% (and how long it took to get there) does not tell you much at all about the time it will take to get to 100% as it could very well be, that the last 20% of the vector were sorted (and thus were quick to sort with bubblesort - O(n)), but the remaining 80% are random, and take O(n^2) to sort.
In fact all it tells you is that you're making progress, but that's all you wanted in the first place so I guess that's okay.
If you want a more accurate percentage adjust your program like this:
#include <iomanip>
/* ... */
callback(10000-static_cast<int>(n*10000/len));
/* ... */
std::cout.fill('0'); //to fill leading zero of p%100
std::cout << "\r" << prefix << p/100 << "." << std::setw(2) << p%100 << "%" << std::flush;
If you decide to use floating point values instead remember to clear remnant characters from previous outputs - "\r" only resets the cursor position, but does not clear the line.
Use std::cout.precision(3); for a fixed precision or write some spaces after your message to clear previous runs.
For the special case of bubblesort, you can take the number of elements you have, then divide that by 100. If you have 552 elements, then you will get 5. (integers make sense to work with). Then, have a counter in your loop. If the counter is a multiple of 5, (you've so far sorted 5 elements) then you can increase the percentage by 1 and print it. As far as printing it so that the percentage appears on the spot instead of printing below, you can print backspaces! Either that or try using the ncurses library, though that might be overkill. Finally, a different way to do this might be to use a linux style progress bar that is 50 characters long or something similar.

Setting vector elements in range-based for loop [duplicate]

This question already has answers here:
How can I modify values in a map using range based for loop?
(4 answers)
Closed 1 year ago.
I have come across what I consider weird behaviour with the c++11 range-based for loop when assigning to elements of a dynamically allocated std::vector. I have the following code:
int arraySize = 1000;
std::string fname = "aFileWithLoadsOfNumbers.bin";
CTdata = new std::vector<short int>(arraySize, 0);
std::ifstream dataInput(fname.c_str(), std::ios::binary);
if(dataInput.is_open()
{
std::cout << "File opened sucessfully" << std::endl;
for(auto n: *CTdata)
{
dataInput.read(reinterpret_cast<char*>(&n), sizeof(short int));
// If I do "cout << n << endl;" here, I get sensible results
}
// However, if I do something like "cout << CTdata->at(500) << endl;" here, I get 0
}
else
{
std::cerr << "Failed to open file." << std::endl;
}
If I change the loop to a more traditional for(int i=0; i<arraySize; i++) and use &CTdata->at(i) in place of &n in the read function, things do as I would expect.
What am I missing?
Change this loop statement
for(auto n: *CTdata)
to
for(auto &n : *CTdata)
that is you have to use references to elements of the vector.
you have to write
for( auto& n : *CTdata )
because auto n means short int n when you need short int& n.
i recommend you to read difference beetween decltype and auto.
The reason your loop fails is because you reference vector elements by value. However, in this case you can eliminate the loop altogether:
dataInput.read(reinterpret_cast<char*>(CTdata->data()), arraySize*sizeof(short int));
This reads the content into the vector in a single call.
Vlad's answer perfectly answers your question.
However, consider this for a moment. Instead of filling your array with zeroes from the beginning, you could call vector<>::reserve(), which pre allocates your backing buffer without changing the front facing portion of the vector.
You can then call vector<>::push_back() like normal, with no performance implications, while still maintaining the logic clear in your source code. Coming from a C# background, looping over your vector like that looks like an abomination to me, not to mention you set each element twice. Plus if at any point your element generation fails, you'll have a bunch of zeroes that weren't supposed to be there in the first place.

make permutations of an array of numbers, then turn them into a single int

Basic idea: Given an array, find all the permutations of that array. Then, take each of those arrays and put it all together. Eg the array {6,5,3,4,1,2} gives you 653412. The permutations work, but I cannot get the integers.
int main ()
{
int myints[] = {2,3,4,5,6,7,8,9};
int k;
int dmartin=0;
int powof10=1;
std::cout << "The 8! possible permutations with 8 elements:\n";
do {
for(k=0; k<8; k++){
std::cout << myints[k] << ' ';
dmartin=myints[8-k-1]*powof10+dmartin;
powof10=powof10*10;
}
cout << "\n" << dmartin << "\n";
} while ( std::next_permutation(myints,myints+8) );
dmartin=0;
return 0;
}
I also have some code that works when you just have one array, but in this case there are thousands. I though I needed to reset dmartin=0 at the end of each while loop so that it didn't keep adding to the previous answer, however when I tried that I got "0" for each of my answers. Without trying to reset, I get answers that seem random (and are negative).
The problem is that you're not resetting your two variables inside your loop, so they'll continue from the values they had during the previous iteration, which will just be wrong, and will quickly overflow, giving seemingly rubbish output. Try putting this at the beginning or the end of the do-while loop:
dmartin = 0;
powof10 = 1;
But you're really overcomplicating it a lot. It would be way simpler to just build the number from the most significant digit instead of the least significant one instead. This would eliminate the need for a powof10 variable. This new for-loop would look like this:
for(k = 0; k < 8; k++){
std::cout << myints[k] << ' ';
dmartin = 10*dmartin + myints[k];
}
That won't work for long, since your integer will soon overflow.
That's probably what you are experiencing when you get negative numbers.
Using an integer to store the result does not seem the most appropriate choice to me. Why not use a string, for instance? That would save you the hassle of reinventing base10 conversion in 2014, and you could easily derive a number from the string when needed.
That won't solve the overflow problem, though.
First point: the code to take a vector of digits and turn them into a single number should almost certainly be written as a function, not just code inside the loop.
Second point: you can use std::string like a container of char, and apply normal algorithms to it.
Seem to me, the lazy way would look like this:
std::string input="23456789";
do {
std::cout<<std::stoi(input)<<"\n";
} while (std::next_permutation(input.begin(), input.end()));

Insert into a desired element of an array and push all other elements one spot over in c++

Having some issues with one small function I'm working on for a homework assignment.
I have a static array size of 20 (shelfSize), however, I only need to use a max of 10 elements. So I don't have to worry about out of bounds etc (the entire array of 20 is initialized to 0).
What I am looking to do is insert an integer, booknum, into an element of an array it receives as input.
This my current logic:
void insert_at(int booknum, int element){
for(int i=element+1; i < shelfSize; i++)
bookshelf[i+1]=bookshelf[i]
bookshelf[element]=booknum;
}
so let's say I have the this array:
[5,4,3,1,7]
I want to insert an 8 at element 1 and have the array turn to:
[5,8,4,3,1,7]
Technically, everything after the final element 7 is a 0, however, I have a separate print function that only prints up to a certain element.
No matter how many times I take some pencil and paper and manually write out my logic, I can't get this to work.
Any help would be appreciated, thanks.
You should start from the end of the array, this should word for you:
void insert_at(int booknum, int element)
{
for (int i = shelfsize-1;i>element;i--)
bookshelf[i] = bookshelf[i-1];
bookshelf[element] = booknum;
}
Also I recommend that you get used to handling illegal values, for example, what if a user entered 21?
The optimized code would be:
bool insert_at(int booknum, int element)
{
if (element>=shelfsize-1)
return false;
for (int i = shelfsize-2;i>element;i--)
bookshelf[i] = bookshelf[i-1];
bookshelf[element] = booknum;
return true;
}
If your example is correct, then you're assuming 1-based indices instead of 0-based. Use the following instead:
void insert_at(int booknum, int element){
for(int i=element; i < shelfSize; i++)
bookshelf[i]=bookshelf[i-1];
bookshelf[element-1]=booknum;
}
However, I would prefer you just use the same code, and change "at element 2" in your example to "at element 1". Always remember C++ arrays are 0-based.
That being said, please tell your professor that this is why vectors (and other standard containers) were made, and that C++ arrays are evil.
http://www.parashift.com/c++-faq-lite/containers.html#faq-34.1
Just noticed, you are copying up, this means your function does this:
[5,4,3,1,7]
--^
[5,4,4,1,7]
--^
[5,4,4,4,7]
--^
[5,4,4,4,4]
--^
[5,4,4,4,4,4]
For moving values in an array, you always want to copy in the opposite direction to which you are moving, so to move up, you want to copy each item up from the top down:
[5,4,3,1,7]
--^
[5,4,3,1,7,7]
--^
[5,4,3,1,1,7]
--^
[5,4,3,3,1,7]
--^
[5,4,4,3,1,7]
And then you can overwrite the index you freed up.