C++ push_back in vectors - c++

I built a recursive function that reads a vector as input and returns a new vector in which every two consecutive elements are switched. For example input: 1 2 3 4 5 6 and output: 2 1 4 3 6 5. The thing I don't get is that when I write the function this way:
vector<int> reverse(vector<int> v) {
if (v.size() < 2)
return v;
else
{
int pos1 = v.at(0); //= 1
int pos2 = v.at(1); //= 2
v.erase(v.begin()); //v = 2 3 4 5 6
v.erase(v.begin()); //v = 3 4 5 6
vector<int> rev = reverse(v);
rev.push_back(pos2); //rev = 2
rev.push_back(pos1); //rev = 2 1
return rev;
}
}
i get 6 5 4 3 2 1. I know the vector::push_back() adds the elements at the end of the vector, so why not 2 1 4 3 6 5? When I wrote it this way it gave me the good answer though (2 1 4 3 6 5) but idk why:
vector<int> reverse(vector<int> v) {
if (v.size() < 2)
return v;
else
{
int pos1 = v.at(v.size() - 2); //= 5
int pos2 = v.at(v.size() - 1); //= 6
v.pop_back(); //v = 1 2 3 4 5
v.pop_back(); //v = 1 2 3 4
vector<int> rev = reverse(v); //call the recursive function
rev.push_back(pos2); //rev = 5
rev.push_back(pos1); //rev = 6 5
return rev;
}
}
The main() function is this:
int main() {
vector<int> w;
int zahl;
cout << "Please give the vector or any letter to end the input: "<< endl;
while (cin >> zahl)
{
w.push_back(zahl);
}
for (int elem : reverse(w))
{
cout << elem << ", ";
}
return 0;
}

It's an easy fix.
The problem with your code is that the recursive step does not correctly translate a correctly constructed sub-result to a slightly larger one.
You would want to do:
// Correctly create the head of the result.
vector<int> rev = {pos2, pos1};
// Now you want to handle the tail, and assuming the output of reverse
// is correct for smaller lists, this would be achieved by appending
// the rest.
const auto sub = reverse(v);
rev.insert(rev.end(), sub.begin(), sub.end());
This ensures that if your list starts with 1 2, it would turn into a list with 2 1, followed by a correctly processed tail.
Your second code worked because you were processing the sequence in reverse, so your recursive step was in fact correct.

The result you obtain is incorrect because in the last call to your function you return an empty vector, and then you push at the back of this vector your last pair of numbers inverted, so 6,5, so you do proceding back in the call stack.
Let's have a look to what you have at every call (first call, second call, ecc.):
v=[1,2,3,4,5,6] ->recursive call
v=[3,4,5,6] ->recursive call
v=[5,6] ->recursive call
v=[] ->return empty vector
rev=[], push back the first two elements of v in reverse order, so rev=[6,5] ->return rev
rev=[6,5], push back the first two elements of v in reverse order, so rev=[6,5,4,3] ->return rev
rev=[6,5,4,3], push back the first two elements of v in reverse order, so rev=[6,5,4,3,2,1]
For this reason, you need first to have a vector with the first two numbers reversed and then attach the processed tail, as suggested above.
Please note that you are constructing copies of the vector every time you call the function. You can create a reversed copy without modifying the copy of the argument given as argument. I would use iterators instead, so that every time your function "sees" a smaller portion of the original vector, without touching it. Here an implementation:
vector<int> reverse(vector<int>::const_iterator begin, vector<int>::const_iterator end) {
if (begin==end-1) //the vector has an odd number of elements, let's append the last element
return vector<int>(1, *(end-1));
else if(begin>=end) //the vector has en even number of elements
return vector<int>();
else
{
vector<int> pairWiseReversed({*(begin+1), *begin});
vector<int> tail=reverse(begin+2, end);
pairWiseReversed.insert(pairWiseReversed.end(), tail.begin(), tail.end());
return pairWiseReversed;
}
}
vector<int> buildReversed(const vector<int>& input){
return reverse(input.begin(), input.end());
}
And here a main:
int main() {
vector<int> v{1,2,3,4,5,6};
cout<<"Input vector"<<endl;
for(auto n:v)
cout<<n<<" ";
cout<<endl;
vector<int> res=buildReversed(v);
cout<<"Output vector"<<endl;
for(auto n:res)
cout<<n<<" ";
cout<<endl;
return 0;
}

Related

remove an element from the back of a vector after shuffling it c++

