Swapping elements efficiently in C++ vector - c++

Basically, I have a vector vect. I want to move part of vect from the end, to the start, efficiently. Example:
vect before = {1,2,3,4,5,6,7}
Moving the last two elements from end to start:
vect after = {6,7,1,2,3,4,5}
Now, I have the following function:
template <class ElementType>
void endToStart(std::vector<ElementType>& vect, size_t startPos)
{
std::vector<ElementType> temp;
temp.reserve(vect.size());
for (auto i = startPos; i < vect.size(); ++i)
{
temp.push_back(vect[i]);
}
for (auto i = 0; i < startPos; ++i)
{
temp.push_back(vect[i]);
}
vect.swap(temp);
}
Is there a more efficient way of doing this?

It looks like you need std::rotate:
#include <algorithm> // std::rotate
#include <iostream>
int main() {
std::vector<int> vect = {1,2,3,4,5,6,7};
std::rotate(vect.begin(), vect.begin() + 5, vect.end());
// ^^^^^^^^^^^^^^^^
// the new first position
for(auto v : vect) std::cout << v << ' ';
}
Demo

Related

Deleting both an element and its duplicates in a Vector in C++

I've searched the Internet and known how to delete an element (with std::erase) and finding duplicates of an element to then delete it (vec.erase(std::unique(vec.begin(), vec.end()),vec.end());). But all methods only delete either an element or its duplicates.
I want to delete both.
For example, using this vector:
std::vector<int> vec = {2,3,1,5,2,2,5,1};
I want output to be:
{3}
My initial idea was:
void removeDuplicatesandElement(std::vector<int> &vec)
{
std::sort(vec.begin(), vec.end());
int passedNumber = 0; //To tell amount of number not deleted (since not duplicated)
for (int i = 0; i != vec.size(); i = passedNumber) //This is not best practice, but I tried
{
if (vec[i] == vec[i+1])
{
int ctr = 1;
for(int j = i+1; j != vec.size(); j++)
{
if (vec[j] == vec[i]) ctr++;
else break;
}
vec.erase(vec.begin()+i, vec.begin()+i+ctr);
}
else passedNumber++;
}
}
And it worked. But this code is redundant and runs at O(n^2), so I'm trying to find other ways to solve the problem (maybe an STL function that I've never heard of, or just improve the code).
Something like this, perhaps:
void removeDuplicatesandElement(std::vector<int> &vec) {
if (vec.size() <= 1) return;
std::sort(vec.begin(), vec.end());
int cur_val = vec.front() - 1;
auto pred = [&](const int& val) {
if (val == cur_val) return true;
cur_val = val;
// Look ahead to the next element to see if it's a duplicate.
return &val != &vec.back() && (&val)[1] == val;
};
vec.erase(std::remove_if(vec.begin(), vec.end(), pred), vec.end());
}
Demo
This relies heavily on the fact that std::vector is guaranteed to have contiguous storage. It won't work with any other container.
You can do it using STL maps as follows:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
void retainUniqueElements(vector<int> &A){
unordered_map<int, int> Cnt;
for(auto element:A) Cnt[element]++;
A.clear(); //removes all the elements of A
for(auto i:Cnt){
if(i.second == 1){ // that if the element occurs once
A.push_back(i.first); //then add it in our vector
}
}
}
int main() {
vector<int> vec = {2,3,1,5,2,2,5,1};
retainUniqueElements(vec);
for(auto i:vec){
cout << i << " ";
}
cout << "\n";
return 0;
}
Output:
3
Time Complexity of the above approach: O(n)
Space Complexity of the above approach: O(n)
From what you have searched, we can look in the vector for duplicated values, then use the Erase–remove idiom to clean up the vector.
#include <vector>
#include <algorithm>
#include <iostream>
void removeDuplicatesandElement(std::vector<int> &vec)
{
std::sort(vec.begin(), vec.end());
if (vec.size() < 2)
return;
for (int i = 0; i < vec.size() - 1;)
{
// This is for the case we emptied our vector
if (vec.size() < 2)
return;
// This heavily relies on the fact that this vector is sorted
if (vec[i] == vec[i + 1])
vec.erase(std::remove(vec.begin(), vec.end(), (int)vec[i]), vec.end());
else
i += 1;
}
// Since all duplicates are removed, the remaining elements in the vector are unique, thus the size of the vector
// But we are not returning anything or any reference, so I'm just gonna leave this here
// return vec.size()
}
int main()
{
std::vector<int> vec = {2, 3, 1, 5, 2, 2, 5, 1};
removeDuplicatesandElement(vec);
for (auto i : vec)
{
std::cout << i << " ";
}
std::cout << "\n";
return 0;
}
Output: 3
Time complexity: O(n)

