vector constructor creating vector with one less element - c++

I am trying to split a vector into "almost equal" parts, and create subvectors for those parts.
I have asked the original question here: How to split a vector into n "almost equal" parts but I found a really good solution, what I am trying to use, from here: Best way to extract a subvector from a vector?
I wrote this function for creating integers for start and end values (round is my function which rounds to specified digits.)
void split( double number, double parts )
{
double loop = number / parts;
for( int i = 0; i < parts; i++ )
{
int start = round( i * loop, 0 );
int end = round( ( i + 1 ) * loop - 1, 0 );
cout << start << " " << end << endl;
}
}
This function so far works OK, but my problem is that when I try to run this:
vector<some> dest( &source[start], &source[end] );
Then it creates one LESS element, then required. I mean for example if I call it with
vector<some> dest( &source[0], &source[99] );
then it will have 99 elements, instead of 100. Why is this happening?
How can I fix it? If I use [end+1], then it terminates at the last vector, with "subscript out of range."

The vector constructor (and all STL constructors that accept pointer ranges, for that matter) are designed to take in a range of STL-style iterators. When using iterators, you specify a range by providing a pointer to the first- and the past-the-end elements, not the first and last elements. If you wanted to create a vector as a copy of the subrange (0, 99) out of another vector, you could write
vector<some> dest(source.begin(), source.begin() + 100);
Note that this uses vector iterators to specify the slice of the first 100 elements rather than operator[], which has undefined behavior when the provided index is out of bounds. In your case, this undefined behavior is manifesting as a runtime debug error. Iterators don't have this problem, since they're specifically designed to be used this way.
If you want to use raw C++ arrays as input to the vector constructor, you could do it like this:
vector<some> dest(source, source + 100);
Hope this helps!

While it's not legal to use &v[n] if v is an std::vector with n elements you can use instead
vector<some> dest(v.begin()+first, v.begin()+last+1);
even if last+1 == n.

Related

C++ Vector Operations

Is there any alternative for this? Performing a vector operation in multiples on certain condition?
i want to perform erase vector operation (n-1) times, just deleting only first element in a particular vector on a given if condition.
is it possible to do like this
if ( ret.size() == n ){
(n-1)*order.erase(order.begin());
(n-1)*quantity.erase(quantity.begin());
(n-1)*price.erase(price.begin());
}
I am currently doing this
if ( ret.size() == 2 ){
order.erase(order.begin());
quantity.erase(quantity.begin());
price.erase(price.begin());
}
if ( ret.size() == 3 ){
order.erase(order.begin());
order.erase(order.begin());
quantity.erase(quantity.begin());
quantity.erase(quantity.begin());
price.erase(price.begin());
price.erase(price.begin());
}
order.erase( order.begin(), order.begin() + ( ret.size() - 1 ) );
Needs prior checking of ret.size() vs. order.size() of course, but it seems your code can assert that from context.
That being said, when you are repeatedly erasing from the beginning of your vectors, perhaps your vectors are sorted the wrong way, or you might be better off with std::deque, performance-wise.
Edit: From the comments, it appears that your actual problem is "how to remove all but the last element of a vector". There are a number of ways to do this, like
// actually erasing all but the last
order.erase( order.begin(), order.end() - 1 );
...or...
// creating a new vector with the last element of the old
order = vector< ... >{ order.back() };
(The elipsis here standing for the type of your order vector, not the actual elipsis -- you will have to fill in that part.)

Find uncommon elements using hashing