so the purpose of the code is to shuffle a vector, then print a random number from the vector, and then delete that same number so it won't repeat.
what I did is:
there is an initialized vector called songs, first I used random_device to make a random func.
I initialized an iterator to the back of the vector.
I shuffled the vector
Print
remove the last element that I printed (after shuffling).
The problem is when I do songs.pop_back(); it removes the last element from the original vector and not from the shuffled one, so it makes numbers coming back that way.
and I get an error.
code:
int getSong(int n, vector<int> songs, vector<int>::iterator iter) {
random_device random;
shuffle(songs.begin(), songs.end(), random);
for (int j = 0; j < n; j++) {
cout << songs[j] << " ";
}
iter = songs.end() -1 ;
int song = *iter;
iter--;
return song;
}
int main() {
vector<int> songs = { 1,2,3,4,5,6,7,8,9 };
int n = songs.size();
vector<int>::iterator iter;
for (int i = 0; i < n; n--) {
int l = getSong(n, songs, iter);
cout << "The song number is:" << l << "\n" << endl;
songs.pop_back();
}
return 0;
}
the output is:
Thank you!
I would write something like this instead. It is sort of wasteful but I wanted to keep your original program structure.
First, you need to pass a reference to the vector with std::vector<int>& if you want to modify its contents in the function. If your intent was to keep the original vector then yes, you just pass by value. But as you need to remove the last value in the main function, I figured this was the only way.
Second the iterator is not necessary. You can just remove that.
Last, you dont need to pass the size as the vector itself contains the size.
The use of random_device is somewhat awkward as random_shuffle would be cleaner - but again I tried to change your code minimally.
int getSong( vector<int>& songs ) {
random_device random;
shuffle(songs.begin(), songs.end(), random);
for ( int song : songs ) {
cout << song << " ";
}
cout << endl;
return *songs.rbegin();
}
In regards to the main loop, checking for empty() is cleaner than a loop through the size - it's more immune to edge cases.
int main() {
vector<int> songs = { 1,2,3,4,5,6,7,8,9 };
while( !songs.empty() ) {
int l = getSong(songs);
cout << "The song number is:" << l << "\n" << endl;
songs.pop_back();
}
return 0;
}
https://godbolt.org/z/oWbxvMjE3
Produces:
Program stdout
5 3 6 8 1 9 7 4 2
The song number is:2
7 3 5 8 6 9 1 4
The song number is:4
6 1 9 8 3 5 7
The song number is:7
3 6 1 5 8 9
The song number is:9
6 8 5 3 1
The song number is:1
8 5 3 6
The song number is:6
3 5 8
The song number is:8
3 5
The song number is:5
3
The song number is:3

How do I implement adding and removing elements of an array?

How to implement output of all elements of an array?
A task:
N guys are arranged in a circle. Starting the countdown from the 1st, each k is removed, closing the circle after each removal. Who is left? Display the order of removal from the circle.
#include <iostream>
#include <conio.h>
int counter(int n, int k) {
int function = n >= 1 ? (counter (n - 1, k) + k - 1) % n + 1: 1;
return function;
};
int main(void) {
setlocale(LC_ALL, "Russian");
int peoples;
int quantity;
std::cin >> peoples;
std::cin >> quantity;
std::cout << "Remaining : " << counter(peoples, quantity);
return 0;
}
My code outputs the remaining one item.
How to implement replenishment of an array with elements.
for (i = 0, i < 5, i++) {
cout << ?;
}
output:
[1, 2, 3, 4, 5]
something like this)
and how can you implement the removal of array elements
for example deleting every third array element in a circle
Output:
1 2 3 4 5
1 2 4 5
2 4 5
2 4
4
How do I implement adding and removing elements of an array?
There is no way to add or remove elements from an array. An array has a constant number of elements that doesn't change through the life of the array.
If you need to represent a dynamic sequence of objects that can grow or shrink, you need a more complex data structure. std::vector is an implementation of such data structure. You can add using std::vector::push_back and remove using std::vector::erase.

Array and simple queries using vector