Create a vector with repeated entries of each Element

I want to expand a given vector by repeating every entry three times. For example, if the vector is [5,7]. The output vector should be [5 5 5 7 7 7]
#include<iostream.h>
#include<vector.h>
int main(void)
{
std::vector<int> x;
x.push_back(5);
x.push_back(7);
x.insert(x.end(), x.begin(), x.begin() + 1);
return 0;
}
This didnt work out. Any help would be appreciated.
A simple approach is to loop over the vector and create a new one:
std::vector<int> vec{5, 7};
// create a new vector
std::vector<int> new_vec;
new_vec.reserve(vec.size() * 3);
for (auto elem : vec) {
for (std::size_t i = 0; i < 3; ++i) {
new_vec.push_back(elem);
}
}
I don't know how simple code you want, but for example this works.
#include<iostream>
#include<vector>
int main(void)
{
std::vector<int> x;
x.push_back(5);
x.push_back(7);
for (std::vector<int>::iterator it = x.end(); it != x.begin(); )
{
it--;
it = x.insert(it, 2, *it);
}
// print the vector to check
for (size_t i = 0; i < x.size(); i++) std::cout << x[i] << " ";
std::cout << std::endl;
return 0;
}
Maybe something like this could help you achieve that:
#include <iostream>
#include <algorithm>
#include <vector>
template<typename T>
std::vector<T> RepeateEntryNumberOfTimes(std::vector<T> input, std::uint16_t numberOfTimes)
{
std::vector<T> result;
std::for_each(input.begin(), input.end(), [&result, numberOfTimes](T item){
for(std::uint16_t numberOfReps = 0; numberOfReps != numberOfTimes; ++numberOfReps)
{
result.push_back(item);
}
});
return result;
}
See godbolt example: https://godbolt.org/z/ns9o3b
Your code has problem since it inserting elements to same vector.
Modification of vector invalidates old iterators, so your code has undefined behavior.
Even ignoring this error, logic of your code doesn't seem to do what you are expecting.
template<typename In, typename Out>
Out replicate_elements(In b, In e, size_t n, Out o)
{
while(b != e) {
o = std::fill_n(o, n, *b++);
}
return o;
}
std::vector<int> foo(const std::vector<int>& x)
{
std::vector<int> r;
r.reserve(x.size() * 3);
replicate_elements(x.begin(), x.end(), 3, std::back_inserter(r));
return r;
}
https://www.godbolt.org/z/zvE5TG

initializing a vector with a lambda being fed the index in c++