I think this is a fairly common question but I didn't find any answer for this using hashing in C++.
I have two arrays, both of the same lengths, which contain some elements, for example:
A={5,3,5,4,2}
B={3,4,1,2,1}
Here, the uncommon elements are: {5,5,1,1}
I have tried this approach- iterating a while loop on both the arrays after sorting:
while(i<n && j<n) {
if(a[i]<b[j])
uncommon[k++]=a[i++];
else if (a[i] > b[j])
uncommon[k++]=b[j++];
else {
i++;
j++;
}
}
while(i<n && a[i]!=b[j-1])
uncommon[k++]=a[i++];
while(j < n && b[j]!=a[i-1])
uncommon[k++]=b[j++];
and I am getting the correct answer with this. However, I want a better approach in terms of time complexity since sorting both arrays every time might be computationally expensive.
I tried to do hashing but couldn't figure it out entirely.
To insert elements from arr1[]:
set<int> uncommon;
for (int i=0;i<n1;i++)
uncommon.insert(arr1[i]);
To compare arr2[] elements:
for (int i = 0; i < n2; i++)
if (uncommon.find(arr2[i]) != uncommon.end())
Now, what I am unable to do is to send only those elements to the uncommon array[] which are uncommon to both of them.
Thank you!
First of all, std::set does not have anything to do with hashing. Sets and maps are ordered containers. Implementations may differ, but most likely it is a binary search tree. Whatever you do, you wont get faster that nlogn with them - the same complexity as sorting.
If you're fine with nlogn and sorting, I'd strongly advice just using set_symmetric_difference algorithm https://en.cppreference.com/w/cpp/algorithm/set_symmetric_difference , it requires two sorted containers.
But if you insist on an implementation relying on hashing, you should use std::unordered_set or std::unordered_map. This way you can be faster than nlogn. You can get your answer in nm time, where n = a.size() and m = b.size(). You should create two unordered_set`s: hashed_a, hashed_b and in two loops check what elements from hashed_a are not in hashed_b, and what elements in hashed_b are not in hashed_a. Here a pseudocode:
create hashed_a and hashed_b
create set_result // for the result
for (a_v : hashed_a)
if (a_v not in hashed_b)
set_result.insert(a_v)
for (b_v : hashed_b)
if (b_v not in hashed_a)
set_result.insert(b_v)
return set_result // it holds the symmetric diference, which you need
UPDATE: as noted in the comments, my answer doesn't count for duplicates. The easiest way to modify it for duplicates would be to use unordered_map<int, int> with the keys for elements in the set and values for number of encounters.
First, you need to find a way to distinguish between the same values contained in the same array (for ex. 5 and 5 in the first array, and 1 and 1 in the second array). This is the key to reducing the overall complexity, otherwise you can't do better than O(nlogn). A good possible algorithm for this task is to create a wrapper object to hold your actual values, and put in your arrays pointers to those wrapper objects with actual data, so your pointer addresses will serve as a unique identifier for objects. This wrapping will cost you just O(n1+n2) operations, but also an additional O(n1+n2) space.
Now your problem is that you have in both arrays only elements unique to each of those arrays, and you want to find the uncommon elements. This means the (Union of both array elements) - (Intersection of both array elements). Therefore, all you need to do is to push all the elements of the first array into a hash-map (complexity O(n1)), and then start pushing all the elements of the second array into the same hash-map (complexity O(n2)), by detecting the collisions (equality of an element from first array with an element from the second array). This comparison step will require O(n2) comparisons in the worst case. So for the maximum performance optimization you could have checked the size of the arrays before starting pushing the elements into the hash-map, and swap the arrays so that the first push will take place with the longest array. Your overall algorithm complexity would be O(n1+n2) pushes (hashings) and O(n2) comparisons.
The implementation is the most boring stuff, so I let it to you ;)
A solution without sorting (and without hashing but you seem to care more about complexity then the hashing itself) is to notice the following : an uncommon element e is an element that is in exactly one multiset.
This means that the multiset of all uncommon elements is the union between 2 multisets:
S1 = The element in A that are not in B
S2 = The element in B that are not in A
Using the std::set_difference, you get:
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::multiset<int> ms1{5,3,5,4,2};
std::multiset<int> ms2{3,4,1,2,1};
std::vector<int> v;
std::set_difference( ms1.begin(), ms1.end(), ms2.begin(), ms2.end(), std::back_inserter(v));
std::set_difference( ms2.begin(), ms2.end(), ms1.begin(), ms1.end(), std::back_inserter(v));
for(int e : v)
std::cout << e << ' ';
return 0;
}
Output:
5 5 1 1
The complexity of this code is 4.(N1+N2 -1) where N1 and N2 are the size of the multisets.
Links:
set_difference: https://en.cppreference.com/w/cpp/algorithm/set_difference
compiler explorer: https://godbolt.org/z/o3KGbf
The Question can Be solved in O(nlogn) time-complexity.
ALGORITHM
Sort both array with merge sort in O(nlogn) complexity. You can also use sort-function. For example sort(array1.begin(),array1.end()).
Now use two pointer method to remove all common elements on both arrays.
Program of above Method
int i = 0, j = 0;
while (i < array1.size() && j < array2.size()) {
// If not common, print smaller
if (array1[i] < array2[j]) {
cout << array1[i] << " ";
i++;
}
else if (array2[j] < array1[i]) {
cout << array2[j] << " ";
j++;
}
// Skip common element
else {
i++;
j++;
}
}
Complexity of above program is O(array1.size() + array2.size()). In worst case say O(2n)
The above program gives the uncommon elements as output. If you want to store them , just create a vector and push them into vector.
Original Problem LINK

Sort std::vector<int> but ignore a certain number

I have an std::vector<int> of the size 10 and each entry is initially -1. This vector represents a leaderboard for my game (high scores), and -1 just means there is no score for that entry.
std::vector<int> myVector;
myVector.resize(10, -1);
When the game is started, I want to load the high score from a file. I load each line (up to 10 lines), convert the value that is found to an int with std::stoi, and if the number is >0 I replace it with the -1 currently in the vector at the current position.
All this works. Now to the problem:
Since the values in the file aren't necessarily sorted, I want to sort myVector after I load all entries. I do this with
std::sort(myVector.begin(), myVector.end());
This sorts it in ascending order (lower score is better in my game).
The problem is that, since the vector is initially filled with -1 and there aren't necessarily 10 entries saved in the high scores file, the vector might contain a few -1 in addition to the player's scores.
That means when sorting the vector with the above code, all the -1 will appear before the player's scores.
My question is: How do I sort the vector (in ascending order), but all entries with -1 will be put at the end (since they don't represent a real score)?
Combine partitioning and sorting:
std::sort(v.begin(),
std::partition(v.begin(), v.end(), [](int n){ return n != -1; }));
If you store the iterator returned from partition, you already have a complete description of the range of non-trivial values, so you don't need to look for −1s later.
You can provide lambda as parameter for sort:
std::sort(myVector.begin(), myVector.end(),[]( int i1, int i2 ) {
if( i1 == -1 ) return false;
if( i2 == -1 ) return true;
return i1 < i2; }
);
here is the demo (copied from Kerrek)
but it is not clear how you realize where is which score after sort.
From your description, it appears that the score can be never negative. In that case, I'd recommend the scores to be a vector of unsigned int. You can define a constant
const unsigned int INFINITY = -1;
and load your vector with INFINITY initially. INFINITY is the maximum positive integer that can be stored in a 32 bit unsigned integer (which also corresponds to -1 in 2's complement)
Then you could simply sort using
sort(v.begin(),v.end());
All INFINITY will be at the end after the sort.
std::sort supports using your own comparison function with the signature bool cmp(const T& a, const T& b);. So write your own function similar to this:
bool sort_negatives(const int& a, const int& b)
{
if (a == -1) {
return false;
}
if (b == -1) {
return true;
}
return a < b;
}
And then call sort like std::sort(myVector.begin(), myVector.end(), sort_negatives);.
EDIT: Fixed the logic courtesy of Slava. If you are using a compiler with C++11 support, use the lambda or partition answers, but this should work on compilers pre C++11.
For the following, I assume that the -1 values are all placed at the end of the vector. If they are not, use KerrekSB's method, or make sure that you do not skip the indices in the vector for which no valid score is in the file (by using an extra index / iterator for writing to the vector).
std::sort uses a pair of iterators. Simply provide the sub-range which contains non--1 values. You already know the end of this range after reading from a file. If you already use iterators to fill the vector, like in
auto it = myVector.begin();
while (...) {
*it = stoi(...);
++it;
}
then simply use it instead of myVector.end():
std::sort(myVector.begin(), it);
Otherwise (i.e., when using indices to fill up the vector, let's say i is the number of values), use
std::sort(myVector.begin(), myVector.begin() + i);
An alternative approach is to use reserve() instead of resize().
std::vector<int> myVector;
myVector.reserve(10);
for each line in file:
int number_in_line = ...;
myVector.push_back(number_in_line);
std::sort(myVector.begin(), myVector.end());
This way, the vector would have only the numbers that are actually in file, no extra (spurious) values (e.g. -1). If the vector need to be later passed to other module or function for further processing, they do not need to know about the special nature of '-1' values.

Why is my for loop crashing on a vector of doubles?

This for loop always crashes immediately:
for (auto i = v.size() - 1; i >=0; --i);
Obviously I have a whole load of code in the loop, and v is a vector of doubles. I'm trying to iterate over them in reverse order.
What is going on here?
for (auto i = v.size() - 1; i >=0; --i);
Look at vector::size() method - it returns usually unsigned int (on strange platforms it might be other unsigned type)! So your i variable will have unsigned type.
When your loop will come to step i == 0 it will decrement it and i will have value 2^32 - 1 == UNSIGNED_INT_MAX (or other positive value if you work on strange platform - see vector::size_type on your platform to see underlying type). So it will never be less then 0, it will never stop your loop. I guess when it turns so big it crashes becouse it goes out of range, but i don't see whole code to be sure.
See here - look for size_type typedef - it says its unsigned type.
You might want to use reverse iterators (see #NathanOliver's response), though i'm not very fond of them in simple loops.
Since i is unsigned it will never be less than 0. It will wrap around to the maximum value that it can hold instead.
If you want to iterate through a vector backwards then you should use a reverse_iterator
std::vector<int> foo = {1,2,3,4,5,6,7,8,9};
for (auto it = foo.rbegin(); it != foo.rend(); ++it)
std::cout << *it << " ";
This will output
9 8 7 6 5 4 3 2 1
The variable i will be an unsigned type.
That can never be less than zero.
Eventually you will access an element outside the vector as i will wrap around to the largest possible unsigned value rather than going negative
What Bathsheba said: the auto type is an unsigned. So decrementing 0 becomes some large positive number, which is >= 0 so the loop continues, but that value is outside the vector's range and causes the crash.

Use Object in vector in loop

Currently, i have a loop iterating through a vector, and i'm trying to find the index of an object, while i'm in the loop, to delete it. How can i go about this?
Here's my code :
for (Object &a : objectDict)
{
a.setTime(theTime);
double tempMoveX = 0, tempMoveZ = 0, tempUX = 0,tempUZ = 0;
for (Object &b : objectDict)
{
if (a != b)
{
...
debug << fixed << setprecision(20) << "Collision" << endl;
a.appendMass(b.getMass());
objectDict.erase(find(objectDict.begin(), objectDict.end(), b));
...
Thats the important part. How can i erase object b from the vector?
One easy way is to simply build a separate vector containing the indexes of elements to erase later. Once you've finished going through the regular vector, loop in reverse order through the "to be removed" vector (in reverse because you don't want to invalidate the indexes as you go), and erase them.
Alternatively, as you iterate over the original vector, select the elements you want to keep, and copy them to another vector. At the very end, swap the two vectors (which is cheap). This will work better if you have relatively many elements to delete, on average.
Well, in case you need an index while iterating vector's elements, instead of:
for (Object &a : objectDict) { ...
do traditional:
for (size_t i = 0; i < objectDict.size(); ++i) { ...
and within the loop's body: instead of using reference a, you'll use objectDict[i], then when you will need to erase element, you can do:
objectDict.erase(vec.begin() + i);
i--;
i-- is used to move the index backwards by 1 so that when the next iteration increments it again, the element that follows right after the element that has been erased is not skipped.