I am solving "https://www.hackerrank.com/challenges/array-and-simple-queries/copy-from/145435292" problem. while solving this problem I got stuck in one logical error.
I have tried to solve this problem in this way.
int main()
{
long long int i,j,k,l,x,n,m,a[3],c;
vector<long long int> g1;
cin>>n>>m;
for (i=0;i<n;i++)
{
cin>>x;
g1.push_back(x);
}
for(i=0;i<m;i++)
{
for(j=0;j<3;j++)
{
cin>>a[j];
}
if(a[0]==1)
{
c=0;
g1.insert(g1.begin(),g1.begin()+(a[1]-1),g1.begin()+a[2]);
c=a[2]-a[1];
c++;
g1.erase(g1.begin() + a[1]+(c-1), g1.begin() + a[2]+c);
}
else
{
g1.insert(g1.end(),g1.begin()+(a[1]-1),g1.begin()+a[2]);
g1.erase(g1.begin() + a[1]-1, g1.begin() + a[2]);
}
cout<<"\n";
for (auto y = g1.begin(); y != g1.end(); ++y)
cout << *y << " ";
}
// c=g1[0]-g1[n-1];
// if(c<0)
// {
// c=c*-1;
// }
// cout<<c<<"\n";
// cout<<"\n";
// for (auto y = g1.begin(); y != g1.end(); ++y)
// cout << *y << " ";
return 0;
}
The input format is-
n,m: where n is the total number and m is the total number of queries.
The next line is n numbers.
The next lines contain m queries.
Type 1 queries are represented as 1 i j : Modify the given array by removing elements from i to j and adding them to the front.
Type 2 queries are represented as 2 i j : Modify the given array by removing elements from i to j and adding them to the back
For Input:
7 2
1 2 3 4 5 6 7
1 3 6
1 3 6
My output is:
3 4 5 6 1 2 7
5 6 3 4 3 4 7
But my output should be:
3 4 5 6 1 2 7
5 6 1 2 3 4 7
Please help me out.
Regarding this line:
g1.insert(g1.begin(),g1.begin()+(a[1]-1),g1.begin()+a[2]);
// ^^ ^^ ^^ It's the same
I can't find a specific quote from the Standard, but in 22.3.11.5 [Containers.sequences.vector.modifiers (insert, emplace_back, emplace, push_back)] it's specified:
Causes reallocation if the new size is greater than the old capacity.
Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence, as well as the past-the-end iterator. If no reallocation happens, then references, pointers, and iterators before the insertion point remain valid but those at or after the insertion point, including the past-the-end iterator, are invalidated.
The cppreference.com page about std::vector::insert has the following clarifications (emphasis mine)
template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last );
Inserts elements at the specified location in the container.
...
The behavior is undefined if first and last are iterators into *this.
...
first, last - the range of elements to insert, can't be iterators into container for which insert is called.
It's also worth noting that inserting at the beginnning and then erasing the elements in the middle of a vector may be a rather inefficient method.
The expected results could be easily achieved using another algorithm, std::rotate:
if (a[0] == 1)
{
std::rotate(
g1.begin(), // First element of the range to be left rotated.
g1.begin() + (a[1] - 1), // Element which will become the first
g1.begin() + a[2] // Last element of the range to be modified.
);
}
else
{
std::rotate(
g1.begin() + (a[1] - 1),
g1.begin() + a[2],
g1.end()
);
}

reverse iteration of map in c++ missing out the first element

I have a code where I am reverse iterating a map in C++. For n pairs in map, sometimes the map prints out n pairs, sometimes n-1 pairs.
for test case
4 2
2 1
3 5
2 3
1 5
it prints 4 hi's, for the next case 3 hi's
4 1
0 2
0 3
3 5
0 6
My code:
include cmath, cstdio, vector, iostream, map, algorithm, using namespace std;
int main() {
int n,f;
cin >> n >> f;
int k[n],l[n],dif[n];
map<int,int> m;
map<int,int>::reverse_iterator it;
for (int i=0;i<n;i++){
scanf("%d %d\n",&k[i],&l[i]);
dif[i] = l[i]-k[i];
m.insert(make_pair(dif[i],l[i]));
}
int a = 0;
int sum = 0;
for(it = m.rbegin(); it != m.rend(); ++it ) {
cout << "hi" << endl;
int article = it->second - it->first;
int people = it->second;
if (a < f and article!=0){
a++;
if (2*article > people){
sum = sum + people;
} else {
sum = sum + (2*article);
}
} else {
if (article > people){
sum = sum + people;
} else {
sum = sum + article;
}
}
}
cout << sum;
return 0;
}
This has nothing to do with reverse iteration, it would be the same with forward iteration. A map has a pair of a key and a value. Each key can only be included in the map once. When you insert the same key again the previous value is overwritten. In your second test case you are setting the key 0 three times:
4 1
0 2 <--
0 3 <--
3 5
0 6 <--
So your map actually only has three values, so the three "Hi" are correct. In your first example you overwrite key 2 only twice, so the four "Hi". Maybe a map is not the correct container you are looking for.