Is there a library function for initializing a vector based on the index of its elements ?
This would shorten things like :
#include <vector>
using namespace std;
int main() {
auto square = [] (int n) {return n*n;};
vector<int> v(5, 0);
for (int i = 0; i < 5; i++){
v[i] = square(i);
}
}
The way that comes to mind is to break it into two steps. In this case std::iota will fill the vector with the inputs (0, 1, 2, etc). Then std::transform will perform your function square on each of the elements and replace them in the vector.
int main()
{
auto square = [] (int n) {return n*n;};
std::vector<int> v(5, 0);
std::iota(v.begin(), v.end(), 0);
std::transform(v.begin(), v.end(), v.begin(), square);
for (int i : v)
std::cout << i << ' ';
}
Output
0 1 4 9 16
Honestly this is the kind of thing that will be much more concise and streamlined once ranges are available, C++20 working example
int main()
{
auto square = [] (int n) {return n*n;};
for (int i : std::views::iota(0, 5) | std::views::transform(square))
std::cout << i << ' ';
}
For a vector there is easy way to calculate its index by subtracing pointers:
std::for_each(v.begin(),v.end(),
[&v,&square](auto& elem){ elem = square(&elem - &v[0]);});
by auto& elem you access original item of vector then index is calculated by &elem - &v[0] which is passed into square.

Finding multiple max elements in a vector C++

So.. I am trying to find the maximum value of a vector and its position in the vector. I am using a for loop, and it's working fine. My problem is, that if the maximum value appears more than once, I want to know all the positions in which it appears in the vector.. So, how could I manage this?
So far, this is the code I am using: (the vector called v has elements that I read from a file but I will not add that part of the code)
std::vector<double>v;
double maxvalue;
int position=0;
maxvalue = v[0];
for (unsigned int i=0; i<v.size(); i++){
if (v[i]> maxvalue){
maxvalue=v[i];
position= i;
}
}
You could modify your approach to keep a vector of indices where the maximum occurred:
#include <cfloat>
#include <iostream>
#include <utility>
#include <vector>
std::pair<double, std::vector<std::size_t>> FindMaxElements(std::vector<double> const& v)
{
std::vector<std::size_t> indices;
double current_max = -DBL_MAX;
for (std::size_t i = 0; i < v.size(); ++i)
{
if (v[i] > current_max)
{
current_max = v[i];
indices.clear();
}
if (v[i] == current_max)
{
indices.push_back(i);
}
}
return std::make_pair(current_max, indices);
}
int main()
{
auto result = FindMaxElements({1, 4, 7, 2, 7, 3});
std::cout << "max: " << result.first << '\n';
std::cout << "indices: ";
for (auto i : result.second)
std::cout << i << ' ';
}
Output
max: 7
indices: 2 4
Here is a two-pass version using the standard library (whereas it might be cleaner without it):
#include <vector>
#include <algorithm>
int main()
{
std::vector<double> v {/* fill it*/ };
std::vector<int> pos;
auto it = std::max_element(std::begin(v), std::end(v));
while (it != std::end(v))
{
pos.push_back(std::distance(std::begin(v), it));
it = std::find(std::next(it), std::end(v), *it);
}
//...
}
The function template below, find_maximums(), returns an std::vector<size_t> that contains the positions where the maximums are in the input vector. Note that it returns an empty vector of indexes if the input vector is empty.
template<typename T>
auto find_maximums(const std::vector<T>& v) {
std::vector<size_t> indexes;
for (auto it_max = std::max_element(v.begin(), v.end()); it_max != v.end();
it_max = std::find(it_max+1, v.end(), *it_max))
{
auto index = std::distance(v.begin(), it_max);
indexes.push_back(index);
}
return indexes;
}
As an example of use:
auto main() -> int {
std::vector<int> v = {11, 7, 3, 11, 0, 7, 1, 11, 11};
auto max_indexes = find_maximums(v);
if (max_indexes.empty())
return 1;
std::cout << "max: " << v[max_indexes.front()] << std::endl;
std::cout << "max at positions: ";
for (auto idx: max_indexes)
std::cout << idx << ' ';
std::cout << '\n';
}
It outputs:
max: 11
max at positions: 0 3 7 8
Passing a couple of iterators and a comparator
template <class It,
class Comp = std::less<typename std::iterator_traits<It>::value_type>>
auto max_elements_indices(It first, It last, Comp cmp = Comp{})
{
// This function returns a vector of indices, so to get the maximum, the caller
// should first check if the returned vector is empty and then use one of
// those indices to retrieve the value.
std::vector<std::size_t> indices;
if (first == last)
return indices;
// Using the first element instead of a sentinel value is easier to generalize
indices.push_back(0);
auto value = *first;
for (auto i = std::next(first); i != last; ++i)
{
// The most common case should be an element below the maximum
if ( cmp(*i, value) )
continue;
else
{
if ( cmp(value, *i) )
{
value = *i;
indices.clear();
}
indices.push_back(std::distance(first, i));
}
}
return indices;
}
It is testable 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?