Iterated Difference

This is an spoj problem. It works, but It's too slow.
Here is the question:
Iterated Difference
You are given a list of N non-negative integers a(1), a(2), ... ,
a(N). You replace the given list by a new list: the k-th entry of the
new list is the absolute value of a(k) - a(k+1), wrapping around at
the end of the list (the k-th entry of the new list is the absolute
value of a(N) - a(1)). How many iterations of this replacement are
needed to arrive at a list in which every entry is the same integer?
For example, let N = 4 and start with the list (0 2 5 11). The successive iterations are:
2 3 6 11
1 3 5 9
2 2 4 8
0 2 4 6
2 2 2 6
0 0 4 4
0 4 0 4
4 4 4 4
Thus, 8 iterations are needed in this example.
Input
The input will contain data for a number of test cases. For each case,
there will be two lines of input. The first line will contain the
integer N (2 <= N <= 20), the number of entries in the list. The
second line will contain the list of integers, separated by one blank
space. End of input will be indicated by N = 0.
Output
For each case, there will be one line of output, specifying the case
number and the number of iterations, in the format shown in the sample
output. If the list does not attain the desired form after 1000
iterations, print 'not attained'.
Sample Input
4
0 2 5 11
5
0 2 5 11 3
4
300 8600 9000 4000
16
12 20 3 7 8 10 44 50 12 200 300 7 8 10 44 50
3
1 1 1
4
0 4 0 4
0
Sample Output
Case 1: 8 iterations
Case 2: not attained
Case 3: 3 iterations
Case 4: 50 iterations
Case 5: 0 iterations
Case 6: 1 iterations
I'm not sure of what to do to make it faster. I tried using arrays, but I get all sorts of problems trying to allocate the memory and set one array to another.
How can I make it faster? Here's my code:
#include <iostream>
#include <vector>
#include <cmath>
#include <sstream>
#include <string>
using namespace std;
bool checker(vector<int>& nums2) {
int n = nums2[0];
for (int i = 1; i < nums2.size(); i++)
{
if (n != nums2[i])
return false;
}
return true;
}
vector<int> iterate(vector<int>& nums, int& iter, bool& attained) {
if (iter == 1000) {
attained = false;
return nums;
}
vector<int> nums2;
for (int i = 0; i < nums.size(); i++) {
if (i == nums.size() - 1)
nums2.push_back((int)abs((double)nums[i] - (double)nums[0]));
else
nums2.push_back((int)abs((double)nums[i] - (double)nums[i + 1]));
}
iter++;
return nums2;
}
int main()
{
int N = -1, count = 1;
while (1) {
int num = 0;
vector<int> nums;
string List = "";
stringstream ss;
cin >> N;
if (N == 0)
break;
cin.ignore();
cin.clear();
getline(cin, List);
ss << List;
while (ss >> num) {
nums.push_back(num);
}
int iterations = 0;
bool attained = true;
while (!checker(nums)) {
nums = iterate(nums, iterations, attained);
}
if (!attained)
cout << "case " << count << ": not attained";
else
cout << "case " << count << ": " << iterations << " iterations" << endl;
count++;
}
}
I fixed it. It was a problem with the while loop in the main function. The condition was:
while (!checker(nums)) { ... }
It would stay in the loop and repeatedly call the iterate function because if it is not attainable, then the checker will always be false. So changing the condition to:
while (!checker(nums) && attained) { ... }
would break the loop if it was not attainable.
Basically, it was just getting stuck on doing the same thing over and over; it wasn't actually slow.
Thanks, xan, for your answer.
If you want it to be a little faster you should work on debugging your array variation to avoid the vector allocations. If you want it to be a lot faster you need to do some analysis of the problem to find a better algorithm. For instance, if you see the same list twice you're in a loop and will exceed 1000 iterations. And the result will be the same if you rotate the list, which you can consider when checking for a repeated list.
Your implementation executes 1000 iterations in 25ms on my mainstream lapton. Fixed one, because there's a bug and case 2 will execute forever.
To do faster you can reuse the same vector and modify it in place, your iterator() function signature would look like:
void iterate(vector<int>& nums);
This version takes 7ms on my machine, because it doesn't allocate memory in loop.