This is a followup of this question. The only difference is the constrain that the two vectors cannot be combined in a struct.
Suppose we have a vector
std::vector<double> v1 = {9.0,5.0,3.0,2.0,1.0};
Now we sort the vector v1. Let v2 be given by
std::vector<std::string> v2 = {"you?","are","how","there","hello"};
How to transform v2 the same way v1 was transformed by sort?
Based on this answer, you can use an array of indices to "sort" the vector of doubles, and just use the resulting index array to index the vector of strings.
#include <algorithm>
#include <iostream>
#include <string>
#include <numeric>
int main()
{
std::vector<double> v1 = {5.0,9.0,3.0,2.0,1.0};
std::vector<std::string> v2 = {"are", "you?","how","there","hello"};
// Create an array of indices, starting from 0
std::vector<int> index(v1.size());
std::iota(index.begin(), index.end(), 0);
// "Sort" the index array according to the value in the vector of doubles
std::sort(index.begin(), index.end(),
[&](int n1, int n2){ return v1[n1] < v1[n2]; });
// Output results
for (auto i : index )
std::cout << v2[i] << " " << v1[i] << ", index is " << i << "\n";
}
Output:
hello 1, index is 4
there 2, index is 3
how 3, index is 2
are 5, index is 0
you? 9, index is 1
Note:
I changed the original data to illustrate how the index array works.
The abstraction you are missing is the ability to view the vectors as one item. That's the role that a vector of indices is a proxy for in another answer.
I think it is worth mentioning that there are libraries that provide such a concept (often under the name "zip"). For example, with range-v3:
std::vector<double> v1 = {5, 9, 3, 2, 1};
std::vector<std::string> v2 = {"are", "you?", "how", "there", "hello"};
// Sort the vectors
ranges::actions::sort(ranges::views::zip(v1, v2));
// Output results
for (std::size_t i = 0; i < v1.size(); ++i)
std::cout << v2[i] << " " << v1[i] << ", index is " << i << "\n";
A possible solution uses a helper std::vector<int>:
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdexcept>
template<typename T>
void MySort(std::vector<T> t, std::vector<int>& helper)
{
struct StructHelper
{
T t1;
int num;
StructHelper(T t, int i): t1{t}, num{i} {};
bool operator<(const StructHelper& other) const
{ return t1 < other.t1; }
};
std::vector<StructHelper> shVector;
for(int i=0; i<t.size(); ++i)
{
shVector.emplace_back(t[i], i);
}
std::sort(shVector.begin(), shVector.end());
helper = std::vector<int>(t.size());
for(int i=0; i<t.size(); ++i)
{
helper[i] = shVector[i].num;
}
}
template<typename T>
void MySortUsingHelper(std::vector<T>& t1, const std::vector<int>& helper)
{
if(t1.size() != helper.size()) throw std::out_of_range("not same size");
std::vector<T> t2(t1.size());
for(int i=0; i<helper.size(); ++i)
{
t2[i] = t1[helper[i]];
}
t1 = t2;
}
int main() {
std::vector<double> v1 = {9.0,5.0,3.0,2.0,1.0};
std::vector<int> helper;
MySort(v1, helper);
std::vector<std::string> v2 = {"you?","are","how","there","hello"};
MySortUsingHelper(v2, helper);
for(auto elem : v2)
{
std::cout << elem << " ";
}
return 0;
}
You can run the above code online to see the following output:
hello there how are you?